【问题标题】:Need help in returning from a recursive method从递归方法返回时需要帮助
【发布时间】:2010-02-11 19:20:28
【问题描述】:

我正在尝试跟踪二叉树(不是二叉搜索树)中节点的路径。给定一个节点,我试图从根打印路径的值。

我编写了以下程序。

package dsa.tree;

import java.util.Stack;

public class TracePath {
    private Node n1;

    public static void main(String args[]){
        TracePath nodeFinder = new TracePath();
        nodeFinder.find();
    }

    public void find(){
        Tree t = getSampleTree();
        tracePath(t,n1);
    }

    private Tree getSampleTree() {
        Tree bsTree = new BinarySearchTree();
        int randomData[] = {43,887,11,3,8,33,6,0,46,32,78,76,334,45};
        for(int i=0;i<randomData.length;i++){
            bsTree.add(randomData[i]);
        }
        n1 = bsTree.search(76);
        return bsTree;
    }

    public void tracePath(Tree t, Node node){
        trace(t,node);
    }

    Stack<Node> mainStack = new Stack<Node>();

    public void trace(Tree t, Node node){
        trace(t.getRoot(),node);
    }

    private void trace(Node parent, Node node){
        mainStack.push(parent);
        if(node.data == parent.data){
            for(Node iNode:mainStack){
                System.out.println(iNode.data);
            }
            return;
        }
        if(parent.left != null){
            trace(parent.left, node);
        }
        if(parent.right!=null){
            trace(parent.right, node);
        }
        mainStack.pop();
    }
}

我得到了正确的输出。但它有点乱。如果您看到方法 trace(Node, Node),我正在打印我不应该做的值。我希望跟踪方法正确完成。至少,我应该在遇到 if 条件的阶段终止递归结构。

请指教。

【问题讨论】:

    标签: java algorithm data-structures binary-tree traversal


    【解决方案1】:

    好的,一旦你找到你的节点,你需要终止递归。很简单。更改您的跟踪方法以返回一个布尔值,告诉我们是否找到了节点。这样,我们在找到节点后立即返回树。

    private boolean trace(Node parent, Node node){
        mainStack.push(parent);
        if(node.data == parent.data){
            for(Node iNode:mainStack){
                System.out.println(iNode.data);
            }
            return true;
        }
        if(parent.left != null){
            if (trace(parent.left, node)) return true;
        }
        if(parent.right!=null){
            if (trace(parent.right, node)) return true;
        }
        mainStack.pop();
        return false;
    }
    

    【讨论】:

    • 优秀!!!非常感谢..现在我已经体验了如何终止/退出递归方法..再次感谢!
    • 既然您给出了“解决方案”而不是作业提示,我将编辑我的答案以说明我的意思。
    • 您还可以简化嵌套的 if 语句,例如:if (parent.left != null) { return trace(parent.left, node); }
    【解决方案2】:

    我认为这是家庭作业,所以我会给出一些指示而不是一些代码。

    • 您的 trace 方法执行递归下降,因此不需要堆栈 - 您可以在从找到的节点返回时构建路径结构
    • 如果您的方法使用布尔值或列表返回值,您可以在返回时打印路径,或者在搜索方法返回后使用要打印的节点构建列表

    编辑: 如果需要到 root 的路径节点,一个简单的布尔返回就足够了:

    private boolean trace(Node parent, Node node) {
        boolean found = (node.data == parent.data)
    
        if (!found && parent.left != null) {
            found = trace(parent.left, node);
        }
        if (!found && parent.right != null){
            found = trace(parent.right, node);
        }
    
        if (found) {
            System.out.println(parent.data);
        }
    
        return found;
    }
    

    如果你需要从根到节点的路径,你可以传递一个List来按顺序接收节点:

    private boolean trace(Node parent, Node node, List path) {
        boolean found = (node.data == parent.data)
    
        if (!found && parent.left != null) {
            found = trace(parent.left, node);
        }
        if (!found && parent.right != null){
            found = trace(parent.right, node);
        }
    
        if (found) {
            path.add(0, parent);
        }
    
        return found;
    }
    

    或者,您可以在返回途中构建路径并作为列表返回。

    private List trace(Node parent, Node node) {
        List path = null;
    
        if (null != node) {
            if (node.data == parent.data) {
    
                path = new ArrayList();
            } else {
                path = trace(parent.left, node);
    
                if (null == path) {
                    path = trace(parent.right, node);
                }
            }
            if (null != path) {
                path.add(0, parent);
            }
        }
        return path;
    }
    

    【讨论】:

    • 感谢提示.. 我的疑问是如何终止这个程序?
    • 你错了,他需要堆栈。如果他摆脱它并打印然后,它将打印叶子,然后是叶子的父母,然后是父母,回到根。他需要打印的反面,所以需要 Stack 来存储路径。
    • @Schmelter,我给出了 2 个可能的返回值,一个布尔值,当需要节点到根时,或者在找到节点时构建的列表。不需要接收算法访问的所有节点的堆栈。
    【解决方案3】:

    这样的?

    public Stack<Node> findPath(Node src, Node dest, Stack<Node> alreadyCollected) {
        if (src == dest) 
            return alreadyCollected;
        if (src.left == null && src.right == null)
            return null;
        if (src.left != null) {
            Stack<Node> toTheLeft = new Stack<Node>(alreadyCollected);
            toTheLeft.push(src.left);
            Stack<Node> result = findPath(src.left, dest, toTheLeft);
            if (result != null)
                return result;
        }
        List<Node> toTheRight = new Stack<Node>(alreadyCollected);
        return findPath(src.right, dest, toTheRight);
    }
    

    【讨论】:

    • 感谢您的回复。我觉得你在递归循环中创建了太多新的 Stack()。对我来说看起来很昂贵。
    【解决方案4】:

    这是一个不使用堆栈的递归函数。递归在技术上相当于堆栈,在进行递归时一定不需要堆栈。

    PS:我正在写一个伪代码。自己重写它以编译它:)

    bool trace(Node curr, Node n, Path path){
        if(curr == null)
            return;
        if(n == curr){
            path.insertAtEnd(curr);
            return true;
        }
    
        if(trace(curr.left, n, path)){
            path.insertAtEnd(curr);
            return true;
        }
        if(trace(curr.right, n, path)){
            path.insertAtEnd(curr);
            return true;
        }
        return false
    }
    

    【讨论】:

    • 变量路径只是一个数组,没有用作堆栈(LIFO)的地方。
    • 您的代码运行顺利!!!非常感谢 Niraj.. 是的,stack 做了一个额外的 pop 操作,当可以通过这种方式完成时,它就不需要了。
    • 仅供参考,转换后的代码看起来像 private boolean trace(Node curr, Node n, List path){ if(curr == null) return false; if(n == curr){ path.add(curr);返回真; } if(trace(curr.left, n, path)){ path.add(curr);返回真; } if(trace(curr.right, n, path)){ path.add(curr);返回真; } 返回假; }
    • 您可能已经注意到一件事:您可以比较参考文献而不是数据。一个 BST 可以多次包含相同的数据,然后比较数据会导致错误。
    【解决方案5】:

    从跟踪返回一个布尔值,并根据递归调用返回的值决定是否继续搜索。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-04-29
      • 1970-01-01
      • 2011-05-05
      • 2015-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-01
      相关资源
      最近更新 更多