二叉树遍历

二叉树的遍历一般以根为起点,存在两种基本遍历方式:

深度优先遍历,顺着一条路径尽可能弹缩,必要时回溯。检查到二叉树的叶节点即符合这种情况,由于无法继续探索,只能向上回溯。

宽度优先遍历,实际上将二叉树进行分层处理,检查完每一个层次后继续向下检查,如果检查到叶节点,则忽略该叶节点之后的层次。

那么按照深度优先遍历规则,下面的基本图则描述了遍历过程中的三个基本单位:根节点、左子树、右子树。对于任何一个子树,也存在相同的访问策略,因为二叉树是递归的。

那么控制这三个单位的访问顺序,即构成了三种不同的遍历结果

前序遍历:即DLR顺序,先访问根节点,再访问左子树,最后访问右子树

后序遍历:即LRD顺序,先访问左子树,再访问右子树,最后访问根节点

中序遍历:即LDR顺序,先访问左子树,再访问根节点,最后访问右子树

 

给出下面这个一个例图,分别说明这三种遍历的结果:

对于前序遍历,结果是ABDHEICFJKG

对于后序遍历,结果是HDIEBJKFGCA

对于中序遍历,结果是DHBEIAJFKCG

 

宽度优先遍历的结果则是:ABCDEFGHIJK。

 

那构建一个二叉树,分别以代码实现这样的遍历过程。

构建二叉树的策略有很多种,常用的一种是传入列表,递归创建,需要注意的是,只有完全二叉树,满足列表创建的需求。

PS:完全二叉树是指对于一个高度为h的二叉树,如果其第0层到第h-1层的节点都是满的,如果最后一层不满但所有节点都是靠左连续排列,空位都在右边,这样的就是一个完全二叉树。

那么上述的图形,需要扩充一下,形成一个完全二叉树满足构建需求,扩充后的结果如下:

那么可以使用完全二叉树的性质, 若一棵二叉树共有n个节点,且按照列表序排序输入,那么:

1)序号为0的是根节点

2  对于序号i > 0,其父节点的序号是 (i - 1) / 2

3) 对于序号i,如果 2 * i + 1 < n,则其左节点序号为 2 * i + 1,否则无左节点;如果 2 * i + 2 < n,则其右节点序号为 2 * i + 2,否则无右节点

那么对于上述完全二叉树,可以用如下列表描述并构建:

[A, B, C, D, E, F, G, #, H, #, I, J, K]

按照一定层次描述即是

A || B, C || D, E, F, G || #, H, #, I, J, K

那么现在开始构建它:

 1 class TreeNode(object):
 2     def __init__(self, val=None, l=None, r=None):
 3         self.val = val
 4         self.left = l
 5         self.right = r
 6 
 7 
 8 class BinaryTree(object):
 9 
10     def __init__(self, tree_list):
11         self.bt = self.build_tree(tree_list, 0)
12 
13     def build_tree(self, tree_list, i):
14         if i < len(tree_list):
15             if tree_list[i] == '#':
16                 return None
17             t = TreeNode(tree_list[i])
18             t.left = self.build_tree(tree_list, 2 * i + 1)
19             t.right = self.build_tree(tree_list, 2 * i + 2)
20             return t
21         return None
22 
23 if __name__ == '__main__':
24     tree_list = ['A', 'B', 'C', 'D', 'E', 'F', 'G', '#', 'H', '#', 'I', 'J', 'K']
25     bt_model = BinaryTree(tree_list)

二叉树构建好之后,开始对它进行分析并遍历。

首先来看一下前序遍历,它的顺序是根,左子树,右子树,那么使用递归的写法是:

1 class BinaryTree(object):
2 
3     @staticmethod
4     def pre_order_recursion(t):
5         if t:
6             print t.val,
7             BinaryTree.pre_order_recursion(t.left)
8             BinaryTree.pre_order_recursion(t.right)

它的思路和前序遍历完全一致,如果根节点非空则访问它,并且继续按照这个规则分别访问它的左右子树

如果不使用递归写法,则需要手动维护一个栈,当遍历一个二叉树的时候,从根节点开始,向左下探索,但凡探索到了则同时压栈右子树;如果左下分支已经探索完毕,那么弹出栈顶右子树,继续上述操作(向左下探索并压栈右子树),直至栈内没有任何信息且树已经全部遍历完为止。

一个思路分析简图如下:

一定要谨记前序遍历的访问顺序,根,左子树,右子树:

手动维护一个栈,是空的

1)对于上图,根节点不为空,则访问根节点,将右子树入栈

2)一路向左,,如果节点不为空右子树入栈,则B的右子树,C, E的右子树也同时入栈,由于E的左子树为空,则无法继续左下,中止这个流程

3)弹出栈顶对象,为E的右子树,但该子树为空,继续弹栈顶对象为C的右子树,但仍为空,一直到弹出B的右子树

4)D不为空,则访问D为根节点的子树,将D的右子树入栈,由于左子树为空,后续弹出F为根节点的子树,F无法左下,则弹出F的右子树,此时栈内只剩下A的右子树且该子树不为空

5)A的右子树重复 2-4 流程

代码如下,并与递归的程序比较结果:

 1 class TreeNode(object):
 2     def __init__(self, val=None, l=None, r=None):
 3         self.val = val
 4         self.left = l
 5         self.right = r
 6 
 7 
 8 class BinaryTree(object):
 9 
10     def __init__(self, tree_list):
11         self.bt = self.build_tree(tree_list, 0)
12 
13     def build_tree(self, tree_list, i):
14         if i < len(tree_list):
15             if tree_list[i] == '#':
16                 return None
17             t = TreeNode(tree_list[i])
18             t.left = self.build_tree(tree_list, 2 * i + 1)
19             t.right = self.build_tree(tree_list, 2 * i + 2)
20             return t
21         return None
22 
23     @staticmethod
24     def pre_order_recursion(t):
25         if t:
26             print t.val,
27             BinaryTree.pre_order_recursion(t.left)
28             BinaryTree.pre_order_recursion(t.right)
29 
30     @staticmethod
31     def pre_order(t):
32         sstack = []
33         while t or sstack: 
34             while t: #左下分支探索
35                 sstack.append(t.right) #右分支入栈
36                 print t.val, # 处理根数据
37                 t = t.left #结合循环,沿着左下分支探索
38             t = sstack.pop() #无法左下探索,弹出栈顶元素
39 
40 
41 if __name__ == '__main__':
42     tree_list = ['A', 'B', 'C', 'D', 'E', 'F', 'G', '#', 'H', '#', 'I', 'J', 'K']
43     bt = BinaryTree(tree_list)
44     bt.pre_order_recursion(bt.bt)
45     print
46     bt.pre_order(bt.bt)
1 /Users/kielchan/PycharmProjects/untitled1/venv/bin/python /Users/kielchan/PycharmProjects/untitled1/venv/binarytree.py
2 A B D H E I C F J K G
3 A B D H E I C F J K G
4 
5 Process finished with exit code 0

与文中一开始的前序遍历结果一致。

既然如此,那么之后把中序遍历和后序遍历的递归和非递归也全写一下好了。

 

  1 #-*- coding:utf-8 -*-
  2 
  3 
  4 class TreeNode(object):
  5     def __init__(self, val=None, l=None, r=None):
  6         self.val = val
  7         self.left = l
  8         self.right = r
  9 
 10 
 11 class BinaryTree(object):
 12 
 13     def __init__(self, tree_list):
 14         self.bt = self.build_tree(tree_list, 0)
 15 
 16     def build_tree(self, tree_list, i):
 17         if i < len(tree_list):
 18             if tree_list[i] == '#':
 19                 return None
 20             t = TreeNode(tree_list[i])
 21             t.left = self.build_tree(tree_list, 2 * i + 1)
 22             t.right = self.build_tree(tree_list, 2 * i + 2)
 23             return t
 24         return None
 25 
 26     @staticmethod
 27     def pre_order_recursion(t):
 28         if t:
 29             print t.val,
 30             BinaryTree.pre_order_recursion(t.left)
 31             BinaryTree.pre_order_recursion(t.right)
 32 
 33     @staticmethod
 34     def in_order_recursion(t):
 35         if t:
 36             BinaryTree.in_order_recursion(t.left)
 37             print t.val,
 38             BinaryTree.in_order_recursion(t.right)
 39 
 40     @staticmethod
 41     def post_order_recursion(t):
 42         if t:
 43             BinaryTree.post_order_recursion(t.left)
 44             BinaryTree.post_order_recursion(t.right)
 45             print t.val,
 46 
 47     @staticmethod
 48     def pre_order(t):
 49         sstack = []
 50         while t or sstack:
 51             while t:
 52                 sstack.append(t.right)
 53                 print t.val,
 54                 t = t.left
 55             t = sstack.pop()
 56 
 57     @staticmethod
 58     def in_order(t):
 59         sstack = []
 60         while t or sstack:
 61             while t:
 62                 sstack.append(t)#将所有左分支节点入栈
 63                 t = t.left
 64             if sstack:
 65                 top = sstack.pop()#弹出左分支节点
 66                 print top.val,#因为是中序遍历,首先处理当前根节点
 67                 t = top.right #因为当前根节点的左子树为空,则处理当前根节点的右子树,符合(L)DR的访问顺序,如果R为空,则向上层回溯
 68 
 69     @staticmethod
 70     def post_order(t):
 71         sstack = []
 72         while t or sstack:
 73             while t:
 74                 sstack.append(t)
 75                 t = t.left if t.left else t.right #按照LRD规则,将L或者R放进堆栈中, L优先级大于R优先级
 76             top = sstack.pop()#弹出栈顶对象并处理它
 77             print top.val,
 78             if sstack and top is sstack[-1].left:
 79                 t = sstack[-1].right #如果弹出对象是当前栈顶对象的左子树则处理当前对象的右子树
 80             else:
 81                 t = None #否则弹出对象是右子树或者已经访问过了,强行退栈向上回溯
 82 
 83     def findTarget(self, root, k):
 84         """
 85         :type root: TreeNode
 86         :type k: int
 87         :rtype: bool
 88         """
 89         if root is None:
 90             return False
 91         if (k - root.val) in self.rv:
 92             return True
 93         self.rv.add(root.val)
 94         return self.findTarget(root.left, k) or self.findTarget(root.right, k)
 95 
 96 
 97 if __name__ == '__main__':
 98     tree_list = ['A', 'B', 'C', 'D', 'E', 'F', 'G', '#', 'H', '#', 'I', 'J', 'K']
 99     bt = BinaryTree(tree_list)
