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


    栈模拟非递归算法

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

  • 相关阅读:
    Linux之lsof命令
    lnmp一键安装的卸载
    MySQL密码忘了怎么办?MySQL重置root密码方法
    LNMP状态管理命令
    perl5 第一章 概述
    行政级别详解
    http://dl.fedoraproject.org/pub/epel/7/x86_64/,开源软件清单list
    Linux Centos 系统上安装BT客户端 Transmission
    在VPS上安裝BT軟體Transmission
    What is a good EPUB reader on Linux
  • 原文地址:https://www.cnblogs.com/bitpeng/p/4770419.html
Copyright © 2020-2023  润新知