【问题标题】:In order Traversal Breaking Out Of Recursive Loop为了遍历递归循环
【发布时间】:2015-06-17 12:29:01
【问题描述】:

我在 SOF 上搜索了一段时间并阅读了类似的帖子。我没有找到任何令人满意的答案。我遇到的问题是我想遍历一棵树,直到“根节点”和目标节点相同。如果 'root' == 目标,我想返回 true 否则返回 false。

这就是我所拥有的

private boolean modifiedInorderTraversal(Node newRoot, Node target){     
        if(newRoot.leftPointer != null){
            modifiedInorderTraversal(newRoot.leftPointer, target);
        }

        if(newRoot == target){
            System.out.println("newRoot == target");
            return true;
            //return false;
        } 

        if(newRoot.rightPointer != null){
            modifiedInorderTraversal(newRoot.rightPointer, target);
        }

        System.out.println("before false return");
    //return true;   
        return false; 
    }

你会注意到被注释掉的是返回 false 和返回 true。如果我交换返回值,我就能让程序在所有测试用例中正常运行。但是,我个人不喜欢这种解决方案。我添加了打印语句来跟踪什么问题,并且我使用 Netbeans 作为我的调试器。当我运行代码时,它确实显示它正在进入

if(newRoot == target){
    System.out.println("newRoot == target");
    return true;
    //return false;
} 

我知道这一点,因为我的行被打印了。现在,尽管返回语句为 true,但我的递归似乎仍在继续,导致 false 的错误返回。我尝试使用全局变量来停止递归无济于事。 该尝试的示例

private breakRecursion = false;

private boolean example(Node newRoot, Node target){
    if(!breakRecursion){
        if(blah blah){recurse}
        if(newRoot == target){breakRecursion = true, return true}
        if(blah blah){recurse}
        return false;
    }
}

有什么想法吗?我读过可以使用异常来中断循环,但我认为这也很混乱。
***********************更新********************* 我发现这符合我的预期

private boolean found = false;
    private boolean modifiedInorderTraversal(Node newRoot, Node target){     
        if(newRoot.leftPointer != null){
            modifiedInorderTraversal(newRoot.leftPointer, target);
        }

        if(newRoot == target){
            found = true;
        } 

        if(newRoot.rightPointer != null){
            modifiedInorderTraversal(newRoot.rightPointer, target);
        }

        return found; 
    }

我对这个解决方案的唯一问题是运行时间是 O(n)。最坏的情况应该是 O(n),但是这个解决方案不会提前中断,并且无论目标在哪里找到都会遍历所有节点。

【问题讨论】:

  • 但是在找到目标后继续遍历树。将 && !found 添​​加到您检查的 if 语句是左子和右子空。如果要保持一致,则在函数中声明找到,从递归调用中分配返回值,并在最后返回找到。

标签: java recursion binary-search-tree


【解决方案1】:

您的问题是,当您从递归堆栈中的一个级别返回指示您找到目标时,您忘记在更高级别使用此信息来停止搜索。试试这个(当然删除最终产品中的打印语句):

private static boolean modifiedInorderTraversal(Node newRoot, Node target){     
    boolean foundIt = false;

    if(newRoot.leftPointer != null){
        foundIt = modifiedInorderTraversal(newRoot.leftPointer, target);
        if(foundIt){
            System.out.println("Target found in left subtree");
            return true;
        }
    }

    System.out.println("searching: "+newRoot.value);
    if(newRoot == target){
        System.out.println("Target found at current node!");
        return true; //the target is this node!
    } 

    if(newRoot.rightPointer != null){
        foundIt = modifiedInorderTraversal(newRoot.rightPointer, target);
        if(foundIt){
            System.out.println("Target found in right subtree!");
            return true;
        }
    }

    System.out.println("Not found below root "+newRoot.value);
    return false; //the target is in neither subtree, and is not the root :-(
}

//My tree:
//      a
//    /   \
//    b    c
//   /\    /\
//  d e   f  g
public static void main(String[] arg){
    Node d = new Node(null,null,"d");
    Node e = new Node(null,null,"e");
    Node f = new Node(null,null,"f");
    Node g = new Node(null,null,"g");

    Node b = new Node(d,e,"b");
    Node c = new Node(f,g,"c");

    Node a = new Node(b,c,"a");

    System.out.println("Searching for f");
    if(modifiedInorderTraversal(a, f)){
        System.out.println("Success!");
    }

    System.out.println("---------------------------------");

    System.out.println("Searching for q");
    Node q = new Node(null,null,"q");
    if(modifiedInorderTraversal(a, q)){
        System.out.println("Shouldn't make it here...");
    } else{
        System.out.println("Didn't find q, as we shouldn't");
    }
}

private static class Node {
    public Node(Node left, Node right, String value){
        leftPointer = left;
        rightPointer = right;
        this.value = value;
    }
    Node leftPointer;
    Node rightPointer;
    String value;
}

如果在左子树、当前节点或右子树中找到值,则将停止搜索。如果在其中任何一个中都找不到目标,那么我们就放弃。运行上面给出:

Searching for f
searching: d
Not found below root d
searching: b
searching: e
Not found below root e
Not found below root b
searching: a
searching: f
Target found at current node!
Target found in left subtree
Target found in right subtree!
Success!
---------------------------------
Searching for q
searching: d
Not found below root d
searching: b
searching: e
Not found below root e
Not found below root b
searching: a
searching: f
Not found below root f
searching: c
searching: g
Not found below root g
Not found below root c
Not found below root a
Didn't find q, as we shouldn't

【讨论】:

  • 谢谢!我比我上面发布的更喜欢这个解决方案。
  • @msanti 我添加了一个使用示例,其中包含一些有用的打印语句,以帮助您可视化正在发生的事情。
  • 感谢您的插图。它极大地帮助了我的理解。