關於Java的二叉樹、紅黑樹、B+樹詳解

數組和鏈表是常用的數據結構,數組雖然查找快(有序數組可以通過二分法查找),但是插入和刪除是比較慢的;而鏈表,插入和刪除很快(隻需要改變一些引用值),但是查找就很慢,需要從頭開始遍歷; 那麼有沒有一種數據結構能同時具備數組查找快的優點以及鏈表插入和刪除快的優點呢,那就是接下來要介紹的——樹。

1、二叉查找樹

特性:

  • 1、左子樹上所有節點的值均小於它的根節點的值;
  • 2、右子樹上所有節點的值均大於它的根節點的值;
  • 3、左、右子樹也分別為二叉排序樹。

2、平衡二叉查找樹

特性:

  • 1、在二叉樹的基礎上,要求兩個子樹的高度差不能超過1;
  • 2、每次增刪都會通過一次或多次旋轉來平衡二叉樹;

調整平衡的基本思想:

當在二叉排序樹中插入一個節點時,首先檢查是否因插入而破壞瞭平衡,若破壞,則找出其中的最小不平衡二叉樹,在保持二叉排序樹特性的情況下,調整最小不平衡子樹中節點之間的關系,以達到新的平衡。 所謂最小不平衡子樹,指離插入節點最近且以平衡因子的絕對值大於1的節點作為根的子樹。

先插入指定節點,記錄下當前節點的信息,LH,EH或者RH。

  • 若左子樹高LH,查看其左子樹根節點的信息,若是LH,則一次右旋;若是RH,則一次左旋+一次右旋
  • 若右子樹高RH,查看右子樹根節點的信息,若是RH,則一次左旋;若是LH,則一次右旋+一次左旋
  • 調整改變的節點信息

雖然平衡樹解決瞭二叉查找樹退化為近似鏈表的缺點,能夠把查找時間控制在 O(logn),不過卻不是最佳的,因為平衡樹要求每個節點的左子樹和右子樹的高度差至多等於1,這個要求實在是太嚴瞭,導致每次進行插入/刪除節點的時候,幾乎都會破壞平衡樹的第二個規則,進而我們都需要通過左旋和右旋來進行調整,使之再次成為一顆符合要求的平衡樹,且隨著樹的高度的增加,動態插入和刪除的代價也越來越大,為瞭解決優化插入和刪除性能,紅黑樹出現瞭。

顯然,如果在那種插入、刪除很頻繁的場景中,平衡樹需要頻繁著進行調整,這會使平衡樹的性能大打折扣,為瞭解決這個問題,於是有瞭紅黑樹,紅黑樹具有如下特點:

3、紅黑樹:

特性:

1、根節點是黑色;

2、每個節點或者是黑色,或者是紅色;

