二叉树算法
前言:上篇博客写了很多关于二叉树的分类,性质,存储结构。那这篇博客要来写代码了。
一、创建与先序遍历
用C语言实现二叉树是很方便的,因为C语言有很高大上的指针。但,python就没有指针了,那怎么办呢? 我们可以用一个类来实现(java也是用类实现的)……
下面我创建一课二叉树,并且用先序遍历结点:
1 class TreeNode(object): # 创建树的结点
2 def __init__(self, node_data=None, left=None, right=None):
3 self.node_data = node_data
4 self.left = left
5 self.right = right
6
7
8 class BTree(object):
9 def __init__(self, root=None): # 初始化根结点
10 self.root = root
11
12 def preorder(self, tree_node):
13 if tree_node is None:
14 return
15 print(tree_node.node_data)
16 self.preorder(tree_node.left)
17 self.preorder(tree_node.right)
18
19
20 if __name__ == '__main__':
21 n1 = TreeNode(1)
22 n2 = TreeNode(2, n1)
23 n3 = TreeNode(3)
24 n4 = TreeNode(4)
25 n5 = TreeNode(5, n3, n4)
26 n6 = TreeNode(6, n2, n5)
27 n7 = TreeNode(7, n6)
28 n8 = TreeNode(8)
29
30 root_node = TreeNode('root', n7, n8) # 根结点
31
32 bt = BTree(root_node) # 将根结点(包含左右结点)当作参数传给BTree类
33
34 # 前序遍历
35 bt.preorder(root_node)
上面代码很重要,也很简单,看不懂可以的话就得去看看类与面向对象的知识了。首先我创建了如下的一课二叉树:
先序遍历的结果是: root-7-6-2-1-5-3-4-8
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
C:\Python34\python3.exe C:/Users/Administrator/PycharmProjects/laonanhai/编程/创建二叉树.py root 7 6 2 1 5 3 4 8 Process finished with exit code 0
二、二叉树的遍历
遍历即将树的所有结点访问且仅访问一次。按照根节点位置的不同分为先序遍历,中序遍历,后序遍历。V表示访问根结点,L表示遍历左子树,R表示遍历右子树。
- 先序遍历:根节点->左子树->右子树
- 中序遍历:左子树->根节点->右子树
- 后序遍历:左子树->右子树->根节点
下面做个练习热热身: 写出上图二叉树的三种遍历方式
- 先序遍历:abdefgc
- 中序遍历:debgfac
- 后序遍历:edgfbca
很好,现在给你一课二叉树,你应该能写出三种遍历方式。啥,不懂? 那你得多牛才进得了BAT......
我拿中序遍历来讲一下吧。中序遍历是先遍历左子树,再结点,最后右子树。以上图为例,先找根结点a的左子树b, 但b还有左子树,所以遍历的第一个数还不是b. 最后我找到了d,发现d没有左子树了,好,遍历的第一个数为结点d, 接下来为d的右子树e。e没有左右子树,所以此时以d为根结点的树已遍历完成,接下来看b的上一层,即b. b的左子树已遍历,所以遍历的第三个数为b, 接下来遍历b的右子树(以f的根结点的二叉树),发现此时f有左子树,好极了,遍历f的左子树g,发现g结点没有左右子树,故第4个数就是g, 第5个数是g的父亲f. 接下来应该遍历f的右子树的,但f的右子树为空,b的右子树遍历完成,就直接返回上一层。此时以b为根结点的树已遍历完成。同理,接下来还需遍历a, c。最终结果是: d-e-b-g-f-a-c
遍历算法:
1 class TreeNode(object): # 创建树的结点
2 def __init__(self, node_data=None, left=None, right=None):
3 self.node_data = node_data
4 self.left = left
5 self.right = right
6
7
8 class BTree(object):
9 def __init__(self, root=None): # 初始化根结点
10 self.root = root
11
12 def PreOrder(self, tree_node): # 先序遍历
13 if tree_node is None:
14 return
15 print(tree_node.node_data)
16 self.PreOrder(tree_node.left)
17 self.PreOrder(tree_node.right)
18
19 def InOrder(self, tree_node): # 中序遍历
20 if tree_node is None:
21 return
22 self.InOrder(tree_node.left)
23 print(tree_node.node_data)
24 self.InOrder(tree_node.right)
25
26 def PostOrder(self, tree_node): # 后序遍历
27 if tree_node is None:
28 return
29 self.PostOrder(tree_node.left)
30 self.PostOrder(tree_node.right)
31 print(tree_node.node_data)
32
33
34 if __name__ == '__main__':
35 n1 = TreeNode(1)
36 n2 = TreeNode(2, n1)
37 n3 = TreeNode(3)
38 n4 = TreeNode(4)
39 n5 = TreeNode(5, n3, n4)
40 n6 = TreeNode(6, n2, n5)
41 n7 = TreeNode(7, n6)
42 n8 = TreeNode(8)
43
44 root_node = TreeNode('root', n7, n8) # 根结点
45
46 bt = BTree(root_node) # 将根结点(包含左右结点)当作参数传给BTree类
47
48 # 前序遍历
49 print("PreOrder".center(50, "-"))
50 bt.PreOrder(root_node)
51
52 # 中序遍历
53 print("InOrder".center(50, "-"))
54 bt.InOrder(root_node)
55
56 # 后序遍历
57 print("PostOrder".center(50, "-"))
58 bt.PostOrder(root_node)
输出:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
C:\Python34\python3.exe C:/Users/Administrator/PycharmProjects/laonanhai/编程/遍历二叉树.py ---------------------PreOrder--------------------- root 7 6 2 1 5 3 4 8 ---------------------InOrder---------------------- 1 2 6 3 5 4 7 root 8 --------------------PostOrder--------------------- 1 2 3 4 5 6 7 8 root Process finished with exit code 0
三、求二叉树深度
二叉树由根结点和左、右子树构成,而根结点独占1层,所以二叉树深度为其左右子树深度的最大值加1.
利用后层遍历的思想,先递归求左、右子树的深度,然后取两者较大值 +1,作为深度值返回。
算法实现:
1 def BitTreeDepth(self, tree_node): # tree_node为结点
2 if tree_node is None: # 空二叉树深度为0
3 return 0
4 else:
5 depth_left = self.BitTreeDepth(tree_node.left) # 求左子树深度
6 depth_right = self.BitTreeDepth(tree_node.right) # 求右子树深度
7 # 左右子树深度较大值+1
8 return 1 + (depth_left if depth_left>depth_right else depth_right)
四、求二叉树叶子结点数
同样,我们也可以遍历左、右子树各有多少个叶子结点,一遍历到叶子结点则count++, count初始值为0.
在计算叶子结点数时,教材用C语言写的算法有用到指针,我用python写就挺懵比。后来把算法改了下,总算是搞出来了:
算法:
1 def CountLeaf(self, tree_node, count):
2 if tree_node is None:
3 return count
4
5 if not tree_node.left and not tree_node.right: # 没有左右结点,即为叶子结点
6 count += 1
7
8 count = self.CountLeaf(tree_node.left, count) # 对左子树进行递归计数
9 count = self.CountLeaf(tree_node.right, count)
10 return count # 叶子数
总程序:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class TreeNode(object): # 创建树的结点 2 def __init__(self, node_data=None, left=None, right=None): 3 self.node_data = node_data 4 self.left = left 5 self.right = right 6 7 8 class BTree(object): 9 def __init__(self, root=None): # 初始化根结点 10 self.root = root 11 12 def PreOrder(self, tree_node): # 先序遍历 13 if tree_node is None: 14 return 15 print(tree_node.node_data) 16 self.PreOrder(tree_node.left) 17 self.PreOrder(tree_node.right) 18 19 def InOrder(self, tree_node): # 中序遍历 20 if tree_node is None: 21 return 22 self.InOrder(tree_node.left) 23 print(tree_node.node_data) 24 self.InOrder(tree_node.right) 25 26 def PostOrder(self, tree_node): # 后序遍历 27 if tree_node is None: 28 return 29 self.PostOrder(tree_node.left) 30 self.PostOrder(tree_node.right) 31 print(tree_node.node_data) 32 33 def BitTreeDepth(self, tree_node): # tree_node为结点 34 if tree_node is None: # 空二叉树深度为0 35 return 0 36 else: 37 depth_left = self.BitTreeDepth(tree_node.left) # 求左子树深度 38 depth_right = self.BitTreeDepth(tree_node.right) # 求右子树深度 39 # 左右子树深度较大值+1 40 return 1 + (depth_left if depth_left>depth_right else depth_right) 41 42 def CountLeaf(self, tree_node, count): 43 if tree_node is None: 44 return count 45 46 if not tree_node.left and not tree_node.right: # 没有左右结点,即为叶子结点 47 count += 1 48 49 count = self.CountLeaf(tree_node.left, count) # 对左子树进行递归计数 50 count = self.CountLeaf(tree_node.right, count) 51 return count # 叶子数 52 53 54 if __name__ == '__main__': 55 n1 = TreeNode(1) 56 n2 = TreeNode(2, n1) 57 n3 = TreeNode(3) 58 n4 = TreeNode(4) 59 n5 = TreeNode(5, n3, n4) 60 n6 = TreeNode(6, n2, n5) 61 n7 = TreeNode(7, n6) 62 n8 = TreeNode(8) 63 64 root_node = TreeNode('root', n7, n8) # 根结点 65 66 bt = BTree(root_node) # 将根结点(包含左右结点)当作参数传给BTree类 67 68 print("\033[31;1m二叉树已创建完成\033[0m".center(50, "-")) 69 70 while True: 71 print("""\033[31;1m 72 1.遍历二叉树 73 2.求二叉树的深度 74 3.求二叉树叶子结点数 75 exit.退出\033[0m 76 """) 77 choice = input("\033[31;1m please choose:\033[0m") 78 if choice == "1": 79 print("开始遍历二叉树".center(50, "-")) 80 # 前序遍历 81 print("PreOrder".center(50, "-")) 82 bt.PreOrder(root_node) 83 # 中序遍历 84 print("InOrder".center(50, "-")) 85 bt.InOrder(root_node) 86 # 后序遍历 87 print("PostOrder".center(50, "-")) 88 bt.PostOrder(root_node) 89 elif choice == "2": 90 # 求二叉树的深度 91 depth = bt.BitTreeDepth(root_node) 92 print("\033[31;1m depth:\033[0m", depth) 93 elif choice == "3": 94 # 求二叉树叶子结点数 95 leaf_count = bt.CountLeaf(root_node, count=0) # 叶子数为0,当作参数传入 96 print("\033[31;1m leaf_count\033[0m", leaf_count) 97 elif choice == "exit": 98 exit() 99 else: 100 print("\033[31;1mPlease input value num\033[0m") 101 continue
二叉树示意图:
运行结果:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
C:\Python34\python3.exe C:/Users/Administrator/PycharmProjects/laonanhai/编程/遍历二叉树.py ---------------二叉树已创建完成---------------- 1.遍历二叉树 2.求二叉树的深度 3.求二叉树叶子结点数 exit.退出 please choose:1 ---------------------开始遍历二叉树---------------------- ---------------------PreOrder--------------------- root 7 6 2 1 5 3 4 8 ---------------------InOrder---------------------- 1 2 6 3 5 4 7 root 8 --------------------PostOrder--------------------- 1 2 3 4 5 6 7 8 root 1.遍历二叉树 2.求二叉树的深度 3.求二叉树叶子结点数 exit.退出 please choose:2 depth: 5 1.遍历二叉树 2.求二叉树的深度 3.求二叉树叶子结点数 exit.退出 please choose:3 leaf_count 4 1.遍历二叉树 2.求二叉树的深度 3.求二叉树叶子结点数 exit.退出 please choose:exit Process finished with exit code 0
出处:http://www.cnblogs.com/0zcl
文章未标明转载则为原创博客。欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
1.非系统的学习也是在浪费时间
2.做一个会欣赏美,懂艺术,会艺术的技术人