學習筆記——二叉樹(python實現)
樹形結構在資料結構中也是非常重要的一種存在,其特點為非線性,各個節點之間以分支關係相聯絡。
樹(Tree)是個結點的有限集。在任意一棵樹中:
(1)有且僅有一個特定的稱為根(Root)的節點;
(2)當n>1時,其餘節點可分為m(m>0)個互不相交的有限集T_1,T_2,…,T_m,其中每一個集合本身又是一棵樹,並且稱為根的子樹(SubTree)。
有關術語及定義:
(1)結點:包含一個數據元素及若干指向其子樹的分支。
(2)度:節點所擁有的子樹數量。
(3)葉子:度為零的結點。
(4)分支節點:度不為零的結點。
(5)樹的度:度的最大的值。
二叉樹的性質:
性質1)在二叉樹的第i層上至多有2^{i-1}個結點(i\geq 1)。
性質2)深度為k的二叉樹至多有2^{k}-1個結點(k\geq 1)。
性質3)對任何一棵二叉樹,如果其葉子節點數為n_{0},度為2的結點數為n_2,則n_0=n_2+1。
下面介紹完全二叉樹的兩個特性:
性質4)具有n個結點的完全二叉樹的深度為[log_{2}n]+1,其中[x]表示不大於x的最大整數。
性質5)如果對一棵有n個結點的完全二叉樹的結點按層序編號(從第一層到最後一層,每層從左到右),則對任一結點i(1\leq i\leq n),有:
(1)如果i=1,則結點i是二叉樹的根,無雙親;如果i>1,則其雙親結點為[1/2]。
(3)如果2i+1>n,則結點i無右孩子;否則其右孩子是結點2i+1。
介紹完了二叉樹的定義及基本性質,接下來,我們需要了解二叉樹的遍歷。所謂二叉樹的遍歷,指的是如何按某種搜尋路徑巡防樹中的每個結點,使得每個結點均被訪問一次,而且僅被訪問一次。對於二叉樹,常見的遍歷方法有:先序遍歷,中序遍歷,後序遍歷,層序遍歷。這些遍歷方法一般使用遞迴演算法實現。
先序遍歷的操作定義為:若二叉樹為空,為空操作;否則(1)訪問根節點;(2)先序遍歷左子樹;(3)先序遍歷右子樹。
中序遍歷的操作定義為:若二叉樹為空,為空操作;否則(1)中序遍歷左子樹;(2)訪問根結點;(3)中序遍歷右子樹。
層序遍歷的操作定義為:若二叉樹為空,則None;否則從上到下、從左到右按層次進行訪問。
基礎原理就說到這,接下來看一下在電腦中如何實現呢?
(1)建立:個人認為在python中初始化資料結構都十分簡單,更是大同小異,通過上述分析可以知道對於一個樹來說,它需要定義資料節點,左子樹和右子樹。
(2)先序遍歷:首先看其資料域是否為空,若不是空則輸出其值,接下來依次判斷其左子樹,右子樹是否為空,若不是空則再次呼叫此函式(遞迴實現)。
(3)中序遍歷:思路和先序遍歷的實現是一樣的。不過順序有所改變:首先看其左子樹是否為空,若不是空則向下執行,判斷其資料域是否為空,不為空則輸出其資料,最後判斷右子樹是否為空,若不是空則再次呼叫此函式(遞迴實現)。
(4)後序遍歷:和上述過程一樣,不過將其變成了左右根。
(5)樹的高度:可以分為五種情況:
(1).data為空:則直接返回0(空樹)
(2)左子樹,右子樹為空:返回1
(3)左子樹為空,右子樹不為空:返回1+右子樹高度(將右子樹結點遞迴呼叫height()方法
(4)右子樹為空,左子樹不為空:返回1+左子樹高度(將左子樹結點遞迴呼叫height()方法
(5)左右子樹都不為空:則為1+max(左子樹高度,右子樹高度)
(6)層次遍歷:首先建立列表,如果data域不為空就將其加到列表中然後判斷樹高。當其大於等於1時,運用for迴圈將節點返回(注意不是直接將資料返回,所以對每個層還要在建立一個列表,用來返回該層的節點),具體返回過程如下:依次判斷該層的上一個節點的左孩子和右孩子(一定是上一層的左孩子和右孩子這樣才能保證所返回的為該層的值)是否為空,不為空則返回。最後如此列表不為空,將其新增到最初定義的列表當中。當返回層次列表時運用雙層迴圈巢狀,外層迴圈條件為0~height即層數,內層為上述過程中所求得的列表長度,得到其資料值(此返回操作,是因為上述返回的是節點而不是資料,此過程把資料返回確保遍歷的實現)
(7)葉子結點:依舊可以分為五種情況
(1).data為空:則直接返回None(空樹)
(2)左子樹,右子樹為空:返回data
(3)左子樹為空,右子樹不為空:直接對右子樹結點遞迴呼叫leaves()方法
(4)右子樹為空,左子樹不為空:直接對左子樹結點遞迴呼叫leaves()方法
(5)左右子樹都不為空:分別對左,右子樹結點遞迴呼叫leaves()方法
程式碼段:
import uuid
from random import sample
# 二叉樹類
class BTree(object):
# 初始化
def __init__(self, data=None, left=None, right=None):
self.data = data # 資料域
self.left = left # 左子樹
self.right = right # 右子樹
# 前序遍歷
def preorder(self):
if self.data is not None:
print(self.data, end=' ')
if self.left is not None:
self.left.preorder()
if self.right is not None:
self.right.preorder()
# 中序遍歷
def inorder(self):
if self.left is not None:
self.left.inorder()
if self.data is not None:
print(self.data, end=' ')
if self.right is not None:
self.right.inorder()
# 後序遍歷
def postorder(self):
if self.left is not None:
self.left.postorder()
if self.right is not None:
self.right.postorder()
if self.data is not None:
print(self.data, end=' ')
# 層序遍歷
def levelorder(self):
# 層序遍歷列表
level_order = []
# 是否新增根節點中的資料
if self.data is not None:
level_order.append([self])
# 二叉樹的高度
height = self.height()
# 返回某個節點的左孩子
def LChild_Of_Node(node):
return node.left if node.left is not None else None
# 返回某個節點的右孩子
def RChild_Of_Node(node):
return node.right if node.right is not None else None
if height >= 1:
# 對第二層及其以後的層數進行操作, 在level_order中新增節點而不是資料
for _ in range(2, height + 1):
level = [] # 該層的節點
for node in level_order[-1]:
# 如果左孩子非空,則新增左孩子
if LChild_Of_Node(node):
level.append(LChild_Of_Node(node))
# 如果右孩子非空,則新增右孩子
if RChild_Of_Node(node):
level.append(RChild_Of_Node(node))
# 如果該層非空,則新增該層
if level:
level_order.append(level)
# 取出每層中的資料
for i in range(0, height): # 層數
for index in range(len(level_order[i])):
level_order[i][index] = level_order[i][index].data
return level_order
# 二叉樹的高度
def height(self):
# 空的樹高度為0, 只有root節點的樹高度為1
if self.data is None:
return 0
elif self.left is None and self.right is None:
return 1
elif self.left is None and self.right is not None:
return 1 + self.right.height()
elif self.left is not None and self.right is None:
return 1 + self.left.height()
else:
return 1 + max(self.left.height(), self.right.height())
# 二叉樹的葉子節點
def leaves(self):
if self.data is None:
return None
elif self.left is None and self.right is None:
print(self.data, end=' ')
elif self.left is None and self.right is not None:
self.right.leaves()
elif self.right is None and self.left is not None:
self.left.leaves()
else:
self.left.leaves()
self.right.leaves()
#外部檔案保證實現
from Binary_Tree import BTree
# 構造二叉樹, BOTTOM-UP METHOD
right_tree = BTree(6)
right_tree.left = BTree(2)
right_tree.right = BTree(4)
left_tree = BTree(5)
left_tree.left = BTree(1)
left_tree.right = BTree(3)
tree = BTree(11)
tree.left = left_tree
tree.right = right_tree
left_tree = BTree(7)
left_tree.left = BTree(3)
left_tree.right = BTree(4)
right_tree = tree # 增加新的變數
tree = BTree(18)
tree.left = left_tree
tree.right = right_tree
print('先序遍歷為:')
tree.preorder()
print()
print('中序遍歷為:')
tree.inorder()
print()
print('後序遍歷為:')
tree.postorder()
print()
print('層序遍歷為:')
level_order = tree.levelorder()
print(level_order)
print()
height = tree.height()
print('樹的高度為%s.' % height)
print('葉子節點為:')
tree.leaves()
print()
注:該文章參考於https://www.jianshu.com/p/9503238394df