3、每個葉子節點是黑色。 [註意:這裡葉子節點,是指為空的葉子節點!;

4、如果一個節點是紅色的,則它的子節點必須是黑色的,也就是說一個紅節點的父節點隻能是黑色

5、從一個節點到該節點的子孫節點的所有路徑上包含相同數目的黑節點,也就是說確保沒有一條路徑會比其他路徑長出倆倍;

紅黑樹(Red Black Tree) 是一種自平衡二叉查找樹 紅黑樹和AVL樹類似,都是在進行插入和刪除操作時通過特定操作保持二叉查找樹的平衡,從而獲得較高的查找性能。 二叉平衡樹的嚴格平衡策略以犧牲建立查找結構(插入,刪除操作)的代價,換來瞭穩定的O(logN) 的查找時間復雜度 它雖然是復雜的,但它的最壞情況運行時間也是非常良好的,並且在實踐中是高效的: 它可以在O(log n)時間內做查找,插入和刪除,這裡的n 是樹中元素的數目。

紅黑樹的操作代價:

  • 查找代價:由於紅黑樹的性質(最長路徑長度不超過最短路徑長度的2倍),可以說明紅黑樹雖然不像平衡二叉查找樹一樣是嚴格平衡的,但平衡性能還是要比二叉查找樹要好。其查找代價基本維持在O(logN)左右,但在最差情況下(最長路徑是最短路徑的2倍少1),比平衡二叉查找樹要略遜色一點。
  • 插入代價:RBT插入結點時,需要旋轉操作和變色操作。但由於隻需要保證RBT基本平衡就可以瞭。因此插入結點最多隻需要2次旋轉,這一點和平衡二叉查找樹的插入操作一樣。雖然變色操作需要O(logN),但是變色操作十分簡單,代價很小。
  • 刪除代價:紅黑樹的刪除操作代價要比平衡二叉查找樹要好的多,刪除一個結點最多隻需要3次旋轉操作。

RBT 效率總結 : 查找效率最好情況下時間復雜度為O(logN),但在最壞情況下比平衡二叉查找樹要差一些,但也遠遠好於二叉查找樹。 插入和刪除操作改變樹的平衡性的概率要遠遠小於AVL(RBT不是高度平衡的)。因此需要的旋轉操作的可能性要小,而且一旦需要旋轉,插入一個結點最多隻需要旋轉2次,刪除最多隻需要旋轉3次(小於AVL的刪除操作所需要的旋轉次數)。雖然變色操作的時間復雜度在O(logN),但是實際上,這種操作由於簡單所需要的代價很小。

紅黑樹能夠以O(log2(N))的時間復雜度進行搜索、插入、刪除操作。此外,任何不平衡都會在3次旋轉之內解決。這一點是平衡二叉查找樹所不具備的。

調整平衡的基本思想:

  • 變色:為瞭重新符合紅黑樹的規則,嘗試把紅色節點變為黑色,或者把黑色節點變為紅色。
  • 左旋轉:逆時針旋轉紅黑樹的兩個節點,使得父節點被自己的右孩子取代,而自己成為自己的左孩子。說起來很怪異,大傢看下圖:

  • 右旋轉:順時針旋轉紅黑樹的兩個節點,使得父節點被自己的左孩子取代,而自己成為自己的右孩子。大傢看下圖:

場景:HashMap TreeSet TreeMap

4、 B樹:

設計緣由:

數據庫索引是存儲在磁盤上的,當數據量比較大的時候,索引的大小可能有十幾個G,甚至更多。當我們利用索引查詢的時候,能把整個索引全部加載到內存嗎?顯然不可能,能做的隻有逐一加載每一個磁盤頁,這裡的磁盤頁對應著索引樹的節點。

如果我們利用二叉查找樹作為索引結構,那麼最壞(每個節點數據在不同磁盤頁上)的情況下,磁盤IO次數等於索引樹的高度。 所以,為瞭減少磁盤IO次數,我們就需要把原本“瘦高”的樹結構變得“矮胖”(節點數變少瞭)。這就是B樹的特征之一

B樹是一種多路平衡查找樹,它的每一個節點最多包含m個孩子,m被稱為B樹的階,m的大小取決於磁盤頁的大小。——一個節點最多包含一個磁盤頁的數據

也就是說,當B樹變得矮胖以後,每個節點可以包含多個數據(數據量大小由磁盤頁的大小決定),同樣的數據,B樹比二叉樹/紅黑樹節點少。所以,B樹在查詢時,磁盤IO次數變少瞭,從而可以提升查找性能。

特征:

一個m階的B樹具有如下幾個特征:

1.根結點至少有兩個子女。
2.每個中間節點都包含k-1個元素和k個孩子,其中 m/2 <= k <= m
3.每一個葉子節點都包含k-1個元素,其中 m/2 <= k <= m
4.所有的葉子結點都位於同一層。
5.每個節點中的元素從小到大排列,節點當中k-1個元素正好是k個孩子包含的元素的值域分劃

場景:

B樹主要應用於文件系統以及部分數據庫索引,比如著名的非關系型數據MongoDB。 而大部分關系型數據庫,比如mysql,則使用B+樹作為索引

5、 B+樹

B+樹是B樹的一種變體,但是又有所不同,

特征:

一個m階的B+樹具有如下幾個特征:

  • 1.有k個子樹的中間節點包含有k個元素(B樹中是k-1個元素),每個元素不保存數據,隻用來索引,所有數據都保存在葉子節點。
  • 2.所有的葉子結點中包含瞭全部元素的信息,及指向含這些元素記錄的指針,且葉子結點本身依關鍵字的大小自小而大順序鏈接。
  • 3.所有的中間節點元素都同時存在於子節點,在子節點元素中是最大(或最小)元素。

這裡特別要註意有兩點:

其一:每個父節點的元素都出現在子節點中,是子節點的最大(或最小)元素;因此所有葉子節點包含瞭全量元素信息;

其二:每個葉子節點都帶有指向下一個節點的指針,形成瞭一個有序鏈表;

其三:隻有葉子節點帶有衛星數據,其餘中間節點僅僅是索引,沒有任何數據關聯,如下圖,所謂衛星數據,指的是索引元素所指向的數據記錄,比如數據庫中的某一行,在B樹種,無論中間節點還是葉子節點都帶有衛星數據。

設計優勢

B+樹的好處主要體現在查詢性能上,由於B+樹的中間節點沒有衛星數據,所以同樣大小的磁盤頁可以容納更多的節點元素,這就意味著,一次性加載到內存中的節點元素更多,從而使得查詢時IO次數也更少。(舉個簡單的例子,一個磁盤頁可以加載B樹的100個節點元素,但是可以加載B+樹的1000個節點元素,那麼對於查找999這個數來說,B數需要10次IO,B+數隻需要1次IO)

B+樹相對B樹的優點:

  • IO一次讀數據是從磁盤上讀的,磁盤容量是固定的,取數據量大小是固定的,非葉子節點不存儲數據,節點小,磁盤IO次數就少。
  • B+樹查詢性能穩定,因為B+樹的查詢必須最終查找到葉子節點; 而B樹,隻要找到匹配元素即可,無論匹配元素處於中間節點,還是葉子節點。所以B樹的查詢性能並不穩定,最好情況是隻查根節點,最壞情況是查到葉子節點
  • B+樹的所有Data域在葉子節點,一般來說都會進行一個優化,就是將所有的葉子節點用指針串聯起來(可以認為是鏈表),遍歷葉子節點就能獲取全部數據,這樣就能進行區間訪問瞭。 B樹做范圍查詢,隻能繁瑣的遍歷,但是B+樹,隻需要查到查找到范圍下限以後,遍歷葉子節點(有序鏈表)就可以瞭。

綜合起來,B+樹比B樹的優勢有三個:1、IO次數更少;2、查詢性能更佳;3、范圍查詢簡便

場景:Mysql索引

6、紅黑樹 VS B+樹

紅黑樹的深度比B+樹大,當數據量小時,可以把數據完全放到內存中,紅黑樹的時間復雜度比B樹低(不用每次都查到葉子節點),如linux中進程的調度用的是紅黑樹,Java中HashMap、TreeMap、TreeSet(都在內存中操作)也都是用紅黑樹實現;

但是,當數據量大時,不能一次性把數據放到內存時,紅黑樹往往出現由於樹的深度過大而造成磁盤IO讀寫過於頻繁,進而導致效率低下;而B樹因其讀磁盤次數少,具有更快的速度。

到此這篇關於關於Java的二叉樹、紅黑樹、B+樹詳解的文章就介紹到這瞭,更多相關Java二叉樹、紅黑樹、B+樹內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: