Python數據結構與算法—樹形結構、二叉樹


基礎概念

1.定義:樹(Tree)是n(n≥0)個節點的有限集合T,它滿足兩個條件:有且僅有一個特定的稱為根(Root)的節點;其余的節點可以分為m(m≥0)個互不相交的有限集合T1、T2、……、Tm,其中每一個集合又是一棵樹,並稱為其根的子樹(Subtree)。

2.基本概念

  • 一個節點的子樹的個數稱為該節點的度數,一棵樹的度數是指該樹中節點的最大度數。
  • 度數為零的節點稱為樹葉或終端節點,度數不為零的節點稱為分支節點,除根節點外的分支節點稱為內部節點。
  • 一個節點的子樹之根節點稱為該節點的子節點,該節點稱為它們的父節點,同一節點的各個子節點之間稱為兄弟節點。一棵樹的根節點沒有父節點,葉節點沒有子節點。
  • 一個節點系列k1,k2, ……,ki,ki+1, ……,kj,並滿足ki是ki+1的父節點,就稱為一條從k1到kj的路徑,路徑的長度為j-1,即路徑中的邊數。路徑中前面的節點是后面節點的祖先,后面節點是前面節點的子孫。
  • 節點的層數等於父節點的層數加一,根節點的層數定義為一。樹中節點層數的最大值稱為該樹的高度或深度。
  • m(m≥0)棵互不相交的樹的集合稱為森林。樹去掉根節點就成為森林,森林加上一個新的根節點就成為樹。

二叉樹

定義與特征

1.定義:二叉樹(Binary Tree)是n(n≥0)個節點的有限集合,它或者是空集(n=0),或者是由一個根節點以及兩棵互不相交的、分別稱為左子樹和右子樹的二叉樹組成。二叉樹與普通有序樹不同,二叉樹嚴格區分左孩子和右孩子,即使只有一個子節點也要區分左右。

2.二叉樹的特征

  • 二叉樹第i(i≥1)層上的節點最多為2^{i-1}2i1個。
  • 深度為k(k≥1)的二叉樹最多有2^k-12k1個節點。
  • 在任意一棵二叉樹中,樹葉的數目比度數為2的節點的數目多一。
  • 滿二叉樹 :深度為k(k≥1)時有2^k-12k1個節點的二叉樹。
  • 完全二叉樹 :只有最下面兩層有度數小於2的節點,且最下面一層的葉節點集中在最左邊的若干位置上。

二叉樹的遍歷

遍歷 :沿某條搜索路徑周游二叉樹,對樹中的每一個節點訪問一次且僅訪問一次。

先序遍歷: 先訪問樹根,再訪問左子樹,最后訪問右子樹;
中序遍歷: 先訪問左子樹,再訪問樹根,最后訪問右子樹;
后序遍歷: 先訪問左子樹,再訪問右子樹,最后訪問樹根;
層次遍歷: 從根節點開始,逐層從左向右進行遍歷。

遞歸思想和實踐

1.什么是遞歸?

所謂遞歸函數是指一個函數的函數體中直接調用或間接調用了該函數自身的函數。這里的直接調用是指一個函數的函數體中含有調用自身的語句,間接調用是指一個函數在函數體里有調用了其它函數,而其它函數又反過來調用了該函數的情況。

2.遞歸函數調用的執行過程分為兩個階段

遞推階段:從原問題出發,按遞歸公式遞推從未知到已知,最終達到遞歸終止條件。
回歸階段:按遞歸終止條件求出結果,逆向逐步代入遞歸公式,回歸到原問題求解。

3.優點與缺點

優點:遞歸可以把問題簡單化,讓思路更為清晰,代碼更簡潔
缺點:遞歸因系統環境影響大,當遞歸深度太大時,可能會得到不可預知的結果

# 求n的階乘
def recursion(n):
  # 遞歸終止條件
  if n < 1:
    return 1
  return n * recursion(n - 1)

print("n!=",recursion(5))

二叉樹的代碼實現

二叉樹順序存儲

二叉樹本身是一種遞歸結構,可以使用Python list 進行存儲。但是如果二叉樹的結構比較稀疏的話浪費的空間是比較多的。

  • 空結點用None表示
  • 非空二叉樹用包含三個元素的列表[d,l,r]表示,其中d表示根結點,l,r左子樹和右子樹。
 1 ['A',['B',None,None
 2      ],
 3      ['C',['D',['F',None,None],
 4                ['G',None,None],
 5           ],     
 6           ['E',['H',None,None],
 7                ['I',None,None],
 8           ],
 9      ]
10 ]
順序存儲代碼
 1 bitree.py 二叉樹的實現
 2 
 3 思路分析: 
 4 1. 使用鏈式存儲
 5   節點類設計上有兩個屬性變量引用左孩子和右孩子
 6 2. 操作類完成二叉樹的遍歷
 7 """
 8 from day2.squeue import SQueue
 9 
10 # 二叉樹節點
11 class TreeNode:
12   def __init__(self, data=None, left=None, right=None):
13     self.data = data
14     self.left = left
15     self.right = right
16 
17 #  二叉樹操作
18 class Bitree:
19   def __init__(self, root=None):
20     self.root = root  # 獲取樹根
21 
22   # 先序遍歷
23   def preOrder(self,node):
24     if node is None:
25       return
26     print(node.data,end=' ')
27     self.preOrder(node.left)
28     self.preOrder(node.right)
29 
30   #  中序遍歷
31   def inOrder(self, node):
32     if node is None:
33       return
34     self.inOrder(node.left)
35     print(node.data, end=' ')
36     self.inOrder(node.right)
37 
38   #  后序遍歷
39   def postOrder(self, node):
40     if node is None:
41       return
42     self.postOrder(node.left)
43     self.postOrder(node.right)
44     print(node.data, end=' ')
45 
46   # 層次遍歷
47   def levelOrder(self,node):
48     sq = SQueue()
49     sq.enqueue(node) # 從node遍歷
50     while not sq.is_empty():
51       node = sq.dequeue() # 出隊一個
52       print(node.data,end=' ') # 遍歷數據
53       if node.left:
54         sq.enqueue(node.left)
55       if node.right:
56         sq.enqueue(node.right)
57 
58 if __name__ == "__main__":
59   #  后序遍歷 BFGDIHECA
60   # 構建樹 (筆記中)
61   b = TreeNode('B')
62   f = TreeNode('F')
63   g = TreeNode('G')
64   d = TreeNode('D', f, g)
65   i = TreeNode('I')
66   h = TreeNode('H')
67   e = TreeNode('E', i, h)
68   c = TreeNode('C', d, e)
69   a = TreeNode('A', b, c)  # 樹根
70 
71   #  初始化樹對象,得到樹根
72   bt = Bitree(a)
73   # 先序
74   bt.preOrder(bt.root)
75   print()
76   #  中序
77   bt.inOrder(bt.root)
78   print()
79   bt.postOrder(bt.root)
80   print()
81   bt.levelOrder(bt.root)
82   print()
鏈式存儲代碼

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM