详解数据结构二叉树及其代码实现

开发 前端
树是一种非常重要的非线性结构,本身具有递归的性质(在其后的编程中体现的淋漓尽致)。

 树

树是一种非常重要的非线性结构,本身具有递归的性质(在其后的编程中体现的淋漓尽致)。


看下图,A 节点就是 B 节点的父节点,B 节点是 A 节点的子节点。B、C、D 这三个节点的父节点是同一个节点A,没有父节点的叫做根节点,也就是 E 。

 

没有子节点的节点叫作叶子节点或者叶节点,图中的G,H,I,J,K,L

关于“树”,还有三个比较相似的概念:高度(Height)、深度(Depth),层(level)


二叉树(binary Tree)

二叉树是n(n>=0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树组成。


上图中,编号1是普通二叉树,编号2又是满二叉树,编号2又是完全二叉树。

满二叉树:在一棵二叉树中。如果所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上,这样的二叉树称为满二叉树。

满二叉树的特点有:

  • 叶子只能出现在最下一层。出现在其它层就不可能达成平衡。
  • 非叶子结点的度一定是2。
  • 在同样深度的二叉树中,满二叉树的结点个数最多,叶子数最多。

编号3是完全二叉树

「对一颗具有n个结点的二叉树按层编号,如果编号为i(1<=i<=n)的结点与同样深度的满二叉树中编号为i的结点在二叉树中位置完全相同,则这棵二叉树称为完全二叉树。」

就是保证叶子节点的上面层都要达到最大,最低下两层,最后一层的叶子节点都靠左排列


二叉树具备以下数学性质:

在二叉树的第i层上至多有2(i-1)个结点(i>0)

深度为k的二叉树至多有2K-1个结点(k>0)

对于任意一棵二叉树,如果其叶结点数为N0,而度数为2的结点总数为N2,则N0=N2+1;

具有n个结点的完全二叉树的深度必为log2(n+1)

二叉树的遍历和节点的删除

二叉树的遍历是指从二叉树的根结点出发,按照某种次序依次访问二叉树中的所有结点,使得每个结点被访问一次,且仅被访问一次。

  • 中序遍历:先左子树,再根节点,最后右子树
  • 前序遍历:先根节点,再左子树,最后右子树
  • 后序遍历:先左子树,再右子树,最后根节点。

前序遍历通俗的说就是从二叉树的根结点出发,当第一次到达结点时就输出结点数据,按照先向左在向右的方向访问。

中序遍历就是从二叉树的根结点出发,当第二次到达结点时就输出结点数据,按照先向左在向右的方向访问。

后序遍历就是从二叉树的根结点出发,当第三次到达结点时就输出结点数据,按照先向左在向右的方向访问。


删除共有三种情况

  • 被删除的节点是叶子节点,这时候只要把这个节点删除,再把指向这个节点的父节点指针置为空就行
  • 被删除的节点有左子树,或者有右子树,而且只有其中一个,那么只要把当前删除节点的父节点指向被删除节点的左子树或者右子树就行。
  • 如果要删除的节点有两个子节点,需要找到这个节点的右子树的最小节点,把它替换到要删除的节点上,然后再删除掉这个最小节点,因为最小节点肯定没有左子节点

 

代码具体实现二叉树

上面就是二叉树全部内容,下面用Pytho代码具体实现二叉树。

按下来就是编程实现了,请动手自己实现一把。

先实现一个 node 节点类:

  1. class Node(object): 
  2.     def __init__(self, item): 
  3.         self.item = item 
  4.         self.left = None 
  5.         self.right = None 
  6.  
  7.     def __str__(self): 
  8.         return str(self.item) 

这里的 __str__ 方法是为了方便打印。在 print 一个 Node 类时会打印__str__的返回值,例如:print(Node(5)) 就会打印出字符串 5 。

实现一个二叉树类:

  1. class Tree(object): 
  2.     def __init__(self): 
  3.         # 根节点定义为 root 永不删除,做为哨兵使用。 
  4.         self.root = Node('root'
  5.     # 添加节点操作 
  6.     def add(self, item): 
  7.         node = Node(item) 
  8.         if self.root is None: 
  9.             self.root = node 
  10.         else
  11.             q = [self.root] 
  12.             while True
  13.                 pop_node = q.pop(0) 
  14.                 if pop_node.left is None: 
  15.                     pop_node.left = node 
  16.                     return 
  17.                 elif pop_node.right is None: 
  18.                     pop_node.right = node 
  19.                     return 
  20.                 else
  21.                     q.append(pop_node.left
  22.                     q.append(pop_node.right
  23.  
  24.     def get_parent(self, item): 
  25.         ''
  26.         找到 Item 的父节点 
  27.         ''
  28.         if self.root.item == item: 
  29.             return None  # 根节点没有父节点 
  30.         tmp = [self.root] 
  31.         while tmp: 
  32.             pop_node = tmp.pop(0) 
  33.             if pop_node.left and pop_node.left.item == item: 
  34.                 return pop_node 
  35.             if pop_node.right and pop_node.right.item == item: 
  36.                 return pop_node 
  37.             if pop_node.left is not None: 
  38.                 tmp.append(pop_node.left
  39.             if pop_node.right is not None: 
  40.                 tmp.append(pop_node.right
  41.         return None 
  42.  
  43.     def delete(self, item): 
  44.         ''
  45.         从二叉树中删除一个元素 
  46.         先获取 待删除节点 item 的父节点 
  47.         如果父节点不为空, 
  48.             判断 item 的左右子树 
  49.             如果左子树为空,那么判断 item 是父节点的左孩子,还是右孩子,如果是左孩子,将父节点的左指针指向 item 的右子树,反之将父节点的右指针指向 item 的右子树 
  50.             如果右子树为空,那么判断 item 是父节点的左孩子,还是右孩子,如果是左孩子,将父节点的左指针指向 item 的左子树,反之将父节点的右指针指向 item 的左子树 
  51.             如果左右子树均不为空,寻找右子树中的最左叶子节点 x ,将 x 替代要删除的节点。 
  52.         删除成功,返回 True 
  53.         删除失败, 返回 False 
  54.  
  55.         ''
  56.         if self.root is None:  # 如果根为空,就什么也不做 
  57.             return False 
  58.  
  59.         parent = self.get_parent(item) 
  60.         if parent: 
  61.             del_node = parent.left if parent.left.item == item else parent.right  # 待删除节点 
  62.             if del_node.left is None: 
  63.                 if parent.left.item == item: 
  64.                     parent.left = del_node.right 
  65.                 else
  66.                     parent.right = del_node.right 
  67.                 del del_node 
  68.                 return True 
  69.             elif del_node.right is None: 
  70.                 if parent.left.item == item: 
  71.                     parent.left = del_node.left 
  72.                 else
  73.                     parent.right = del_node.left 
  74.                 del del_node 
  75.                 return True 
  76.             else:  # 左右子树都不为空 
  77.                 tmp_pre = del_node 
  78.                 tmp_next = del_node.right 
  79.                 if tmp_next.left is None: 
  80.                     # 替代 
  81.                     tmp_pre.right = tmp_next.right 
  82.                     tmp_next.left = del_node.left 
  83.                     tmp_next.right = del_node.right 
  84.  
  85.                 else
  86.                     while tmp_next.left:  # 让tmp指向右子树的最后一个叶子 
  87.                         tmp_pre = tmp_next 
  88.                         tmp_next = tmp_next.left 
  89.                     # 替代 
  90.                     tmp_pre.left = tmp_next.right 
  91.                     tmp_next.left = del_node.left 
  92.                     tmp_next.right = del_node.right 
  93.                 if parent.left.item == item: 
  94.                     parent.left = tmp_next 
  95.                 else
  96.                     parent.right = tmp_next 
  97.                 del del_node 
  98.                 return True 
  99.         else
  100.             return False 
  101.  
  102.     def traverse(self):  # 层次遍历 
  103.         if self.root is None: 
  104.             return None 
  105.         q = [self.root] 
  106.         res = [self.root.item] 
  107.         while q != []: 
  108.             pop_node = q.pop(0) 
  109.             if pop_node.left is not None: 
  110.                 q.append(pop_node.left
  111.                 res.append(pop_node.left.item) 
  112.  
  113.             if pop_node.right is not None: 
  114.                 q.append(pop_node.right
  115.                 res.append(pop_node.right.item) 
  116.         return res 
  117.  
  118.     def preorder(self, root):  # 先序遍历 
  119.         if root is None: 
  120.             return [] 
  121.         result = [root.item] 
  122.         left_item = self.preorder(root.left
  123.         right_item = self.preorder(root.right
  124.         return result + left_item + right_item 
  125.  
  126.     def inorder(self, root):  # 中序遍历 
  127.         if root is None: 
  128.             return [] 
  129.         result = [root.item] 
  130.         left_item = self.inorder(root.left
  131.         right_item = self.inorder(root.right
  132.         return left_item + result + right_item 
  133.  
  134.     def postorder(self, root):  # 后序遍历 
  135.         if root is None: 
  136.             return [] 
  137.         result = [root.item] 
  138.         left_item = self.postorder(root.left
  139.         right_item = self.postorder(root.right
  140.         return left_item + right_item + result 

运行测试:

  1. if __name__ == '__main__'
  2.     t = Tree() 
  3.     for i in range(10): 
  4.         t.add(i) 
  5.     print('层序遍历:', t.traverse()) 
  6.     print('先序遍历:', t.preorder(t.root)) 
  7.     print('中序遍历:', t.inorder(t.root)) 
  8.     print('后序遍历:', t.postorder(t.root)) 
  9.  
  10.     for i in range(10): 
  11.         print(i, " 的父亲", t.get_parent(i)) 
  12.  
  13.     for i in range(0, 15, 3): 
  14.         print(f"删除 {i}"'成功' if t.delete(i) else '失败'
  15.         print('层序遍历:', t.traverse()) 
  16.         print('先序遍历:', t.preorder(t.root)) 
  17.         print('中序遍历:', t.inorder(t.root)) 
  18.         print('后序遍历:', t.postorder(t.root)) 

执行结果如下:

  1. 层序遍历: ['root', 0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
  2. 先序遍历: ['root', 0, 2, 6, 7, 3, 8, 9, 1, 4, 5] 
  3. 中序遍历: [6, 2, 7, 0, 8, 3, 9, 'root', 4, 1, 5] 
  4. 后序遍历: [6, 7, 2, 8, 9, 3, 0, 4, 5, 1, 'root'
  5. 0  的父亲 root 
  6. 1  的父亲 root 
  7. 2  的父亲 0 
  8. 3  的父亲 0 
  9. 4  的父亲 1 
  10. 5  的父亲 1 
  11. 6  的父亲 2 
  12. 7  的父亲 2 
  13. 8  的父亲 3 
  14. 9  的父亲 3 
  15. 删除 0 成功 
  16. 层序遍历: ['root', 8, 1, 2, 3, 4, 5, 6, 7, 9] 
  17. 先序遍历: ['root', 8, 2, 6, 7, 3, 9, 1, 4, 5] 
  18. 中序遍历: [6, 2, 7, 8, 3, 9, 'root', 4, 1, 5] 
  19. 后序遍历: [6, 7, 2, 9, 3, 8, 4, 5, 1, 'root'
  20. 删除 3 成功 
  21. 层序遍历: ['root', 8, 1, 2, 9, 4, 5, 6, 7] 
  22. 先序遍历: ['root', 8, 2, 6, 7, 9, 1, 4, 5] 
  23. 中序遍历: [6, 2, 7, 8, 9, 'root', 4, 1, 5] 
  24. 后序遍历: [6, 7, 2, 9, 8, 4, 5, 1, 'root'
  25. 删除 6 成功 
  26. 层序遍历: ['root', 8, 1, 2, 9, 4, 5, 7] 
  27. 先序遍历: ['root', 8, 2, 7, 9, 1, 4, 5] 
  28. 中序遍历: [2, 7, 8, 9, 'root', 4, 1, 5] 
  29. 后序遍历: [7, 2, 9, 8, 4, 5, 1, 'root'
  30. 删除 9 成功 
  31. 层序遍历: ['root', 8, 1, 2, 4, 5, 7] 
  32. 先序遍历: ['root', 8, 2, 7, 1, 4, 5] 
  33. 中序遍历: [2, 7, 8, 'root', 4, 1, 5] 
  34. 后序遍历: [7, 2, 8, 4, 5, 1, 'root'
  35. 删除 12 失败 
  36. 层序遍历: ['root', 8, 1, 2, 4, 5, 7] 
  37. 先序遍历: ['root', 8, 2, 7, 1, 4, 5] 
  38. 中序遍历: [2, 7, 8, 'root', 4, 1, 5] 
  39. 后序遍历: [7, 2, 8, 4, 5, 1, 'root'

Binarytree是一个Python库,它通过一个简单的API生成二叉树,可以进行检查和操作。Github:https://github.com/joowani/binarytree/releases。

本文已收录 GitHub  https://github.com/MaoliRUNsen/runsenlearnpy100

 

责任编辑:姜华 来源: Python之王
相关推荐

2021-04-20 08:37:14

数据结构二叉树

2021-04-19 07:47:42

数据结构二叉树Tree

2013-01-30 10:34:02

数据结构

2020-11-02 09:15:47

算法与数据结构

2021-04-28 20:12:27

数据结构创建

2020-04-27 07:05:58

二叉树左子树右子树

2021-04-01 10:34:18

Java编程数据结构算法

2021-03-19 10:25:12

Java数据结构算法

2020-09-23 18:25:40

算法二叉树多叉树

2018-03-15 08:31:57

二叉树存储结构

2021-03-22 09:00:22

Java数据结构算法

2021-10-12 09:25:11

二叉树树形结构

2013-07-15 16:35:55

二叉树迭代器

2021-03-17 08:19:22

二叉树LeetCode

2019-08-22 09:22:44

数据结构二叉搜索树

2021-09-29 10:19:00

算法平衡二叉树

2021-05-06 17:46:30

二叉树数据结构

2022-10-26 23:58:02

二叉树数组算法

2023-04-06 07:39:48

2009-05-27 09:38:32

C#二叉树
点赞
收藏

51CTO技术栈公众号