淺析 AVL 樹,紅黑樹,B 樹,B+ 樹

一. AVL 樹

1.出現的原因
二叉搜索樹雖可以縮短查找的效率,但如果數據有序或接近有序,二叉搜索樹將有可能退化爲單支樹,此時查找元素相當於在順序表中查找元素,效率低下,相當於O(n)。

例如:對於同一個關鍵碼集合,如果各關鍵碼插入的次序不同,可能得到不同結構的二叉搜索樹:
在這裏插入圖片描述
最優情況下,二叉搜索樹爲完全二叉樹。
最差情況下,二叉搜索樹退化爲單支樹。


2.定義
AVL 樹是一種二叉平衡搜索樹,在 AVL 樹中,任何節點的兩個子樹的高度之差的絕對值最大爲1,因此也被稱爲二叉平衡搜索樹。但是維護這種高度平衡所付出的代價也是很大的,故而實際應用並不多,因此更多的地方是用追求局部平衡而不是整體平衡的紅黑樹。(AVL 樹的每個節點的左子樹和右子樹之差的絕對值不能超過1,如果插入或者刪除一個節點使得高度之差的絕對值大於1,就要進行節點之間的旋轉,將二叉樹始終維持在一個平衡態。)


3.特徵
● AVL 樹它的任何一個節點的左右子樹都是 AVL 樹
●左右子樹高度之差(簡稱平衡因子)的絕對值不超過1(只能爲-1/0/1)
在這裏插入圖片描述
4.AVL 樹的查找、插入和刪除在平均和最壞情況下都是O(logn)。

5.在 AVL 樹中進行插入或刪除節點後,可能導致 AVL 樹失衡。這種失去平衡的可以概括爲4種姿態:LL(左左),LR(左右),RR(右右)和RL(右左)。

二.紅黑樹

1.特徵

  • 每個結點不是紅色的就是黑色的
  • 根節點是黑色的
  • 如果一個節點是紅色的,則它的相鄰結點必須是是黑色的
  • 對於每個結點,從該結點到其所有後代葉結點的簡單路徑上,均包含相同數目的黑色結點
  • 從根節點到葉子節點的每條路徑中,必須包含相同數目的黑色節點
  • 紅黑樹也是一種二叉搜索樹,但是他不是完全平衡的
  • 每個葉子結點都是黑色的
  • 其最長路徑中節點個數不會超過最短路徑中節點個數的兩倍

如圖:
在這裏插入圖片描述

2.主要用途

  • C++的STL中
  • Linux 進程調度 Completely Fair Scheduler,用紅黑樹管理進程控制塊
  • epoll 在內核中的實現,用紅黑樹管理事件塊
  • nginx 中,用紅黑樹管理 timer 等
  • Java的 TreeMap,TreeSet 實現

3.紅黑樹只追求近似平衡,所以在插入與刪除節點時,翻轉次數遠遠少於 AVL 樹,因此在需要較多插入和刪除操作的場景中,使用紅黑樹更好。同樣也因爲近似平衡,所以在查詢時,紅黑樹查詢的深度可能會大於 AVL 樹,所以在需要較多查詢的場景中,使用 AVL 樹更好。

4.紅黑樹的查找、刪除、添加操作都爲 log(n) 。

三.B樹

B樹 是一種搜索樹,我們知道,這一類樹(比如 AVL 樹,紅黑樹等)最初目的都是爲了解決查找效率低的問題。B樹 也是如此,它最初啓發於二叉搜索樹,二叉搜索樹的特點是:每個非葉節點都只有兩個孩子節點。然而這種做法會導致當數據量非常大時,二叉查找樹的深度過深,搜索算法自根節點向下搜索時,需要訪問的節點也就變的相當多。如果這些節點存儲在外存儲器中,每訪問一個節點,相當於就是進行了一次 I/O 操作(因爲每一層的節點都在一個磁盤上),隨着樹高度的增加,頻繁的 I/O 操作一定會降低查詢的效率,所以 B樹 就被搞出來降低樹的高度,從而減少磁盤的訪問。

1.特徵

  • 任意非葉子節點最多隻有M個孩子
  • 所有葉子節點位於同一層
  • k 個關鍵字把節點拆分成 k+1 段,分別指向 k+1 個孩子,同時滿足搜索樹的大小關係。
  • 根節點至少有兩個孩子
  • 每個節點(非根節點)至少有M/2(上取整)個孩子,至多有M個孩子
  • 每個節點(非根節點)至少有M/2-1(上取整)個關鍵字,至多有M-1個關鍵字,並且以升序排列
  • key[i] 和 key[i+1] 之間的孩子節點的值介於key[i]、key[i+1]之間

