目錄
樹和前面所講的表、堆棧和隊列等這些線性數據結構不同,樹不是線性的。在處理較多數據時,使用線性結構較慢,而使用樹結構則可以提高處理速度。不過,相對於線性的表、堆棧和隊列等線性數據結構來說,樹的構建便顯得複雜了。
一、樹
樹是一種非線性的數據結構,如圖-1 所示,之所以稱之爲樹,是因爲其形狀像一棵倒置的樹。每顆樹都有一個根節點,如圖-1 所示的樹中,Root 爲根節點。A、B、C 爲 Root 的兒子,Root 爲 A、B、C 的父親。A、B、C 爲兄弟。同樣,A 爲 D、E 的父親,D、E 爲 A 的兒子,D、E爲兄弟。D、E爲 Root 的孫子,Root 爲 D、E 的祖父。在樹中,如果一個元素沒有兒子,則稱之爲樹的葉子。
在 Python 中,樹的實現可以使用列表或者類的方式。使用列表的方式較爲簡便,但樹的構建過程較爲複雜。使用類的方式構建樹時,需要首先確定樹中的節點所能擁有的最大兒子數。因爲每個節點所擁有的兒子數量並不一定相同,因此使用類的方法將佔用更大的存儲空間。
如下所示的 pytree.py 腳本,以列表的形式構建了圖-1所示的樹。
# -*- coding:UTF-8 -*-
# file: pytree.py
G = ['G', []] # 構造葉子 G,樹中每個元素都由該元素的值和該元素的兒子列表組成
H = ['H', []] # 構造葉子 H
I = ['I', []] # 構造葉子 I
K = ['K', []] # 構造葉子 K
E = ['E', [G, H, I, K]] # 構造 E 節點
D = ['D', []] # 構造葉子 D
F = ['F', []] # 構造葉子 F
A = ['A', [D, E]] # 構造 A 節點
B = ['B', []] # 構造葉子 B
C = ['C', [F]] # 構造 C 節點
Root = ['Root', [A, B, C]] # 構造樹根
print(Root)
輸出結果:
C:\Users\圖圖\AppData\Local\Programs\Python\Python37-32\python.exe D:/Python/pytree.py
['Root',
[['A', [['D', []], ['E', [['G', []], ['H', []], ['I', []], ['K', []]]]]],
['B', []],
['C', [['F', []]]]
]]
Process finished with exit code 0
二、二叉樹
二叉樹是一類比較特殊的樹,在二叉樹中每個節點最多隻有兩個兒子,分爲左和右,如圖-2 所示。相對於樹而言,二叉樹的構建和使用都要簡單得多。
任何一棵樹,都可以通過變換轉換成一棵二叉樹。
在 Python 中,二叉樹的構建和樹一樣,可以使用列表或者類的方式。由於二叉樹中的節點具有確定的兒子數,因此,使用類的方式更爲簡便。下面所示的 pytree.py 用較爲簡單的方式生成了如圖-2所示的樹。
# -*- coding:UTF-8 -*-
# file: pytree.py
class Btree: # 二叉樹節點
def __init__(self, value): # 初始化函數
self.left = None # 左兒子
self.data = value # 節點值
self.right = None # 右兒子
def insertLeft(self, value): # 向左子樹插入節點
self.left = Btree(value)
return self.left
def insertRight(self, value): # 向右子樹插入節點
self.right = Btree(value)
return self.right
def show(self): # 輸出節點數據
print(self.data)
if __name__ == '__main__':
Root = Btree('Root') # 根節點
A = Root.insertLeft('A') # 向根節點中插入 A 節點
C = A.insertLeft('C') # 向 A 節點中插入 C 節點
D = A.insertRight('D') # 向 A 節點中插入 D 節點
F = D.insertLeft('F') # 向 D 節點中插入 F 節點
G = D.insertRight('G') # 向 D 節點中插入 G 節點
B = Root.insertRight('B') # 向根節點中插入 B 節點
E = B.insertRight('E') # 向 B 節點中插入 E 節點
Root.show() # 輸出節點數據
Root.left.show()
Root.right.show()
A = Root.left
A.left.show()
Root.left.right.show()
輸出結果:
當創建好一棵二叉樹後,可以按照一定的順序對樹中所有的元素進行遍歷。按照先左後右,樹的遍歷方法有三種:先序遍歷、中序遍歷和後序遍歷。
先序遍歷的次序——如果二叉樹不爲空,則先訪問根節點,然後訪問左子樹,最後訪問右子樹;否則,程序退出。
中序遍歷的次序——如果二叉樹不爲空,則先訪問左子樹,然後訪問根節點,最後訪問右子樹;否則,程序退出。
後序遍歷的次序——如果二叉樹不爲空,則先訪問左子樹,然後訪問右節點,最後訪問根子樹;否則,程序退出。
下面所示的 TreeTraversal.py 腳本使用了三種遍歷方式遍歷圖-2 所示的樹。
# -*- coding:UTF-8 -*-
# file: TreeTraversal.py
class BTree: # 二叉樹節點
def __init__(self, value): # 初始化函數
self.left = None # 左兒子
self.data = value # 節點值
self.right = None # 右兒子
def insertLeft(self, value): # 向左子樹插入節點
self.left = BTree(value)
return self.left
def insertRight(self, value): # 向右子樹插入節點
self.right = BTree(value)
return self.right
def show(self): # 輸出節點數據
print(self.data)
def preorder(node): # 先序遍歷
if node.data:
node.show()
if node.left:
preorder(node.left)
if node.right:
preorder(node.right)
def inorder(node): # 中序遍歷
if node.data:
if node.left:
inorder(node.left)
node.show()
if node.right:
inorder(node.right)
def postorder(node): # 後序遍歷
if node.data:
if node.left:
postorder(node.left)
if node.right:
postorder(node.right)
node.show()
if __name__ == '__main__':
Root = BTree('Root') # 構建樹
A = Root.insertLeft('A')
C = A.insertLeft('C')
D = A.insertRight('D')
F = D.insertLeft('F')
G = D.insertRight('G')
B = Root.insertRight('B')
E = B.insertRight('E')
print('**************************')
print('Binary Tree Pre-Traversal')
print('**************************')
preorder(Root) # 對樹進行先序遍歷
print('**************************')
print('Binary Tree In-Traversal')
print('**************************')
inorder(Root) # 對樹進行中序遍歷
print('**************************')
print('Binary Tree Post-Traversal')
print('**************************')
postorder(Root) # 對樹進行後序遍歷
運行 TreeTraversal.py 腳本輸出結果:
C:\Users\圖圖\AppData\Local\Programs\Python\Python37-32\python.exe D:/Python/TreeTraversal.py
**************************
Binary Tree Pre-Traversal
**************************
Root
A
C
D
F
G
B
E
**************************
Binary Tree In-Traversal
**************************
C
A
F
D
G
Root
B
E
**************************
Binary Tree Post-Traversal
**************************
C
F
G
D
A
E
B
Root
Process finished with exit code 0