zoukankan      html  css  js  c++  java
  • 二叉树算法

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

     

    一、创建与先序遍历

    用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:Python34python3.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:Python34python3.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("33[31;1m二叉树已创建完成33[0m".center(50, "-"))
     69 
     70     while True:
     71         print("""33[31;1m
     72             1.遍历二叉树
     73             2.求二叉树的深度
     74             3.求二叉树叶子结点数
     75             exit.退出33[0m
     76         """)
     77         choice = input("33[31;1m please choose:33[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("33[31;1m depth:33[0m", depth)
     93         elif choice == "3":
     94             # 求二叉树叶子结点数
     95             leaf_count = bt.CountLeaf(root_node, count=0)  # 叶子数为0,当作参数传入
     96             print("33[31;1m leaf_count33[0m", leaf_count)
     97         elif choice == "exit":
     98             exit()
     99         else:
    100             print("33[31;1mPlease input value num33[0m")
    101             continue
    View Code

    二叉树示意图:

    运行结果:

    C:Python34python3.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
  • 相关阅读:
    TWaver HTML5 (2D)--基本概念
    浏览器编码的函数简介escape(),encodeURI(),encodeURIComponent()
    pom.xml
    注解式控制器简介
    Controller接口
    WebContentGenerator
    Controller简介
    DispatcherServlet中使用的特殊的Bean
    DispatcherServlet默认配置
    DispatcherServlet
  • 原文地址:https://www.cnblogs.com/0zcl/p/6736108.html
Copyright © 2011-2022 走看看