2.特性

  • 關鍵字集合分佈在整顆樹中
  • 任何一個關鍵字出現且只出現在一個結點中
  • 搜索有可能在非葉子結點處就結束
  • 其搜索性能等價於在關鍵字全集內做一次二分查找

四.B+樹

B+ 樹通常用於數據庫和操作系統的文件系統中做索引

  • 在所有非葉子節點中,含有 K 個關鍵字的節點有 k 顆子樹,這些關鍵字不保存數據,只用來索引,所有數據都保存在葉子節點中(而 B 樹是每個關鍵字都用來保存數據的)
  • 所有的葉子節點包含了全部關鍵字的信息,及指向含這些關鍵字記錄的指針,且葉子節點本身依關鍵字的大小自小而大順序連接
  • 所有的非葉子節點可以看成索引
  • 通常在 B+ 樹上有兩個頭指針,一個指向根節點,一個指向葉子節點。
  • 同一個關鍵字會在不同節點中重複出現,根節點的最大關鍵字元素就是整個 B+ 樹的最大元素。

1.B+ 樹應用在MyISAM(非聚簇索引)

MyISAM 引擎是 MySQL5.5.8 版本之前默認的存儲引擎,不支持事物,支持全文檢索,使用 B+Tree 作爲索引結構,葉節點的data域存放的是數據記錄的地址。

MyISAM 引擎使用 B+Tree 作爲索引結構,葉節點的 data 域存放的是數據記錄的地址。下圖是 MyISAM 主鍵索引的原理圖:
在這裏插入圖片描述

可以看出 MyISAM 的索引文件僅僅保存數據記錄的地址。在 MylSAM
中,主索引和輔助索引(Secondary key)在結構上沒有任何區別,只是主索引要求 key 是唯一的,而輔助索引的 key 可以重複。

MyISAM 中索引檢索的算法爲首先按照 B+Tree 搜索算法搜索索引,如果指定的 Key 存在,則取出其 data域 的值,然後以 data域 的值爲地址,讀取相應的數據記錄。


2.B+ 樹應用在InnoDB(聚簇索引)

InnoDB 存儲引擎支持事務,設計目標主要面向在線事務處理的應用,從MySQL 數據庫5.5.8版本開始, InnoDB 存儲引擎是默認的存儲引擎。InnoDB 支持 B+樹索引、全文索引、哈希索引。但 InnoDB 使用B+ Tree 作爲索引結構,具體實現方式卻與 MyISAM 截然不同。

MyISAM 索引文件和數據文件是分離的,索引文件中僅保存數據記錄的地址。而在 InnoDB 中,表數據文件本身就是按 B+Tree 組織的一個索引結構,這棵樹的葉節點 data域 保存了完整的數據記錄。這個索引的 key 是數據表的主鍵,因此 InnoDB 表數據文件本身就是主索引。

在這裏插入圖片描述
上圖是 InnoDB 主索引(同時也是數據文件)的示意圖,可以看到葉節點包含了完整的數據記錄,這種索引叫做聚集索引。因爲 InnoDB 的數據文件本身要按主鍵聚集,所以 InnoDB 要求表必須有主鍵(MyISAM可以沒有),如果沒有顯式指定,則 MySQL 系統會自動選擇一個可以唯一標識數據記錄的列作爲主鍵, 如果不存在這種列,則 MySQL 自動爲 InnoDB 表生成一個隱含字段作爲主鍵,這個字段長度爲6個字節,類型爲長整形。


3.關於 MyISAM 和 InnoDB 存儲引擎中主鍵索引和輔助索引

一是主索引的區別:InnoDB 的完整數據記錄就是索引文件。而 MyISAM 的索引和數據是分開的。

二是輔助索引的區別:InnoDB 的輔助索引 data域 存儲相應記錄主鍵的值,而不是地址,然後根據這個查找到的主鍵的值,去另外一份索引文件去查找(這一份索引文件包含了完整的數據記錄),相當於二次查找。而 MyISAM 的輔助索引和主索引沒有多大區別。

五.總結

