打印树的每个叶子路径而不递归

Posted

技术标签:

【中文标题】打印树的每个叶子路径而不递归【英文标题】:Print every leaf path of a tree without recursive 【发布时间】:2012-06-15 06:03:50 【问题描述】:

如何在不使用递归的情况下打印树的每个叶子路径。

它是一棵树,不是二叉树

struct node 
    int data
    std::vector<node*> children;

打印从根到叶子的所有路径,即下面是树

r:是根节点 d、m、n 是 r 的孩子 x,y,z 是 d 的孩子 m 没有孩子 o, p 是 n 的孩子 - - - - - - -根 ------d m n ---x y z o p

结果应该是:

根-d-x 根-d-y 根-d-z 根-m root-n-o 根-n-p

我尝试使用非递归方式但失败了。

【问题讨论】:

我相信您可以根据自己的情况调整非递归二叉树遍历。具有最小内存开销的最简单实现将在node 中有一个父节点指针。见nonRecursiveInOrderTraversal()。 【参考方案1】:
public static void printAllPathToLeafNonRecursive(Node root) 

    if (root == null) 
        return;
    

    Queue<Object> q = new LinkedList<Object>();
    q.add(root);
    q.add(root.data + "");

    while(!q.isEmpty())

        Node head = (Node) q.poll();
        String headPath = (String) q.poll();

        if(head.isLeaf())
            System.out.println(headPath);
            continue;
        

        if(head.left!=null)
            String leftStr =  headPath + "->" + head.left.data;
            q.add(head.left);
            q.add(leftStr);
        

        if(head.right!=null)
            String rightStr =  headPath + "->" + head.right.data;
            q.add(head.right);
            q.add(rightStr);
        
    



【讨论】:

