二叉树遍历算法

泪湿孤枕 提交于 2020-02-07 15:51:20

二叉树是树(Tree)这一数据结构中非常重要的子类,其中每一个节点最多存在两个子节点,在代码中表示就是,除了本身的 Data 值,还会带有 Left 和 Right 子节点。如下图所示,用形如图中的结构构成了整棵树。

 

任何一种数据结构,都会存在遍历的顺序问题,比如链表,堆栈等等;二叉树这种数据结构也有遍历的顺序,由于其非线性的结构特征,遍历时的顺序有这三种,前序(pre-order),中序(in-order),后序(post-order)。下面依次介绍一下:

1 前序(pre-order)遍历

基本的原则是“根 -> 左 -> 右”,重复直到整棵树的节点被浏览一遍。

1.1 Recursive 版本:

1 def preOrder( self, treenode ):
2     # Recursive version
3     if treenode == None:
4         return
5     print treenode.data
6     self.preOrder( treenode.left )
7     self.preOrder( treenode.right )

这段代码非常好理解,它就是用“根 -> 左 -> 右”的定义方式来写的,迭代调用,直至没有节点可以访问。

print treenode.data # 打印访问节点(根)的值
self.preOrder( treenode ) # 访问左子树
self.preOrder( treenode ) # 访问右子树

1.2 Non-recusive 版本:

 1 def preOrderN( self, treenode ):
 2     # Imperative version
 3     s = []
 4     while treenode is not None or len( s ) > 0:
 5         while treenode is not None:
 6             print treenode.data # 1
 7             s.append( treenode ) # 2
 8             treenode = treenode.left # 2
 9         if len( s ) > 0:
10             treenode = s.pop() # 3
11             treenode = treenode.right # 3

对于非递归版本,首先需要创建一个栈,用来保存需要树的节点,其遍历过程可以这样理解:每次操作由三部分组成:1. 获取当前节点(根)的值,2. 将根的所有左边节点放入栈中,3. 弹出此时的栈顶节点,如果它有右孩子的,将当前节点更新为它的右孩子节点。以上1,2,3,1,2,3...循环下去,直至没有节点可以访问。

2 中序(In-Order)遍历

基本的原则是“左 -> 根 -> 右”

2.1 Recursive 版本:

1 def inOrder( self, treenode ):
2     # Recursive version
3     if treenode == None:
4         return
5     self.inOrder( treenode.left )
6     print treenode.data
7     self.inOrder( treenode.right )

同样是以定义的方式来写的,将“访问左子树”、“获取根的值”、“访问右子树”以迭代的形式写成代码。

2.2 Non-recursive 版本:

 1 def inOrderN( self, treenode ):
 2     # Imperative version
 3     s = []
 4     while treenode is not None or len( s ) > 0:
 5         while treenode is not None:
 6             s.append( treenode ) # 1
 7             treenode = treenode.left # 1
 8         if len( s ) > 0:
 9             treenode = s.pop() # 3
10             print treenode.data # 2
11             treenode = treenode.right # 3

对于非递归版本,我们需要创建一个栈来保存需要树的节点,其遍历过程可以这样理解:每次操作由三部分组成:1. 将根的所有左边节点放入栈中,2. 获取当前节点(根)的值,3. 弹出此时的栈顶节点,如果它有右孩子的,将当前节点更新为它的右孩子节点。以上1,2,3,1,2,3...循环下去,直至没有节点可以访问为止。

3 后序(Post-Order)遍历

基本的原则是“左 -> 右 -> 根”

3.1 Recursive 版本

1 def postOrder( self, treenode ):
2     # Recursive version
3     if treenode == None:
4         return
5     self.postOrder( treenode.left )
6     self.postOrder( treenode.right )
7     print treenode.data

同样是以定义的方式来写的,将“访问左子树”、“访问右子树”、“获取根的值”写成迭代式的代码。

3.2 Non-recursive 版本

 1 def postOrderN( self, treenode ):
 2     # Imperative version
 3     s = []
 4     top = None
 5     pre = None
 6     while treenode is not None or len( s ) > 0:
 7         while treenode is not None:
 8             s.append( treenode ) # 1
 9             treenode = treenode.left # 1
10         if len( s ) > 0:
11             top = s[-1]
12             if top.right != None and top.right != pre:
13                 treenode = top.right # 3
14             else:
15                 print top.data # 2
16                 pre = top # 2
17                 s.pop() # 2

同样需要一个栈来保存树的节点,除此之外还需要一个 pre 记录右孩子的访问情况,过程是这样的:1. 将根的所有左边节点放入栈中,2. 如果栈顶节点的右孩子不存在,或者存在且被访问过,则可以获取当前节点(根)的值,3. 如果栈顶节点的右孩子存在且没被访问过,则进入当前的节点的右子树。以上1,2,3,1,2,3...循环下去,直至没有节点可以访问为止。

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!