二叉树算法

前言:上篇博客写了很多关于二叉树的分类,性质,存储结构。那这篇博客要来写代码了。

 

一、创建与先序遍历

用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

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
View Code

 

二、二叉树的遍历

遍历即将树的所有结点访问且仅访问一次。按照根节点位置的不同分为先序遍历,中序遍历,后序遍历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)

输出:

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
View Code

 

三、求二叉树深度

二叉树由根结点和左、右子树构成,而根结点独占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  # 叶子数

 

 

总程序:

  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
View Code

二叉树示意图:

运行结果:

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
View Code

 

posted @ 2017-04-20 10:49  前程明亮  阅读(403)  评论(0编辑  收藏