本文收錄於專輯:http://dwz.win/HjK,點擊解鎖更多數據結構與算法的知識。node
你好,我是彤哥。mysql
前面兩節,咱們一塊兒學習了關於跳錶的理論知識,並手寫了兩種徹底不一樣的實現,咱們放一張圖來簡單地回顧一下:程序員
實現跳錶的關鍵之處是在有序鏈表的基礎上加上各層索引,經過這些索引能夠作到O(log n)的時間複雜度快速地插入、刪除、查找元素。面試
提及跳錶,咱們就不得不提另外一種很是經典的數據結構——紅黑樹,紅黑樹相對於跳錶來講,雖然時間複雜度都是O(log n),可是紅黑樹的使用場景相對更普遍一些,在早期的Linux內核中就一直存在紅黑樹的實現,也運用在了更高效的多路複用器Epoll中。算法
因此,紅黑樹是每個程序員不得不會的知識點,甚至有些變態的面試官,還會讓你手寫紅黑樹的一部分實現,好比左旋、右旋、插入平衡的過程、刪除平衡的過程,這些內容很是複雜,靠死記硬背每每很難完全掌握。sql
彤哥也是一直在尋找一種紅黑樹的記憶法,總算讓我找到了那麼一種還算不錯的方式,從紅黑樹的起源出發,理解紅黑樹的本質,再從本質出發,完全掌握不用死記硬背的方法,最後再把它手寫出來。數據庫
從本節開始,我也將把這種方法傳遞給你,所以,紅黑樹的部分,我會分紅三個小節來說解:緩存
好了,下面咱們就進入第一小節。數據結構
提及樹,咱們不得不說最有名的樹,那就是二叉樹,什麼是二叉樹呢?架構
二叉樹(binary tree),是指樹中的每一個節點最多隻有兩個子節點的樹。
固然,二叉樹自己彷佛沒什麼用,咱們平時說的二叉樹基本上都是指二叉查找樹,或者叫有序二叉樹、二叉搜索樹、二叉排序樹。
二叉查找樹(BST,binary search tree),就是在二叉樹的基礎上增長有序性,這個有序性通常是指天然順序,有了有序性,咱們就可使用二叉樹來快速的查找、刪除、插入元素了。
好比,上面這顆二叉查找樹,查找元素的平均時間複雜度爲O(log n)。
可是,二叉查找樹有個很是嚴重的問題,試想,仍是這三個元素,若是按照A、B、C的順序插入元素會怎樣?
這是啥?單鏈表?沒錯,當按照元素的天然順序插入元素的時候,二叉查找樹就退化成單鏈表了,單鏈表的插入、刪除、查找元素的時間複雜度是多少?O(n)。
因此,在極限狀況下,二叉查找樹的時間複雜度是很是差的。
既然,插入元素後有可能致使二叉查找樹的性能變差,那麼,咱們是否能夠增長一些手段,讓插入元素後的二叉查找樹依然性能良好呢?
答案是確定的,這種手段就叫作平衡
,這種能夠自平衡的樹就叫作平衡樹。
平衡樹(self-balancing or height-balanced binary search tree),是指插入、刪除元素後能夠自平衡的二叉查找樹,使得它的時間複雜度能夠一直漸近於O(log n)。
好比,上面那顆樹,按A、B、C插入元素後,作一次旋轉操做,就能夠再次變成查找時間複雜度爲O(log n)的樹。
可是,平衡樹一直只是一個概念,直到1962年才由兩個蘇聯人發明了第一種平衡樹——AVL樹。
嚴格來講,平衡樹是指能夠自平衡的二叉查找樹,三個關鍵詞:自平衡、二叉、查找(有序)。
AVL樹(由發明者Adelson-Velsky 和 Landis 的首字母縮寫命名),是指任意節點的兩個子樹的高度差不超過1的平衡樹。
好比,上面這顆樹,就是一顆AVL樹,不信你能夠數數看,是否是每一個節點的兩個子樹的高度差都不超過1。
是否是很難發現它真的是一顆AVL樹,沒錯,這是AVL樹的第一個缺點,不夠直觀,特別是節點個數多的時候。
第二個缺點,就是插入、刪除元素的時候自平衡的過程很是複雜,好比,上面這顆樹插入一個節點T
:
咱們從T往上找,它的父節點U,U的兩顆子樹的高度差爲1,知足AVL樹的規則,再往上,S的兩顆子樹的高度差爲1,也知足規則,再往上,V的兩顆子樹的高度差爲2,不知足規則,此時,須要一個自平衡的過程,該如何自平衡呢?
我下面給出圖示,你能夠試着理解一下:
紅色節點表示旋轉的軸。
通過兩次旋轉,讓這顆樹再次變成了AVL樹,並且這只是其中一種插入場景,真實的狀況還要根據插入的位置的不一樣作不一樣的旋轉,你能夠多插入幾個節點本身嘗試平衡一下。
一樣地,AVL樹的代碼也不是那麼好實現的,反正,到目前爲止,彤哥是沒搞懂AVL樹的各類規則。
基於這些缺點,因此,後來又發展出來了各類各樣的神奇的平衡樹。
2-3樹,是指每一個具備子節點的節點(內部節點,internal node)要麼有兩個子節點和一個數據元素,要麼有三個子節點和兩個數據元素的自平衡的樹,它的全部葉子節點都具備相同的高度。
簡單點講,2-3樹的非葉子節點都具備兩個分叉或者三個分叉,因此,稱做2叉-3叉樹更容易理解。
另一種說法,具備兩個子節點和一個數據元素的節點又稱做2節點,具備三個子節點和兩個數據元素的節點又稱做3節點,因此,整顆樹叫作2-3樹。
2-3樹,插入元素後自平衡的過程相對於AVL樹就要簡單得多了,好比,上面這顆樹,再插入一個元素K,它會先找到I J
這個節點,插入元素K,造成臨時節點I J K
,不符合2-3樹的規則,因此分裂,J
往上移,F H
這個節點變成了F H J
了,也不符合2-3樹的規則,繼續上移H
,根節點變爲D H
,同時,上移的過程當中,子節點也要相應的分裂,過程大體以下:
畫圖辛苦了,關注一波:彤哥讀源碼。
能夠看到,上面自平衡的過程當中,出現了一種節點,它具備四個子節點和三個數據元素,這個節點能夠稱做4節點,若是把4節點看成是能夠容許存在的,那麼,就出現了另外一種樹:2-3-4樹。
2-3-4樹,它的每一個非葉子節點,要麼是2節點,要麼是3節點,要麼是4節點,且能夠自平衡,因此稱做2-3-4樹。
2節點、3節點、4節點的定義在上面已經說起,咱們再重申一下:
2節點:包含兩個子節點和一個數據元素;
3節點:包含三個子節點和兩個數據元素;
4節點:包含四個子節點和三個數據元素;
固然,2-3-4樹插入元素的過程也很好理解,好比,上面這顆樹,插入元素M,找到K L
這個節點,插入便可,造成4節點,知足規則,不須要自平衡:
再插入元素N呢?過程與2-3樹同樣,向上分裂便可,此時,中間節點有兩個,取任意一個上移都是能夠的,咱們這裏以左中節點上移爲例,大體過程以下:
是否是挺簡單的,至少比AVL樹那種左旋右旋簡單得多。
一樣地,在2-3-4樹自平衡的過程當中出現了臨時的5節點,因此,若是容許5節點的存在呢?
嗯,2-3-4-5樹由此誕生!
一樣地,還有2-3-4-5-6樹、2-3-4-5-6-7樹……子子孫孫,無窮盡也~
因此,有人就把這一類樹概括爲一個新的名字:B樹。
B樹,表示的是一類樹,它容許一個節點能夠有多於兩個子節點,同時,也是自平衡的,葉子節點的高度都是相同的。
因此,爲了更好地區分一顆B樹到底屬於哪一類樹,咱們給它一個新的屬性:度(Degree)。
具備度爲3的B樹,表示一個節點最多有三個子節點,也就是2-3樹的定義。
具備度爲4的B樹,表示一個節點最多有四個子節點,也就是2-3-4樹的定義。
B樹,一個節點能夠存儲多個元素,有利於緩存磁盤數據,總體的時間複雜度趨向於O(log n),原理也比較簡單,因此,常常用於數據庫的索引,包括早期的mysql也是使用B樹來做爲索引的。
可是,B樹有個大缺陷,好比,我要按範圍查找元素,以上面的2-3-4樹爲例,查找大於B且小於K的全部元素,該怎麼實現呢?
很難,幾乎無解,因此,後面又出現替代B樹的方案:B+樹。
固然了,B+樹不是本節的重點,本節的重點是紅黑樹。
納尼,紅黑樹在哪裏?寫了3000多字了,還沒見到紅黑樹的影子,我尬了~
來了來了,有意思的紅黑樹來了~~
先上一張圖,請仔細體會:
看明白了沒有?紅黑樹是啥?紅黑樹就是2-3-4樹!!!
OK,本節到此結束。
本節,咱們一塊兒從二叉樹出發,一路通過二叉查找樹、平衡樹、AVL樹、2-3樹、2-3-4樹、B樹,最後終於得出了紅黑樹的本質,紅黑樹的本質就是一顆2-3-4樹,換了個皮膚而已。
那麼,爲何要再造一個紅黑樹呢?直接用2-3-4樹它不香麼?
咱們下一節解答,同時,下一節,咱們將從紅黑樹的本質出發,完全理解紅黑樹插入、刪除、查找、左旋、右旋的全過程,不再用死記硬背了,還不來關注我^^
關注公主號「彤哥讀源碼」,解鎖更多源碼、基礎、架構知識。