自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

詳解數(shù)據(jù)結(jié)構(gòu)二叉樹及其代碼實現(xiàn)

開發(fā) 前端
樹是一種非常重要的非線性結(jié)構(gòu),本身具有遞歸的性質(zhì)(在其后的編程中體現(xiàn)的淋漓盡致)。

 樹

樹是一種非常重要的非線性結(jié)構(gòu),本身具有遞歸的性質(zhì)(在其后的編程中體現(xiàn)的淋漓盡致)。


看下圖,A 節(jié)點就是 B 節(jié)點的父節(jié)點,B 節(jié)點是 A 節(jié)點的子節(jié)點。B、C、D 這三個節(jié)點的父節(jié)點是同一個節(jié)點A,沒有父節(jié)點的叫做根節(jié)點,也就是 E 。

 

沒有子節(jié)點的節(jié)點叫作葉子節(jié)點或者葉節(jié)點,圖中的G,H,I,J,K,L

關(guān)于“樹”,還有三個比較相似的概念:高度(Height)、深度(Depth),層(level)


二叉樹(binary Tree)

二叉樹是n(n>=0)個結(jié)點的有限集合,該集合或者為空集(稱為空二叉樹),或者由一個根結(jié)點和兩棵互不相交的、分別稱為根結(jié)點的左子樹和右子樹組成。


上圖中,編號1是普通二叉樹,編號2又是滿二叉樹,編號2又是完全二叉樹。

滿二叉樹:在一棵二叉樹中。如果所有分支結(jié)點都存在左子樹和右子樹,并且所有葉子都在同一層上,這樣的二叉樹稱為滿二叉樹。

滿二叉樹的特點有:

  • 葉子只能出現(xiàn)在最下一層。出現(xiàn)在其它層就不可能達成平衡。
  • 非葉子結(jié)點的度一定是2。
  • 在同樣深度的二叉樹中,滿二叉樹的結(jié)點個數(shù)最多,葉子數(shù)最多。

編號3是完全二叉樹

「對一顆具有n個結(jié)點的二叉樹按層編號,如果編號為i(1<=i<=n)的結(jié)點與同樣深度的滿二叉樹中編號為i的結(jié)點在二叉樹中位置完全相同,則這棵二叉樹稱為完全二叉樹?!?/strong>

就是保證葉子節(jié)點的上面層都要達到最大,最低下兩層,最后一層的葉子節(jié)點都靠左排列


二叉樹具備以下數(shù)學(xué)性質(zhì):

在二叉樹的第i層上至多有2(i-1)個結(jié)點(i>0)

深度為k的二叉樹至多有2K-1個結(jié)點(k>0)

對于任意一棵二叉樹,如果其葉結(jié)點數(shù)為N0,而度數(shù)為2的結(jié)點總數(shù)為N2,則N0=N2+1;

具有n個結(jié)點的完全二叉樹的深度必為log2(n+1)

二叉樹的遍歷和節(jié)點的刪除

二叉樹的遍歷是指從二叉樹的根結(jié)點出發(fā),按照某種次序依次訪問二叉樹中的所有結(jié)點,使得每個結(jié)點被訪問一次,且僅被訪問一次。

  • 中序遍歷:先左子樹,再根節(jié)點,最后右子樹
  • 前序遍歷:先根節(jié)點,再左子樹,最后右子樹
  • 后序遍歷:先左子樹,再右子樹,最后根節(jié)點。

前序遍歷通俗的說就是從二叉樹的根結(jié)點出發(fā),當(dāng)?shù)谝淮蔚竭_結(jié)點時就輸出結(jié)點數(shù)據(jù),按照先向左在向右的方向訪問。

中序遍歷就是從二叉樹的根結(jié)點出發(fā),當(dāng)?shù)诙蔚竭_結(jié)點時就輸出結(jié)點數(shù)據(jù),按照先向左在向右的方向訪問。

后序遍歷就是從二叉樹的根結(jié)點出發(fā),當(dāng)?shù)谌蔚竭_結(jié)點時就輸出結(jié)點數(shù)據(jù),按照先向左在向右的方向訪問。


刪除共有三種情況

  • 被刪除的節(jié)點是葉子節(jié)點,這時候只要把這個節(jié)點刪除,再把指向這個節(jié)點的父節(jié)點指針置為空就行
  • 被刪除的節(jié)點有左子樹,或者有右子樹,而且只有其中一個,那么只要把當(dāng)前刪除節(jié)點的父節(jié)點指向被刪除節(jié)點的左子樹或者右子樹就行。
  • 如果要刪除的節(jié)點有兩個子節(jié)點,需要找到這個節(jié)點的右子樹的最小節(jié)點,把它替換到要刪除的節(jié)點上,然后再刪除掉這個最小節(jié)點,因為最小節(jié)點肯定沒有左子節(jié)點

 

代碼具體實現(xiàn)二叉樹

上面就是二叉樹全部內(nèi)容,下面用Pytho代碼具體實現(xiàn)二叉樹。

按下來就是編程實現(xiàn)了,請動手自己實現(xiàn)一把。

先實現(xiàn)一個 node 節(jié)點類:

  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 。

實現(xiàn)一個二叉樹類:

  1. class Tree(object): 
  2.     def __init__(self): 
  3.         # 根節(jié)點定義為 root 永不刪除,做為哨兵使用。 
  4.         self.root = Node('root'
  5.     # 添加節(jié)點操作 
  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 的父節(jié)點 
  27.         ''
  28.         if self.root.item == item: 
  29.             return None  # 根節(jié)點沒有父節(jié)點 
  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.         先獲取 待刪除節(jié)點 item 的父節(jié)點 
  47.         如果父節(jié)點不為空, 
  48.             判斷 item 的左右子樹 
  49.             如果左子樹為空,那么判斷 item 是父節(jié)點的左孩子,還是右孩子,如果是左孩子,將父節(jié)點的左指針指向 item 的右子樹,反之將父節(jié)點的右指針指向 item 的右子樹 
  50.             如果右子樹為空,那么判斷 item 是父節(jié)點的左孩子,還是右孩子,如果是左孩子,將父節(jié)點的左指針指向 item 的左子樹,反之將父節(jié)點的右指針指向 item 的左子樹 
  51.             如果左右子樹均不為空,尋找右子樹中的最左葉子節(jié)點 x ,將 x 替代要刪除的節(jié)點。 
  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  # 待刪除節(jié)點 
  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)) 

執(zhí)行結(jié)果如下:

  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

 

責(zé)任編輯:姜華 來源: Python之王
相關(guān)推薦

2021-04-20 08:37:14

數(shù)據(jù)結(jié)構(gòu)二叉樹

2021-04-19 07:47:42

數(shù)據(jù)結(jié)構(gòu)二叉樹Tree

2021-04-28 20:12:27

數(shù)據(jù)結(jié)構(gòu)創(chuàng)建

2020-11-02 09:15:47

算法與數(shù)據(jù)結(jié)構(gòu)

2013-01-30 10:34:02

數(shù)據(jù)結(jié)構(gòu)

2020-04-27 07:05:58

二叉樹左子樹右子樹

2021-03-19 10:25:12

Java數(shù)據(jù)結(jié)構(gòu)算法

2021-04-01 10:34:18

Java編程數(shù)據(jù)結(jié)構(gòu)算法

2020-09-23 18:25:40

算法二叉樹多叉樹

2021-03-22 09:00:22

Java數(shù)據(jù)結(jié)構(gòu)算法

2018-03-15 08:31:57

二叉樹存儲結(jié)構(gòu)

2021-10-12 09:25:11

二叉樹樹形結(jié)構(gòu)

2019-08-22 09:22:44

數(shù)據(jù)結(jié)構(gòu)二叉搜索樹

2021-09-29 10:19:00

算法平衡二叉樹

2021-03-17 08:19:22

二叉樹LeetCode

2013-07-15 16:35:55

二叉樹迭代器

2020-12-22 08:56:51

JavaScript數(shù)據(jù)結(jié)構(gòu)前端

2009-08-11 13:29:57

C#二叉樹遍歷

2021-03-29 10:13:47

Java編程數(shù)據(jù)結(jié)構(gòu)算法

2021-03-22 08:23:29

LeetCode二叉樹節(jié)點
點贊
收藏

51CTO技術(shù)棧公眾號