1.紅黑樹是不符合 AVL 樹的平衡條件的(即每個節點的左子樹和右子樹的高度差的絕對值最大爲 1 的二叉平衡搜索樹)。但是紅黑樹提出了爲節點增加顏色,紅黑是用非嚴格的平衡來換取,自身增刪節點的時候的旋轉次數的降低的,任何不平衡都會在三次旋轉之內解決。而 AVL 是嚴格的二叉平衡搜索樹,因此在增加或者刪除節點的時候,根據不同的情況,旋轉的次數比紅黑樹要多。所以在經常增刪操作的數據結構中,紅黑樹的效率更高。紅黑樹的查詢性能略微遜色於 AVL 。

2.B樹 是爲了提高磁盤或外部存儲設備查找效率而產生的一種多路平衡搜索樹。

3.B+ 樹爲 B 樹的變形,用於大多數數據庫或文件系統的索引結構。

4.B 樹相對於紅黑樹的區別:在大規模數據存儲的時候,紅黑樹往往出現由於樹的深度過大而造成磁盤 IO 讀寫過於頻繁,而 IO 讀寫效率很低,進而導致效率低下的情況發生。樹的深度過大會造成磁盤 IO 頻繁讀寫,根據磁盤查找存取的次數往往由樹的高度所決定,所以,只要我們通過某種較好的樹結構減少樹的高度,因此 B 樹出現了。B樹可以有多個孩子,可以降低樹的高度。

5.B 樹和 B+ 樹的區別:B 樹所有節點都帶有指向記錄(數據)的指針,在非葉子節點就可以查找到數據,並停止搜索。而 B+ 樹只有葉子節點會帶有指向記錄(數據)的指針,也就是在葉子結點中才可以查找到數據,並停止搜索。因爲 B+ 樹它把所有的數據都存儲在葉節點中,內部節點只存放關鍵字和孩子指針,不會帶上指向記錄(數據)的指針。

6.B+ 樹中每個葉子節點都包含指向下一個葉子節點的指針。所有葉子節點都是通過指針連接在一起的,而 B樹 不會。 B+ 樹葉子節點之間通過指針來連接,範圍掃描十分簡單,而對於 B樹 來說,則需要在葉子節點和內部節點不停的往返移動。

7.B+ 樹還有一個最大的好處,遍歷更加高效,方便掃庫,B樹 必須用中序遍歷的方法按序掃庫,而 B+ 樹直接從葉子結點挨個掃一遍就完了。B+ 樹支持 range-query 非常方便,而 B樹 不支持,這是數據庫選用B+樹 的最主要原因。(B+ 樹的遍歷更加高效,B樹需要以中序的方式遍歷節點,而B+樹只需把所有葉子節點串成鏈表就可以從頭到尾遍歷)。

8.B+ 樹每個節點的指針和 key(關鍵值) 一樣多,B樹 每個節點指針比 key多 1。

9.爲什麼說 B+ 比 B 樹更適合實際應用中操作系統的文件索引和數據庫索引?

  1. B+的磁盤讀寫代價更低
    B+ 的內部結點並沒有指向關鍵字具體信息的指針,因此其內部結點相對B樹來說更小。如果把所有同一內部結點的關鍵字存放在同一盤塊中,那麼盤塊所能容納的關鍵字數量也越多。一次性讀入內存中的需要查找的關鍵字也就越多。相對來說IO讀寫次數也就降低了。

  2. B+ 的查詢效率更加穩定
    由於非葉子結點並不是最終指向文件內容的結點,而只是葉子結點中關鍵字的索引。所以任何關鍵字的查找必須走一條從根結點到葉子結點的路。所有關鍵字查詢的路徑長度相同,導致每一個數據的查詢效率相同。

10.數據庫索引採用 B+ 樹的主要原因是: B樹在提高了磁盤 IO 性能的同時,並沒有解決元素遍歷的效率低下的問題。正是爲了解決這個問題,B+樹應運而生。B+樹只要遍歷葉子節點就可以實現整棵樹的遍歷。而且在數據庫中,基於範圍的查詢是非常頻繁的,而 B 樹不支持這樣的操作(或者說效率太低)

11.B+ 樹的優點:

  • 非葉子節點不會帶上指向記錄(數據)的指針,這樣一個塊中可以容納更多的索引項,一是可以降低樹的高度,二是一個內部節點可以定位更多的葉子節點。
  • 葉子節點之間通過指針來連接,範圍掃描將十分簡單,而對於B樹來說,則需要在葉子節點和內部節點不停的往返移動。

12.B 樹的優點:

對於在內部節點的數據,可直接得到,不必根據葉子節點來定位。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章