树的非递归遍历:一种很好的算法

栈模拟非递归算法

递归算法的本质是利用函数的调用栈进行,实际上我们可以自行使用栈来进行模拟,这样的算法空间复杂度为O(h),h为二叉树的高度。

前序遍历

首先把根节点入栈,然后在每次循环中执行以下操作:

  • 此时栈顶元素即为当前的根节点,弹出并打印当前的根节点。
  • 把当前根节点的右儿子和左儿子分别入栈(注意是右儿子先入栈左儿子后入栈,这样的话下次出栈的元素才是左儿子,这样才符合前序遍历的顺序要求:根节点->左儿子->右儿子)。

后序遍历

因为后序遍历的顺序是:左子树->右子树->根节点,于是我们在前序遍历的代码中,当访问完当前节点后,先把当前节点的左子树入栈,再把右子树入栈,这样最终得到的顺序为:根节点->右子树->左子树,刚好是后序遍历倒过来的版本,于是把这个结果做一次翻转即为真正的后序遍历。而翻转可以通过使用另外一个栈简单完成,这样的代价是需要两个栈,但就复杂度而言,空间复杂度仍然是O(h)。

中序遍历

中序遍历稍微复杂,使用一个指针p指向下一个待访问的节点,p初始化为根节点。在每次循环中执行以下操作:

  • 如果p非空,则把p入栈,p变为p的左儿子。
  • 如果p为空,说明已经向左走到尽头了,弹出当前栈顶元素,进行访问,并把p更新为其右儿子。

下面是代码实现。

  1 # coding:utf-8
  2 
  3 '''
  4 递归算法的本质是利用函数的调用栈进行,实际上我们可以自行使用栈来进行模拟,这样的算法空间复杂度为O(h),h为二叉树的高度。
  5 
  6 前序遍历
  7 首先把根节点入栈,然后在每次循环中执行以下操作:
  8 此时栈顶元素即为当前的根节点,弹出并打印当前的根节点。
  9 把当前根节点的右儿子和左儿子分别入栈(注意是右儿子先入栈左儿子后入栈,这样的话下次出栈的元素才是左儿子,
 10 这样才符合前序遍历的顺序要求:根节点->左儿子->右儿子)。
 11 下面是代码实现。
 12 
 13 
 14 后序遍历
 15 因为后序遍历的顺序是:左子树->右子树->根节点,于是我们在前序遍历的代码中,当访问完当前节点后,先把当
 16 前节点的左子树入栈,再把右子树入栈,这样最终得到的顺序为:根节点->右子树->左子树,刚好是后序遍历倒过
 17 来的版本,于是把这个结果做一次翻转即为真正的后序遍历。而翻转可以通过使用另外一个栈简单完成,这样的代
 18 价是需要两个栈,但就复杂度而言,空间复杂度仍然是O(h)。
 19 
 20 
 21 中序遍历
 22 中序遍历稍微复杂,使用一个指针p指向下一个待访问的节点,p初始化为根节点。在每次循环中执行以下操作:
 23 如果p非空,则把p入栈,p变为p的左儿子。
 24 如果p为空,说明已经向左走到尽头了,弹出当前栈顶元素,进行访问,并把p更新为其右儿子。
 25 '''
 26 from random import randint
 27 
 28 class Node(object):
 29     def __init__(self, x):
 30         self.x = x
 31         self.left = None
 32         self.right = None
 33         
 34 def PreOrder(root):
 35     if not root:
 36         return None
 37     
 38     st = [root]    # 辅助栈
 39     path = []      # 遍历路径
 40     while st:
 41         node = st.pop()
 42         path.append(node.x)
 43         if node.right:
 44             st.append(node.right)
 45         if node.left:
 46             st.append(node.left)
 47     return path
 48     
 49 def PostOrder(root):
 50     if not root:
 51         return None
 52     
 53     st = [root]
 54     path = []
 55     while st:
 56         node = st.pop()
 57         path.append(node.x)
 58         if node.left:
 59             st.append(node.left)
 60         if node.right:
 61             st.append(node.right)
 62     return path[::-1] # path值为:根节点->右子树->左子树,所以作一次倒序刚好就是返回结果!
 63         
 64 def InOrder(root):
 65     if not root:
 66         return None
 67     tmp = root; st = []
 68     path = []
 69     while tmp or st:
 70         if tmp:
 71             st.append(tmp)
 72             tmp = tmp.left
 73         else:
 74             tmp = st.pop()
 75             path.append(tmp.x)
 76             tmp = tmp.right
 77             
 78     return path
 79     
 80 def Hierarchy(root):
 81     # write code here
 82     from collections import deque
 83     #if root is None:
 84     #    return None
 85     if not root:
 86         return []
 87 
 88     q = deque()
 89     q.append(root)
 90     ret = []
 91     while len(q) > 0:
 92         node = q.popleft()
 93         ret.append(node.x)
 94         if node.left:
 95             q.append(node.left)
 96         if node.right:
 97             q.append(node.right)
 98         #q.append(node.right) if node.right else pass
 99     return ret  
100         
101 root = Node(1)
102 root.left = Node(2);root.right = Node(3)
103 root.left.left = Node(4); root.left.right = Node(5)
104 root.right.left = Node(6); root.right.right = Node(7)
105 root.left.left.right = Node(8); root.right.left.right = Node(9)
106 print PreOrder(root)
107 print PostOrder(root)
108 print InOrder(root)
109 print Hierarchy(root)

 

运行结果,树木结构如下:

        1
      /   
    2       3
  /      /   
4      5  6    7
          
   8        9

 

参考文献:

http://noalgo.info/832.html  (大神博客啊)

原文地址:https://www.cnblogs.com/bitpeng/p/4770419.html