几种常见的树:排序二叉树、平衡二叉树、红黑树、B+树
一、排序二叉樹(Binary Sort Tree,BST樹)
二叉排序樹,又叫二叉搜索樹、有序二叉樹(ordered binary tree)或排序二叉樹(sorted binary tree)。
1.BST樹的特點
排序二叉樹要么是一棵空二叉樹,要么是具有下列性質的二叉樹:
若它的左子樹不空,則左子樹上所有節點的值均小于它的根節點的值;
若它的右子樹不空,則右子樹上所有節點的值均大于它的根節點的值;
它的左、右子樹也分別為排序二叉樹。
沒有鍵值相等的節點。
由排序二叉樹的特點,我們很容易得出這樣的結論:按中序遍歷排序二叉樹可以得到由小到大的有序序列。排序二叉樹要求所有的元素都能夠排序,也就是鍵要實現comparable接口。
2.BST樹的缺點
排序二叉樹雖然可以快速檢索,但出現最壞的情況——如果插入的節點集本身就是有序的(從小到大排列或從大到小排列),在這種情況下,排序二叉樹就退化成了普通鏈表,其檢索效率就會很差。
二、平衡樹
為了保證不退化成線性查找,就要維持樹的平衡。這個平衡條件要容易保持,從而保證樹的深度為O(logN),很容易想到兩種平衡條件:
最簡單的是要求左右子樹具有相同的高度。
另一種是要求每個節點都必須有相同高度的左子樹和右子樹。
然而,這兩種要求都太嚴格而難以使用。
1.AVL樹(Adelson-Velskii 和 Laandis)
AVL樹得名于它的發明者 G.M. Adelson-Velsky 和 E.M. Landis,是最早被發明的一種平衡樹。平衡二叉樹本質上還是一顆二叉查找樹,只是帶上了平衡條件。
一棵平衡二叉樹是每個節點的左子樹和右子樹的高度最多差1的二叉查找樹。
平衡二叉樹是帶有平衡條件的二叉查找樹
平衡二叉樹的每個節點的左子樹和右子樹的高度最多差1
1.1AVL樹的特點
AVL樹中的每個節點的左子樹和右子樹的高度差不會大于1。在插入時,檢查新節點的插入點所在的最低子樹的根。如果它的子節點的高度相差大于1,則會破壞原有的平衡性,因此需要進行旋轉操作以達到再次平衡,此時會執行一次或兩次旋轉使他們的高度相等。然后算法向上移動,檢查上面的節點,必要時均衡高度。這個檢測檢查所有路徑一直向上,直到根為止。
1.2.AVL樹的缺點
由于插入(或刪除)一個節點時需要掃描兩趟樹,一次向下查找插入點,一次向上平衡樹,所以AVL樹不如下面介紹的紅黑樹效率高,也不如紅黑樹常用。
(也就是說為了保持平衡,平衡二叉樹定義節點的左子樹和右子樹的高度差不大于1,這種規定過于嚴格,導致在做插入或刪除操作時需要自底向上逐層檢查節點的平衡性(高度差),因此效率較低)
2.紅黑樹(Red-Black Tree)
紅黑樹是二叉搜索樹的一種改進,是另一種平衡樹。我們知道二叉搜索樹在最壞的情況下退化成了一個鏈表,而紅黑樹在每一次插入或刪除節點之后都會花O(log N)的時間來對樹的結構作修改,以保持樹的平衡。也就是說,紅黑樹的查找方法與二叉搜索樹完全一樣;插入和刪除節點的方法前半部分與二叉搜索樹完全一樣,而后半部分添加了一些修改樹的結構的操作。
紅黑樹的定義:
每個節點是紅色或者黑色
根節點是黑色
每個葉子節點都是黑色的(這里的葉子節點指的并非指6,11,15,22,27這樣的節點,而是圖中的NIL節點,表示這是樹的尾端。)
對于任意的一個節點,其到尾端節點(NIL)的路徑都包含了相同數目的黑節點。
參考:一步一圖一代碼,一定要讓你真正徹底明白紅黑樹
三、平衡多路查找樹
前面講的BST、AVL、紅黑樹都是典型的二叉查找樹結構,其查找的時間復雜度與樹高相關。那么降低樹高自然對查找效率是有所幫助的。另外還有一個比較實際的問題:就是在大量數據存儲中實現查詢的場景下,平衡二叉樹由于樹深度過大而造成磁盤IO讀寫過于頻繁,進而導致效率低下。那么如何減少樹的深度(當然不能減少查詢數據量),一個基本的想法就是:
①.每個節點存儲多個元素(但元素數量不能無限多,否則查找就退化成了節點內部的線性查找了)。
②.摒棄二叉樹結構而采用多分支(多叉)樹(由于節點內元素數量不能無限多,自然子樹的數量也就不會無限多了)。
這樣我們就提出了一個新的查找樹結構 ——多路查找樹。 根據AVL給我們的啟發,一顆平衡多路查找樹(B樹)自然可以使得數據的查找效率保證在O(logN)這樣的對數級別上。
1.B-樹 (B樹,平衡多路查找樹)
可參考:《算法導論》第18章B樹
注意,這里的B-Tree中的減號只是分隔符,我們通常在書或博客中見到的B-Tree或者B~Tree實際上指的都是B樹。
B樹是為磁盤或其他直接存儲的輔助設備而設計的一種平衡搜索樹。B樹類似于紅黑樹,但它們在降低磁盤I/O操作次數方面要更好一些。許多數據庫使用B樹或B樹的變種來存儲信息。B樹與紅黑樹不同之處在于B樹的節點可以有多個孩子。B樹類似于紅黑樹,就是含有n個節點的B樹的高度為O(lgn)。
1.1B樹的定義
一棵m階的B-Tree有如下特性:
1. 每個節點最多有m個孩子。
2. 除了根節點和葉子節點外,其它每個節點至少有Ceil(m/2)個孩子。
3. 若根節點不是葉子節點,則至少有2個孩子
4. 所有葉子節點都在同一層,且不包含其它關鍵字信息
5. 每個非終端節點包含n個關鍵字信息(P0,P1,…Pn, k1,…kn)
6. 關鍵字的個數n滿足:ceil(m/2)-1 <= n <= m-1
7. ki(i=1,…n)為關鍵字,且關鍵字升序排序。
8. Pi(i=1,…n)為指向子樹根節點的指針。P(i-1)指向的子樹的所有節點關鍵字均小于ki,但都大于k(i-1)
1.2B樹的結構
B-Tree中的每個節點根據實際情況可以包含大量的關鍵字信息和分支,如下圖所示為一個3階的B-Tree:
每個節點占用一個盤塊的磁盤空間,一個節點上有兩個升序排序的關鍵字和三個指向子樹根節點的指針,指針存儲的是子節點所在磁盤塊的地址。兩個關鍵詞劃分成的三個范圍域對應三個指針指向的子樹的數據的范圍域。以根節點為例,關鍵字為17和35,P1指針指向的子樹的數據范圍為小于17,P2指針指向的子樹的數據范圍為17~35,P3指針指向的子樹的數據范圍為大于35。
1.3B樹的查找過程
查找關鍵字29的過程:
根據根節點找到磁盤塊1,讀入內存。【磁盤I/O操作第1次】
比較關鍵字29在區間(17,35),找到磁盤塊1的指針P2。
根據P2指針找到磁盤塊3,讀入內存。【磁盤I/O操作第2次】
比較關鍵字29在區間(26,30),找到磁盤塊3的指針P2。
根據P2指針找到磁盤塊8,讀入內存。【磁盤I/O操作第3次】
在磁盤塊8中的關鍵字列表中找到關鍵字29。
由于節點內部的關鍵字是有序的,所以在節點內部的查找可以使用二分法進行。
分析上面過程,發現需要3次磁盤I/O操作,和3次內存查找操作。由于內存中的關鍵字是一個有序表結構,可以利用二分法查找提高效率。而3次磁盤I/O操作是影響整個B-Tree查找效率的決定因素。B-Tree相對于AVLTree縮減了節點個數,使每次磁盤I/O取到內存的數據都發揮了作用,從而提高了查詢效率。
2.B+樹
B+樹是B樹的一種變種和優化,使其更適合實現外存儲索引結構,InnoDB存儲引擎就是用B+Tree實現其索引結構。B+樹的特點是能夠保持數據穩定有序,其插入與修改擁有較穩定的對數時間復雜度。B+樹元素自底向上插入,這與二叉樹恰好相反。
從上面的B-Tree結構圖中可以看到每個節點中不僅包含數據的key值,還有data值。而每一個頁的存儲空間是有限的,如果data數據較大時將會導致每個節點(即一個頁)能存儲的key的數量很小,當存儲的數據量很大時同樣會導致B-Tree的深度較大,增大查詢時的磁盤I/O次數,進而影響查詢效率。在B+Tree中,所有數據記錄節點都是按照鍵值大小順序存放在同一層的葉子節點上,而非葉子節點上只存儲key值信息,這樣可以大大加大每個節點存儲的key值數量,降低B+Tree的高度。
B+Tree相對于B-Tree的不同點:
①節點存儲的信息不同:
B+樹的分支結點僅僅存儲著關鍵字信息和兒子的指針(這里的指針指的是磁盤塊的偏移量),也就是說內部結點僅僅包含著索引信息。
B樹的節點存儲了索引信息和數據。
②數據存儲的位置不同:
B+樹中的數據都存儲在葉子結點上,也就是其所有葉子結點的數據組合起來就是完整的數據。但B樹的數據存儲在每一個結點中,并不僅僅存儲在葉子結點上。
③查找路徑不同:
B+樹的所有葉子節點都通過指針相連,每次查找都通過內部節點找到對應的葉子節點,從而獲取到數據。順序查找和區間查找也是這樣,從內部節點定位到葉子節點,再在葉子節點中順序查找。
B樹則是每個節點都帶有數據,找到了即停止查找,可能在內部節點中找到,也可能在葉子節點中找到。而區間查找則需要在上下層中不停的穿梭。
④另外:
B樹在內部節點出現的索引項不會再出現在葉子節點中。(???待確定)
將上一節中的B樹優化,由于B+Tree的非葉子節點只存儲鍵值信息,假設每個磁盤塊能存儲4個鍵值及指針信息,則變成B+Tree后其結構如下圖所示:
通常在B+Tree上有兩個頭指針,一個指向根節點,另一個指向關鍵字最小的葉子節點,而且所有葉子節點(即數據節點)之間是一種鏈式環結構。因此可以對B+Tree進行兩種查找運算:一種是對于主鍵的范圍查找和分頁查找,另一種是從根節點開始,進行隨機查找。
Mysql索引中B+樹通的高度通常為2~4層,那么這是為什么呢?
InnoDB存儲引擎中頁的大小為16KB,一般表的主鍵類型為INT(占用4個字節)或BIGINT(占用8個字節),指針類型也一般為4或8個字節,也就是說一個頁(B+Tree中的一個節點)中大概存儲16KB/(8B+8B)=1K個鍵值(因為是估值,為方便計算,這里的K取值為〖10〗^3)。也就是說一個深度為3的B+Tree索引可以維護10^3 * 10^3 * 10^3 = 10億 條記錄。實際情況中每個節點可能不會填充滿,因此在數據庫中,B+Tree的高度一般都在2~4層。
MySQL的InnoDB存儲引擎在設計時是將根節點常駐內存的(少了一次磁盤IO),也就是說查找某一鍵值的行記錄時最多只需要1~3次磁盤I/O操作。所以B+樹適合用來實現文件索引。
3.B*樹
B*樹是B+樹的變體,在B+Tree的非根和非葉子結點再增加指向兄弟的指針;
參考:
一步步分析為什么B+樹適合作為索引的結構
Mysql索引分析
總結
以上是生活随笔為你收集整理的几种常见的树:排序二叉树、平衡二叉树、红黑树、B+树的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 归心似箭,IT达人分享抢票攻略
- 下一篇: 【数学建模】—优秀论文(一)