这不会也打印出路径上的一些节点吗? @Cyber​​neticTwerkGuruOrc 不,它没有。查看它使用队列的方式。它也将字符串推送到队列中,因此它不会被路径节点之外的节点写入。它被适当地轮询和附加:) @smihael:对于超过 2 个孩子的树,可以修改上述解决方案。不要插入 head.left 和 head.right,而是使用:for(int i = 0; i " + head.children[i].data ; q.add(head.children[i]); q.add(si); 有点晚了,但我想指出这真的很慢,因为它为每个节点(不仅仅是叶子)复制一个字符串。如果 N 是 # 个节点,K 是 # 个叶子,通常的算法在 O(KN) 中运行,但在 O(N^2) 中运行,这对任意非二叉树有很大的不同【参考方案2】:

这是一个纯粹基于使用堆栈的预排序迭代遍历的 Python 解决方案。打印路径和路径和。

 class Stack(object): # just for reference
    def __init__(self):
        self.a = []

    def push(self, b):
        self.a.append(b)

    def peek(self):
        return self.a[-1]

    def pop(self):
        return self.a.pop()

    def isEmpty(self):
        return len(self.a) == 0

    def show(self):
        return self.a

 def paths(troot): # you should create your own Tree and supply the root
    current = troot
    s = Stack()
    s.push(current)
    s.push(str(current.key))
    s.push(current.key)

    while not s.isEmpty():
        pathsum = s.pop()
        path = s.pop()
        current = s.pop()

        if not current.left and not current.right:
            print 'path: %s, pathsum: %d' % (path, pathsum)

        if current.right:
            rightstr = path + "->" + str(current.right.key)
            rightpathsum = pathsum * 10 + current.right.key
            s.push(current.right)
            s.push(rightstr)
            s.push(rightpathsum)

        if current.left:
            leftstr = path + "->" + str(current.left.key)
            leftpathsum = pathsum * 10 + current.left.key
            s.push(current.left)
            s.push(leftstr)
            s.push(leftpathsum)

例如,对于以下树:

                          3                                                
                       /   \
                      /     \
                     /       \
                    /         \
                   /           \
                  /             \
                 /               \
                /                 \
              1                       7                        
           /   \                   /   \
          /     \                 /     \
         /       \               /       \
        /         \             /         \
        0           2           5           8            
     /   \       /   \       /   \       /   \
    /     \     /     \     /     \     /     \
   NUL   NUL   NUL   NUL     4     6   NUL     9      

输出将是:

    >>> paths()
    path: 3->1->0, pathsum: 310
    path: 3->1->2, pathsum: 312
    path: 3->7->5->4, pathsum: 3754
    path: 3->7->5->6, pathsum: 3756
    path: 3->7->8->9, pathsum: 3789

【讨论】:

【参考方案3】:

策略很简单。向下,向右,然后向上。在每一个点上,您都知道下一步该去哪里。

保留一个向量,它是您在树中的当前位置。在根上启动它。然后在伪代码中:

while True:
    if not a leaf:
        current_place.push_back(0) // move down one
    else:
        print current path.
        while can't move right:
             if at root:
                 exit()
             current_place.pop_back() //move up one
        current_place[-1] += 1

这些操作将需要函数调用。但它们是带有循环的函数调用,而不是递归,所以它不是递归的。

【讨论】:

基本上,您需要使用显式堆栈操作来模拟递归函数的行为。 @Groo,没错。我考虑过使用队列,但这不会按要求的顺序排列。 这个算法(虽然缺少一些细节)是更好的选择。【参考方案4】:

最后,它只是一个图表。有不同类型的图遍历。只需将 dfs 与堆栈一起使用,并打印您没有前边缘的节点。

【讨论】:

【参考方案5】:
public static void RoottoPathPrint(BinaryTreeNode root) 
    Stack<Object> stack = new Stack<Object>();
    if (root == null)
        return;
    stack.push(root.getData() + "");
    stack.push(root);
    while (!stack.isEmpty()) 
        BinaryTreeNode temp = (BinaryTreeNode) stack.pop();
        String path = (String) stack.pop();

        if (temp.getRight() != null) 
            stack.push(path + temp.getRight().getData());
            stack.push(temp.getRight());
        
        if (temp.getLeft() != null) 
            stack.push(path + temp.getLeft().getData());
            stack.push(temp.getLeft());
        
        if (temp.getLeft() == null && temp.getRight() == null) 
            System.out.println(path);
        
    

我们的想法是在我们遍历树时跟踪单个堆栈中的路径和节点。对象堆栈负责这一点。 希望对您有所帮助!

【讨论】:

【参考方案6】:
private void rootToLeaf(BSTNode root)
    Stack<Map<BSTNode,ArrayList<Integer>>> tmpStack = new Stack<Map<BSTNode,ArrayList<Integer>>>();
    Map<BSTNode,ArrayList<Integer>> tmpMap = new HashMap<BSTNode,ArrayList<Integer>>();
    //List<Integer> tmp_arraylist = new ArrayList<Integer>();
    ArrayList<Integer> tmpList = new ArrayList<Integer>();
    tmpList.add(root.data);
    tmpMap.put(root, tmpList);
    tmpStack.push(tmpMap);
    while(!tmpStack.isEmpty())
        Map<BSTNode,ArrayList<Integer>> temp_map = tmpStack.pop();
        for(BSTNode node : temp_map.keySet())
            if(node.getLeft()==null && node.getRight()==null)
                for(int i: temp_map.get(node))
                    System.out.print(i+" ");
                
                System.out.println();
            
            if(node.getRight()!=null)
                ArrayList<Integer> tmp_List = new ArrayList<Integer>();
                for(int i: temp_map.get(node))
                    tmp_List.add(i);
                
                tmp_List.add(node.getRight().getData());
                Map<BSTNode,ArrayList<Integer>> tmphashMap = new HashMap<BSTNode,ArrayList<Integer>>();
                tmphashMap.put(node.getRight(), tmp_List);
                tmpStack.push(tmphashMap);
            
            if(node.getLeft()!=null)
                ArrayList<Integer> tmp_List = new ArrayList<Integer>();
                for(int i: temp_map.get(node))
                    tmp_List.add(i);
                
                tmp_List.add(node.getLeft().getData());
                Map<BSTNode,ArrayList<Integer>> tmphashMap = new HashMap<BSTNode,ArrayList<Integer>>();
                tmphashMap.put(node.getLeft(), tmp_List);
                tmpStack.push(tmphashMap);
            
        

    

【讨论】:

【参考方案7】:

对于 n 叉树 - 基于 DFS 和 BFS 的路径,求和

                            100     
                      /    /   \     \
                    1     2     3     4
   /   /   /   /   /                /   \   
 10   11  12  13  14              40    41 
                                 / \
                              400  401


public void traverseDFS(Node root) 
    Stack<Node> s = new Stack<Node>();
    Stack<String> sPath = new Stack<>();
    Stack<Integer> sSum = new Stack<>();
    s.push(root);   sPath.push(root.Id + "");   sSum.push(root.Id);

    while (!s.isEmpty()) 
      // Pop out
      Node head = s.pop();    String headPath = sPath.pop();    Integer headSum = sSum.pop();
      if(head.children == null || head.children.isEmpty()) //Leaf
        System.out.println(headPath + "(" + headSum+")");
        continue;
      
      for(Node child : head.children) 
        String path = headPath + "->" + child.Id;
        Integer sum = headSum + child.Id;
        // Push on stack
        s.push(child);    sPath.push(path);   sSum.push(sum);
      
    
  

public static void traverseBFS(Node root) 

    Queue<Node> q = new LinkedList<>();
    Queue<String> qPath = new LinkedList<>();
    Queue<Integer> qSum = new LinkedList<>();
    q.add(root);  qPath.add(root.Id + "");  qSum.add(root.Id);

    while(!q.isEmpty())
      // Poll the q
      Node head = q.poll();   String headPath = qPath.poll();   Integer headSum = qSum.poll();
      if(head.children == null || head.children.isEmpty()) //Leaf
        System.out.println(headPath + "(" + headSum+")");
        continue;
      
      for(Node child : head.children) 
        String path = headPath + "->" + child.Id;
        Integer sum = headSum + child.Id;
        // Add to the q
        q.add(child);   qPath.add(path);    qSum.add(sum);
      
    
  

class Node 
  int Id;
  String Data;
  Node Parent;
  ArrayList<Node> children;

  public Node(int id, String data) 
    Id = id;
    Data = data;
  

输出

-----------Depth FS-------------
100->4->41(145)
100->4->40->401(545)
100->4->40->400(544)
100->3(103)
100->2(102)
100->1->14(115)
100->1->13(114)
100->1->12(113)
100->1->11(112)
100->1->10(111)
-----------BFS-------------
100->2(102)
100->3(103)
100->1->10(111)
100->1->11(112)
100->1->12(113)
100->1->13(114)
100->1->14(115)
100->4->41(145)
100->4->40->400(544)
100->4->40->401(545)

【讨论】:

【参考方案8】:
public void allPathsToLeafNodesWithPreOrderDFS() 
    Stack<Node> stack = new Stack<> ();
    stack.push (root);
    List<Deque<Integer>> paths = new ArrayList<> ();

    while (!stack.isEmpty ()) 
        Node pop = stack.pop ();
        System.out.print (" " + pop.data);
        if (pop.isLeaf ()) 
            Deque<Integer> path = new ArrayDeque<> ();
            Node current = pop;
            while (current != null) 
                path.add (current.data);
                current = current.parent;
            
            paths.add (path);
        
        if (pop.right != null) 
            pop.right.parent = pop;
            stack.push (pop.right);
        
        if (pop.left != null) 
            pop.left.parent = pop;
            stack.push (pop.left);
        
    
    System.out.println ("paths = " + paths);


public void allPathsToLeafNodesWithInOrderDFS() 
    Stack<Node> stack = new Stack<> ();
    List<Deque<Integer>> paths = new ArrayList<> ();
    Node current = root;

    while (!stack.isEmpty () || current != null) 
        if (current != null) 
            stack.push (current);
            if (current.left != null) current.left.parent = current;
            current = current.left;
         else 
            Node pop = stack.pop ();
            System.out.println (" " + pop.data);
            if (pop.isLeaf ()) 
                Deque<Integer> path = new ArrayDeque<> ();
                Node now = pop;
                while (now != null) 
                    path.add (now.data);
                    now = now.parent;
                
                paths.add (path);
            
            current = pop.right;
            if (pop.right != null) pop.right.parent = pop;
        

    
    System.out.println ("paths = " + paths);


public void allPathsToLeafNodesWithBFS ()
    List<Deque<Integer>> paths = new ArrayList<> ();
    Queue<Node> queue = new LinkedList<> ();
    queue.add (root);
    while (!queue.isEmpty ())
        Node poll = queue.poll ();
        System.out.println ("poll = " + poll);
        if (poll.isLeaf ())
            Deque<Integer> path = new ArrayDeque<> ();
            Node current = poll;
            while (current != null)
                path.add (current.data);
                current = current.parent;
            
            paths.add (path);
        
        if(poll.left != null) 
            poll.left.parent = poll;
            queue.add (poll.left);
        
        if(poll.right != null) 
            poll.right.parent = poll;
            queue.add (poll.right);
        
    
    System.out.println ("paths = " + paths);

【讨论】:

以上是关于打印树的每个叶子路径而不递归的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode 112. 路径总和 递归 树的遍历

二叉树路径

求二叉树中从根结点到叶子节点的路径

UVA - 548 Tree(二叉树的递归遍历)

二叉树的和为某一条路径

Java二叉树的递归,非递归遍历,高度,节点数,叶子节点数