zoukankan      html  css  js  c++  java
  • 树的非递归遍历:一种很好的算法

    栈模拟非递归算法

    递归算法的本质是利用函数的调用栈进行,实际上我们可以自行使用栈来进行模拟,这样的算法空间复杂度为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  (大神博客啊)

  • 相关阅读:
    ubuntu安装jdk的两种方法
    LeetCode 606. Construct String from Binary Tree (建立一个二叉树的string)
    LeetCode 617. Merge Two Binary Tree (合并两个二叉树)
    LeetCode 476. Number Complement (数的补数)
    LeetCode 575. Distribute Candies (发糖果)
    LeetCode 461. Hamming Distance (汉明距离)
    LeetCode 405. Convert a Number to Hexadecimal (把一个数转化为16进制)
    LeetCode 594. Longest Harmonious Subsequence (最长的协调子序列)
    LeetCode 371. Sum of Two Integers (两数之和)
    LeetCode 342. Power of Four (4的次方)
  • 原文地址:https://www.cnblogs.com/bitpeng/p/4770419.html
Copyright © 2011-2022 走看看