100     print '前序遍历递归算法'
101     bt.pre_order_recursion(bt.bt)
102     print
103     print '前序遍历非递归算法'
104     bt.pre_order(bt.bt)
105     print
106     print '中序遍历递归算法'
107     bt.in_order_recursion(bt.bt)
108     print
109     print '中序遍历非递归算法'
110     bt.in_order(bt.bt)
111     print
112     print '后序遍历递归算法'
113     bt.post_order_recursion(bt.bt)
114     print
115     print '后序遍历非递归算法'
116     bt.post_order(bt.bt)

运行结果:

 1 /Users/kielchan/PycharmProjects/untitled1/venv/bin/python /Users/kielchan/PycharmProjects/untitled1/venv/binarytree.py
 2 前序遍历递归算法
 3 A B D H E I C F J K G
 4 前序遍历非递归算法
 5 A B D H E I C F J K G
 6 中序遍历递归算法
 7 D H B E I A J F K C G
 8 中序遍历非递归算法
 9 D H B E I A J F K C G
10 后序遍历递归算法
11 H D I E B J K F G C A
12 后序遍历非递归算法
13 H D I E B J K F G C A
14 
15 Process finished with exit code 0

最后一个是宽度优先遍历算法,它的机制很简单,只需维护一个栈,处理当前层次的节点对象,处理一个则弹出一个,并将他的孩子入栈,代码如下:

 1 #-*- coding:utf-8 -*-
 2 
 3 
 4 class TreeNode(object):
 5     def __init__(self, val=None, l=None, r=None):
 6         self.val = val
 7         self.left = l
 8         self.right = r
 9 
10 
11 class BinaryTree(object):
12 
13     def __init__(self, tree_list):
14         self.bt = self.build_tree(tree_list, 0)
15 
16     def build_tree(self, tree_list, i):
17         if i < len(tree_list):
18             if tree_list[i] == '#':
19                 return None
20             t = TreeNode(tree_list[i])
21             t.left = self.build_tree(tree_list, 2 * i + 1)
22             t.right = self.build_tree(tree_list, 2 * i + 2)
23             return t
24         return None
25 
26     @staticmethod
27     def BFS(t):
28         sstack = []
29         sstack.insert(0, t)
30         while sstack:
31             top = sstack.pop()
32             if top is None:
33                 continue
34             print top.val,
35             sstack.insert(0, top.left)
36             sstack.insert(0, top.right)
37 
38 
39 if __name__ == '__main__':
40     tree_list = ['A', 'B', 'C', 'D', 'E', 'F', 'G', '#', 'H', '#', 'I', 'J', 'K']
41     bt = BinaryTree(tree_list)
42     print '宽度优先遍历算法'
43     bt.BFS(bt.bt)

打印结果如下:

1 /Users/kielchan/PycharmProjects/untitled1/venv/bin/python /Users/kielchan/PycharmProjects/untitled1/venv/binarytree.py
2 宽度优先遍历算法
3 A B C D E F G H I J K
4 
5 Process finished with exit code 0

 

转载于:https://www.cnblogs.com/diagnose/p/9134352.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值