Java 查找二叉树从根到叶的所有路径

Java 查找二叉树从根到叶的所有路径,java,algorithm,tree,binary-tree,Java,Algorithm,Tree,Binary Tree,我编写了一个递归算法来查找二叉树的所有路径。基本上,您将找到最左边的路径,将节点放在堆栈中,然后逐渐找到正确的分支。据我测试,该算法运行良好,但在递归过程中添加了一个空条目 例如,下面提供了一个示例树 4 / \ 5 6 / / \ 4 1 6 / \ 5 12 \

我编写了一个递归算法来查找二叉树的所有路径。基本上,您将找到最左边的路径,将节点放在堆栈中,然后逐渐找到正确的分支。据我测试,该算法运行良好,但在递归过程中添加了一个空条目

例如,下面提供了一个示例树

               4
              /  \
             5    6
            /    / \
           4    1   6
          / \
         5  12
             \
             13
public static List<List<Node>> findAllPaths(List<List<Node>> paths, Node node, List<Node> path) {

        if (node == null) {
            return paths;
        }

        path.add(node);

        if (node.left == null && node.right == null) {

            paths.add(path);
            return paths;
        }

        //
        else {
            findAllPaths(paths, node.left, new ArrayList<>(path));
            findAllPaths(paths, node.right, new ArrayList<>(path));
        }

        return paths;
    }
代码应提供以下路径:

[4, 5, 4, 5]
[4, 5, 4, 12, 13]
[4, 6, 1]
[4, 6, 6]
节点定义在这里

private static class Node {

        public int key;

        public Node left;
        public Node right;

        public Node(int key) {
            this.key = key;
        }
    }
查找下面提供的所有路径的算法

/*
 * find all the paths of a binary search tree
 * */
private static void findPaths(Node node, List<List<Integer>> lists, Stack<Node> stack) {

    if (node == null) {
        return;
    }

    List<Integer> list = null;

    stack.push(node);

    while (node.left != null) {
        node = node.left;
        stack.push(node);
    }

    /////////
    if (stack.peek().right != null) {
        findPaths(stack.peek().right, lists, stack);
    }
    /////////


    if (stack.size() > 0) {
        list = new ArrayList<>();
    }

    for (Node n : stack) {
        list.add(n.key);
    }

    lists.add(list);

    Node right = null;

    /*
     * i.    pop till the stack has elements
     * ii.   delete the old left paths that are already included
     * iii.  delete the old right path that are already included
     *
     * */
    while (stack.size() >0 && (stack.peek().right == null || stack.peek().right.equals(right))) {
        right = stack.pop();
    }


    /*
     * for the right paths
     * */
    if (stack.size() == 0) {
        return;
    }

    right = stack.peek().right;

    findPaths(right, lists, stack);
}
代码点击
return
,然后不结束该方法的所有工作, 它仍然在里面演奏,并在这里演奏

if (stack.size() > 0) {
        list = new ArrayList<>();
    }

    for (Node n : stack) {
        list.add(n.key);
    }

    lists.add(list);
if(stack.size()>0){
列表=新的ArrayList();
}
用于(节点n:堆栈){
列表。添加(n.key);
}
列表。添加(列表);
显然,它在之后做不了什么,最后离开了这个方法


如果有人能帮助我改进代码,我将不胜感激。我假设它来自于使用2
return
语句。在
Java
中是否允许使用它?如果允许,这种情况下的演练是什么?

如注释中所述,您不需要单独的堆栈。您可以使用子节点的递归调用和返回路径,并将父节点添加到每个可用路径

private static List<List<Integer>> findPaths(Node node){

    if (node == null) 
        return new ArrayList<List<Integer>>();

    List<List<Integer>> paths = new ArrayList<List<Integer>>();

    List<List<Integer>> left_subtree = findPaths(node.left);
    List<List<Integer>> right_subtree = findPaths(node.right);


    for(int i=0;i<left_subtree.size();++i){
        List<Integer> new_path = new ArrayList<Integer>();
        new_path.add(node.key);
        new_path.addAll(left_subtree.get(i));
        paths.add(new_path);
    }

    for(int i=0;i<right_subtree.size();++i){
        List<Integer> new_path = new ArrayList<Integer>();
        new_path.add(node.key);
        new_path.addAll(right_subtree.get(i));
        paths.add(new_path);
    }


    if(paths.size() == 0){
        paths.add(new ArrayList<Integer>());
        paths.get(0).add(node.key);
    }

    return paths;
}
私有静态列表findpath(节点){
if(node==null)
返回新的ArrayList();
列表路径=新的ArrayList();
List left_subtree=findpath(node.left);
List right_subtree=findpath(node.right);

对于注释中提到的(int i=0;i),您不需要单独的堆栈。您可以使用子节点的递归调用和返回路径,并将父节点添加到每个可用路径

private static List<List<Integer>> findPaths(Node node){

    if (node == null) 
        return new ArrayList<List<Integer>>();

    List<List<Integer>> paths = new ArrayList<List<Integer>>();

    List<List<Integer>> left_subtree = findPaths(node.left);
    List<List<Integer>> right_subtree = findPaths(node.right);


    for(int i=0;i<left_subtree.size();++i){
        List<Integer> new_path = new ArrayList<Integer>();
        new_path.add(node.key);
        new_path.addAll(left_subtree.get(i));
        paths.add(new_path);
    }

    for(int i=0;i<right_subtree.size();++i){
        List<Integer> new_path = new ArrayList<Integer>();
        new_path.add(node.key);
        new_path.addAll(right_subtree.get(i));
        paths.add(new_path);
    }


    if(paths.size() == 0){
        paths.add(new ArrayList<Integer>());
        paths.get(0).add(node.key);
    }

    return paths;
}
私有静态列表findpath(节点){
if(node==null)
返回新的ArrayList();
列表路径=新的ArrayList();
List left_subtree=findpath(node.left);
List right_subtree=findpath(node.right);

对于(int i=0;i),C++在这类代码方面并没有比java有什么不同。下面是C++指定的上述问题的实现。

vector< vector< int > > ans;

void solution(TreeNode *root, vector<int> &current){
    if(root == NULL)
        return;
    current.push_back(root->val);
    if(root->left == NULL and root->right == NULL)
        ans.push_back(current);

    if(root->left)
        solution(root->left, current);

    if(root->right)
        solution(root->right, current);

    current.pop_back();
} 


vector<vector<int> > Solution::pathSum(TreeNode* A) {
    ans.clear();
    vector<int> current;
    solution(A, current);
    return ans;
}
vector>ans;
无效解决方案(TreeNode*根、向量和当前){
if(root==NULL)
返回;
当前。推回(根->值);
如果(根->左==NULL和根->右==NULL)
ans.推回(当前);
如果(根->左)
解决方案(根->左,当前);
如果(根->右)
解决方案(根->右,当前);
当前。弹出返回();
} 
向量解决方案::路径和(树节点*A){
ans.clear();
矢量电流;
溶液(A,电流);
返回ans;
}

以上方法使用递归并保持路径。每当我们碰到解,即叶,我们考虑一个解决方案,并弹出该元素来搜索其他的树下移动的解决方案。

< P>与C++相比,C++并不像此代码中的java那么不同。下面是上面指定问题的C++实现。
vector< vector< int > > ans;

void solution(TreeNode *root, vector<int> &current){
    if(root == NULL)
        return;
    current.push_back(root->val);
    if(root->left == NULL and root->right == NULL)
        ans.push_back(current);

    if(root->left)
        solution(root->left, current);

    if(root->right)
        solution(root->right, current);

    current.pop_back();
} 


vector<vector<int> > Solution::pathSum(TreeNode* A) {
    ans.clear();
    vector<int> current;
    solution(A, current);
    return ans;
}
vector>ans;
无效解决方案(TreeNode*根、向量和当前){
if(root==NULL)
返回;
当前。推回(根->值);
如果(根->左==NULL和根->右==NULL)
ans.推回(当前);
如果(根->左)
解决方案(根->左,当前);
如果(根->右)
解决方案(根->右,当前);
当前。弹出返回();
} 
向量解决方案::路径和(树节点*A){
ans.clear();
矢量电流;
溶液(A,电流);
返回ans;
}

< P >上述方法使用递归并保持路径。每当我们碰到解,即叶,我们考虑一个解决方案并弹出该元素来搜索树下移动的其他解决方案。< /P> < P>我有一个递归解决方案,它可以提供从根到叶的二叉树的所有路径。

               4
              /  \
             5    6
            /    / \
           4    1   6
          / \
         5  12
             \
             13
public static List<List<Node>> findAllPaths(List<List<Node>> paths, Node node, List<Node> path) {

        if (node == null) {
            return paths;
        }

        path.add(node);

        if (node.left == null && node.right == null) {

            paths.add(path);
            return paths;
        }

        //
        else {
            findAllPaths(paths, node.left, new ArrayList<>(path));
            findAllPaths(paths, node.right, new ArrayList<>(path));
        }

        return paths;
    }
公共静态列表findAllPath(列表路径、节点节点、列表路径){
if(node==null){
返回路径;
}
添加(节点);
if(node.left==null&&node.right==null){
路径。添加(路径);
返回路径;
}
//
否则{
FindAllPath(路径,node.left,新的ArrayList(路径));
FindAllPath(路径,node.right,新ArrayList(路径));
}
返回路径;
}

我有一个递归解决方案,可以提供从二叉树的根到叶的所有路径。解决方案如下所示

               4
              /  \
             5    6
            /    / \
           4    1   6
          / \
         5  12
             \
             13
public static List<List<Node>> findAllPaths(List<List<Node>> paths, Node node, List<Node> path) {

        if (node == null) {
            return paths;
        }

        path.add(node);

        if (node.left == null && node.right == null) {

            paths.add(path);
            return paths;
        }

        //
        else {
            findAllPaths(paths, node.left, new ArrayList<>(path));
            findAllPaths(paths, node.right, new ArrayList<>(path));
        }

        return paths;
    }
公共静态列表findAllPath(列表路径、节点节点、列表路径){
if(node==null){
返回路径;
}
添加(节点);
if(node.left==null&&node.right==null){
路径。添加(路径);
返回路径;
}
//
否则{
FindAllPath(路径,node.left,新的ArrayList(路径));
FindAllPath(路径,node.right,新ArrayList(路径));
}
返回路径;
}

您不需要使用单独的堆栈。您可以简单地递归并在递归调用完成后继续向列表中添加节点。请您进一步解释一下好吗?我跟踪堆栈中的所有路径,我个人认为这是必需的。好的,您能让我知道您所说的所有路径是什么意思吗?您能给出一个例子吗?提供了一个示例,所以,从根节点到叶节点的所有路径。如果我向您提供我想到的代码,可以吗?您不需要使用单独的堆栈。您可以简单地递归,并在递归调用完成后继续将节点添加到列表中。您能解释更多吗?我跟踪堆栈中的所有路径,以我的拙见,这是必需的。好的,您能让我知道吗你说的所有路径是什么意思?你能举个例子吗?提供了从根节点到叶节点的所有路径。如果我向你提供我想到的代码,可以吗?好的,这不是最初的问题,但很有帮助。因此,我接受了你的答案。我提供了一个递归解决方案,可能更容易实现。我在下面提供了解决方案@Ar