如何获取从根到二叉树上给定节点的路径?

Posted

技术标签:

【中文标题】如何获取从根到二叉树上给定节点的路径?【英文标题】:how to get the path from root to a given node on a binary tree? 【发布时间】:2011-09-09 00:26:43 【问题描述】:

我正在尝试找出如何获取从根到二叉树上给定节点的路径。

它不是二叉搜索树。

每个非叶节点只有两个指向其子节点的指针。

按序、前序、后序遍历不起作用。

我尝试过预订,但不知道怎么做。例如,我们有一棵二叉树: 它不是二叉搜索树。我们使用排序节点来更容易找到路径。

     1 
   /   \
  2     3
 / \   / \
4   5 6   7 

我们要找到从 1 到 7 的路径:

通过预购,我们有:

1 -> 2 -> 4 -> 5 -> 3 -> 6 -> 7 

从流程中,我们得到从 1 -> 7 的路径,其中包含所有节点。

显然,不应该。

非常感谢任何帮助。

【问题讨论】:

Find path to node in Tree?的可能重复 【参考方案1】:

前序遍历,也称为深度优先搜索确实有效。

如果您以递归方式实现前序遍历,那么当您到达所需节点时,您可以展开(递归调用的)堆栈并反向构建路径。

如果您以非递归方式实现前序遍历,那么您将直接构建堆栈,因此在这种情况下,一旦您到达所需的节点,您就已经有了自己的路径。

在上述问题的树中,查找从 1 到 7 的路径的算法如下。

从 1 开始,将其压入堆栈,堆栈现在为 [1] 向左移动到 2,将其压入堆栈,堆栈现在是 [1 2] 向左到 4,推它,堆栈现在是 [1 2 4] 没有 4 的孩子,而且不是你想要的,所以弹出它,堆栈现在是 [1 2] 现在您回到了 2,并且您已经向左走,现在向右走,堆栈现在是 [1 2 5] 没有 5 的孩子,所以 pop,堆栈现在是 [1 2] 你已经用尽了 2 的孩子,所以弹出它,堆栈现在是 [1] 现在你回到了 1 并且你已经完成了左边,所以向右走到 3,推它,堆栈现在是 [1 3] 向左走,堆栈现在是 [1 3 6] 6 是叶子,不是你要找的,所以 pop,stack 是 [1 3] 现在你必须从 3 向右推,堆栈现在是 [1 3 7] 但是等等!看!您已到达您要查找的节点!看看你的堆栈!这是您想要的路径。

【讨论】:

我试过这样做,但不知道怎么做。例如,我们有一棵二叉树:它不是二叉搜索树。我们使用排序节点来更容易找到路径。 1 2 3 4 5 6 7 我们想找到从 1 到 7 的路径:通过预购,我们有: 1 -> 2 -> 4 -> 5 -> 3 -> 6 -> 7 从流程中,我们从 1 -> 7 获取所有节点的路径。显然,它不应该。非常感谢任何帮助。 @dtustudy68,好的,我已经更新了我的答案。如果您想查看以特定编程语言(Ruby、Python、javascript,首选)实现的算法,请告诉我。 能否请您看看这个解决方案,以及您的意见?正如您所建议的,它也由 DFS 实现。链接:codereview.stackexchange.com/questions/105136/… 这是一种典型的预排序非递归方法,但我认为它无法生成路径。 def nlr(root): stack = [] node = root while node or stack: if node: print node.val stack.append(node) node=node.left else: node = stack.pop() node = node.right 。此刻,我们转到5,堆栈应该是[1],而不是[1,2],因此,无法生成路径。 我不喜欢这个实现的原因是它需要一个“已访问”属性。通常,您会在遍历其子树的右侧之前弹出根节点,因此在前序遍历中它不会在您的堆栈中。例如,你怎么知道你已经用尽了 2 的孩子【参考方案2】:

给你一棵二叉树(根节点).. 并且给定一个键,它可能在树中,也可能不在树中。 您必须找到从根到节点的完整路径。

例子:

                A
           /           \
       B                C
         \               /
          D           E
        /    \           \
      K      L        M
    /
Z

您已经给定节点 Z(或节点的键)并给定节点 A(root) 所以你的输出应该是

A B D K Z

如果给定 M,输出应该是 A C E M

public class main_class 
public static void main(String args[] ) 

    //first create tree
    Node rootNode = new Node ('A' , new Node('B',null,
                                             new Node('D',
                                                      new Node('K',
                                                               new Node('Z',null,
                                                               null),null),
                                                      new Node('L',null,null))),
                                    new Node('C',
                                             new Node('E',
                                                      null,
                                                      new Node('M',null,null)),null) );

    ArrayList <Node> path = new ArrayList<Node>();
    System.out.println(getPath(rootNode,'Z',path));
    System.out.println(path);
    path = new ArrayList<Node>();
    System.out.println(getPath(rootNode,'M',path));
    System.out.println(path);


static boolean getPath(Node rootNode, char key, ArrayList<Node> path )
    //return true if the node is found
    if( rootNode==null)
        return false;
    if (rootNode.getVal()==key)
        path.add(rootNode);
        return true;
    
    boolean left_check = getPath( rootNode.left,key,path);
    boolean right_check = getPath( rootNode.right,key,path);
    if ( left_check || right_check)
        path.add(rootNode);
        return true;
    
    return false;


static class Node 
    char val;
    Node left;
    Node right;
    public Node( char val, Node left, Node right)
        this.left=left;
        this.right=right;
        this.val=val;
    
    public char getVal()
        return val;
    
   public String toString()
        return " " + val + " ";
    



【讨论】:

【参考方案3】:

考虑以下树:

       10
     /   \
    8      2
  /  \    /
3     5  2

接近

我们从根开始并将其与键进行比较,如果匹配则打印路径(如果树只有一个节点,则路径仅包含根)。 否则将节点推入 Vector(我考虑使用向量来存储路径)。 递归遍历树的左右。

以下代码会有所帮助:

     void PrintPath(node* root, vector <int> v,int key)
     
      if(!root)
      return;
      if(root->data==key)
        
          v.push_back(root->data);
          vector<int>:: iterator it;
          for(it=v.begin();it<v.end();it++)
           
             cout<<*it<<" ";
           
            return;
        
        v.push_back(root->data);
        PrintPath(root->left,v,key);
        PrintPath(root->right,v,key);
        

说明

让要找到的节点是给定树的 5(key)。

每一步向量的内容:

    V = 10 V = 10,8 V = 10,8,3(3不是要找到的关键,所以我们会回溯向右) V = 10,8,5(5 是键,因此打印路径)。

【讨论】:

【参考方案4】:

这里有 3 个 Java 解决方案:https://codereview.stackexchange.com/questions/105136/path-sum-in-binary-tree 第一种是递归方法,第二种是使用 2 个 satcks,最后一种是使用 2 个队列。希望这会有所帮助

【讨论】:

【参考方案5】:
public List<Node<T>> getPath(T data)
        Stack<Node<T>> stack = new Stack<Node<T>>();
        Boolean found =  getPath(root, stack, data);
        List<Node<T>> path = new ArrayList<Node<T>>();

        if(!found)
            return path;
        
        return Arrays.asList(stack.toArray((Node<T>[])new Node[stack.size()]));
    

    public Boolean getPath(Node<T> node, Stack<Node<T>> stack, T data)
        if(node == null)
            return false;
        
        stack.push(node);

        if(node.data.equals(data))
            return true;
        
        Boolean found = getPath(node.left, stack, data) ||
                getPath(node.right, stack, data);

        if(!found )
            stack.pop();
        
        return found;
    

【讨论】:

以上是关于如何获取从根到二叉树上给定节点的路径?的主要内容,如果未能解决你的问题,请参考以下文章

求根到叶子节点数字之和

LeetCode 129. 求根到叶子节点数字之和

给定一棵二叉树,找到所有从根到叶的路径

LeetCode 129. 求根到叶子节点数字之和(Sum Root to Leaf Numbers)

[LeetCode] 129. 求根到叶子节点数字之和

LeetCode 1022.从根到叶的二进制数之和