在瞭解二叉樹以前,首先咱們得有樹的概念。java
樹是一種數據結構又可稱爲樹狀圖,如文檔的目錄、HTML的文檔樹都是樹結構,它是由n(n>=1)個有限節點組成一個具備層次關係的集合。把它叫作「樹」是由於它看起來像一棵倒掛的樹,也就是說它是根朝上,而葉朝下的。它具備如下的特色:node
有關樹的一些相關術語:算法
樹的種類有:無序樹、有序樹、二叉樹、霍夫曼樹。其中最重要應用最多的就是二叉樹,下面咱們來學習有關二叉樹的知識。數據庫
二叉樹的定義爲度不超過2的樹,即每一個節點最多有兩個叉(兩個分支)。上面那個例圖其實就是一顆二叉樹。數據結構
二叉樹有兩個特殊的形態:滿二叉樹和徹底二叉樹app
滿二叉樹ide
一個二叉樹,若是除了葉子節點外每個層的結點數都達到最大值,則這個二叉樹就是滿二叉樹。post
徹底二叉樹學習
葉節點只能出如今最下層和次下層,而且最下面一層的結點都集中在該層最左邊的若干位置的二叉樹爲徹底二叉樹。即右邊的最下層和次下層能夠適當缺一個右子數spa
徹底二叉樹是效率很高的數據結構
二叉樹的遍歷
二叉樹的鏈式存儲:將二叉樹的節點定義爲一個對象,節點之間經過相似鏈表的連接方式來鏈接。
二叉樹結點的定義
#二叉樹結點的定義 class BiTreeNode: def __init__(self, data): self.data = data self.lchild = None self.rchild = None
二叉樹的遍歷分爲四種——前序遍歷、中序遍歷、後序遍歷和層級遍歷
設樹結構爲:
四種遍歷方法的代碼實現:
from collections import deque #結點的定義 class BiTreeNode: def __init__(self, data): self.data = data self.lchild = None self.rchild = None #二叉樹結點 a = BiTreeNode('A') b = BiTreeNode('B') c = BiTreeNode('C') d = BiTreeNode('D') e = BiTreeNode('E') f = BiTreeNode('F') g = BiTreeNode('G') #結點之間的關係 e.lchild = a e.rchild = g a.rchild = c c.lchild = b c.rchild = d g.rchild = f root = e #前序遍歷:先打印根,再遞歸左孩子,後遞歸右孩子 def pre_order(root): if root: print(root.data, end='') pre_order(root.lchild) pre_order(root.rchild) #中序遍歷:以根爲中心,左邊打印左子樹,右邊打印右子樹(注意,每一個子樹也有相應的根和子樹) #(ACBD) E (GF)-->(A(CBD)) E (GF)-->(A (B C D)) E (G F) def in_order(root): if root: in_order(root.lchild) print(root.data, end='') in_order(root.rchild) #後序遍歷:先遞歸左子樹,再遞歸右子數,後打印根(注意,每一個子樹也有相應的根和子樹) # (ABCD)(GF)E-->((BCD)A)(GF)E-->(BDCA)(FG)E def post_order(root): if root: post_order(root.lchild) post_order(root.rchild) print(root.data, end='') #層次遍歷:一層一層來,同一層的從左到右輸出 def level_order(root): queue = deque() queue.append(root) while len(queue) > 0: node = queue.popleft() print(node.data,end='') if node.lchild: queue.append(node.lchild) if node.rchild: queue.append(node.rchild) pre_order(root)#EACBDGF print("") in_order(root)#ABCDEGF print("") post_order(root)#BDCAFGE print("") level_order(root)#EAGCFBD
二叉搜索樹
二叉搜索樹(Binary Search Tree),它或者是一棵空樹,或者是具備下列性質的二叉樹: 若它的左子樹不空,則左子樹上全部結點的值均小於它的根結點的值; 若它的右子樹不空,則右子樹上全部結點的值均大於它的根結點的值; 它的左、右子樹也分別爲二叉搜索樹。
二叉搜索樹一個很好玩的網址,集成了增刪改的功能:https://visualgo.net/en/bst
二叉搜索樹的中序遍歷獲得的是原來列表按升序排序的列表
由列表生成二叉搜索樹、經過二叉搜索樹查詢值和刪除值的示例代碼:
#結點定義 class BiTreeNode: def __init__(self, data): self.data = data self.lchild = None self.rchild = None #創建二叉搜索樹(循環列表,插入值) class BST: def __init__(self, li=None): self.root = None if li: self.root = self.insert(self.root, li[0])#列表的第一個元素是根 for val in li[1:]: self.insert(self.root, val) #生成二叉搜索樹遞歸版本 def insert(self, root, val): if root is None: root = BiTreeNode(val) elif val < root.data:#插入的值小於root,要放到左子樹中(遞歸查詢插入的位置) root.lchild = self.insert(root.lchild, val) else:#插入的值大於root,要放到右子樹中(遞歸查詢插入的位置) root.rchild = self.insert(root.rchild, val) return root #生成二叉搜索樹不遞歸的版本 def insert_no_rec(self, val): p = self.root if not p: self.root = BiTreeNode(val) return while True: if val < p.data: if p.lchild: p = p.lchild else: p.lchild = BiTreeNode(val) break else: if p.rchild: p = p.rchild else: p.rchild = BiTreeNode(val) break #查詢遞歸版本 def query(self, root, val): if not root: return False if root.data == val: return True elif root.data > val: return self.query(root.lchild, val) else: return self.query(root.rchild, val) #查詢非遞歸版本 def query_no_rec(self, val): p = self.root while p: if p.data == val: return True elif p.data > val: p = p.lchild else: p = p.rchild return False #中序遍歷,獲得的是升序的列表 def in_order(self, root): if root: self.in_order(root.lchild) print(root.data, end=',') self.in_order(root.rchild) tree = BST() for i in [1,5,9,8,7,6,4,3,2]: tree.insert_no_rec(i) tree.in_order(tree.root) #print(tree.query_no_rec(12))
二叉搜索樹的應用——AVL樹、B樹、B+樹
AVL樹
AVL樹:AVL樹是一棵自平衡的二叉搜索樹。
AVL樹具備如下性質: 根的左右子樹的高度之差的絕對值不能超過1 根的左右子樹都是平衡二叉樹
AVL的實現方式:旋轉
B樹
B樹是一棵自平衡的多路搜索樹。經常使用於數據庫的索引。
在B-樹中查找給定關鍵字的方法是,首先把根結點取來,在根結點所包含的關鍵字K1,…,Kn查找給定的關鍵字(可用順序查找或二分查找法),若找到等於給定值的關鍵字,則查找成功;不然,必定能夠肯定要查找的關鍵字在Ki與Ki+1之間,Pi爲指向子樹根節點的指針,此時取指針Pi所指的結點繼續查找,直至找到,或指針Pi爲空時查找失敗。
B+ 樹
B+樹的查找
1
2
3
4
5
6
7
8
9
10
|
Function: search (k)
return
tree_search (k, root); Function: tree_search (k, node)
if
node is a leaf then
return
node;
switch
k
do
case
k < k_0
return
tree_search(k, p_0);
case
k_i ≤ k < k_{i+
1
}
return
tree_search(k, p_{i+
1
});
case
k_d ≤ k
return
tree_search(k, p_{d+
1
});
//僞代碼假設沒有重複值
|
B+樹的插入
B+樹的刪除