1. 程式人生 > >動畫 | 什麼是紅黑樹?(與2-3-4樹等價)

動畫 | 什麼是紅黑樹?(與2-3-4樹等價)

二分搜尋樹是為了快速查詢而生,它是一顆二叉樹,每一個節點只有一個元素(值或鍵值對),左子樹所有節點的值均小於父節點的值,右子樹所有的值均大於父節點的值,左右子樹也是一顆二分搜尋樹,而且沒有鍵值相等的節點。它的查詢、插入和刪除的時間複雜度都與樹高成比例,期望值是O(log n)。

但是插入陣列如[],二分搜尋樹的缺點就暴露出來了,二分搜尋樹退化成線性表,查詢的時間複雜度達到最壞時間複雜度O(n)。

動畫:二分搜尋樹退化成線性表

那有沒有插入和刪除操作都能保持樹的完美平衡性(任何一個節點到其葉子節點的路徑長度都是相等的)?

有,B樹。B樹是一種自平衡的樹,根節點到其葉子節點的路徑高度都是一樣的,能夠保持資料有序(通過中序遍歷能得到有序資料)。B樹一個節點可以擁有2個以上的子樹,如2-3樹、2-3-4樹甚至2-3-4-5-6-7-8樹,它們滿足二分搜尋樹的性質,但它們不屬於二叉樹,也不屬於二分搜尋樹。

2-3-4樹的完美平衡,每條從根節點到葉子節點的路徑的高度都是一樣的

2-3-4樹有以下節點組成:

2-節點,含有一個元素(值或鍵值對)和兩個子樹(左右子樹),左子樹所有的值均小於父節點的值,右子樹所有的值均大於父節點的值;

3-節點,含有兩個元素和三個子樹,左子樹所有的值均小於父節點最小元素的值,中間子樹所有的值均位於父節點兩個元素之間,右子樹所有的值均大於父節點最大元素的值;

4-節點,含有三個元素和四個子樹,節點之間的比較也滿足二分搜尋樹的性質。

2-3-4樹查詢演算法

2-3-4樹的查詢類似二分搜尋樹的查詢。

2-3-4樹插入演算法

2-3-4樹的插入演算法是消除當前節點是4-節點,將4-節點分解成多個2-節點,中間的2-節點與父節點合併成3-節點或4-節點。

沿著連結向下進行變換分解4-節點分為兩種情況:

1)4-節點作為根節點,分解成3個2-節點,中間的2-節點作為根節點;

2)當前節點為4-節點,分解成3個2-節點,中間的2-節點與父節點合併成3-節點或4-節點;


圖:沿著連結向下進行變換,分解4-節點

在沿著左右連結向下進行變換的同時,也會進行命中查詢。如果元素是鍵值對的話,查詢命中將舊的值賦值為新的值;如果元素是一個值的話,查詢命中將忽略之,因為二分搜尋樹需要滿足沒有相等的元素;如果需要支援重複的元素,則在元素物件新增count屬性,預設為1。

如果查詢未命中,則將待插入元素插入在葉子節點上。樹底下插入一個元素只有兩種情況:向2-節點中插入和向3-節點中插入。


圖:樹底下插入一個元素

2-3-4樹刪除演算法

2-3-4樹的刪除演算法是消除當前節點是2-節點,向兄弟節點或父節點借一個元素過來。

刪除最小元素

從根節點的左孩子開始,沿著左連結向下進行變換可以分為三種情況:

1)當前節點不是2-節點,跳過;

2)當前節點是2-節點,兄弟節點是2-節點,將當前節點、父節點最小元素和兄弟節點合併為4-節點,當前節點變換成4-節點;

3)當前節點是2-節點,兄弟節點不是2-節點,將兄弟節點的最小元素移到父節點,父節點的最小元素移到當前節點,當前節點變換成3-節點。


圖:沿著左連結向下進行變換

刪除最大元素

從根節點的右孩子開始,沿著右連結向下進行變換也同樣分為三種情況:

1)當前節點不是2-節點,跳過;

2)當前節點是2-節點,兄弟節點是2-節點,將當前節點、父節點的最大元素和兄弟節點合併為4-節點,當前節點變換成4-節點;

3)當前節點是2-節點,兄弟節點不是2-節點,將兄弟節點的最大元素移到父節點,父節點的最大元素移到當前節點,當前節點變換成3-節點。


圖:沿著右連結向下進行變換

刪除任意元素

學習過刪除最小元素和刪除最大元素演算法之後,刪除任意元素的演算法自然就簡單了。刪除任意元素演算法需要先進行命中查詢,若查詢命中,則將右子樹的最小值替換掉待刪除元素,然後將右子樹進行刪除最小元素的演算法。

2-3-4樹雖滿足二分搜尋樹的性質,但不是一顆二分搜尋樹。如果期望它是一顆二分搜尋樹,就需要將3-節點和4-節點替換為多個2-節點,還需要註明元素之間的關係(用紅連結表示)。

替換3-節點和4-節點


圖:替換3-節點


圖:替換4-節點

但是存在一個問題,2-3-4樹因為3-節點的不同表示會有很多種不同的紅黑樹,3-節點既可以左傾,也可以右傾。所以為了保證樹的唯一性,3-節點只考慮左傾,當然你也可以只考慮右傾。

這樣對於任何一顆2-3-4樹,只考慮左傾的情況下,都能得到唯一的一顆對應的紅黑樹,這種樹也叫左傾紅黑樹,相對比較減少了複雜性,設計更容易被實現。

紅黑樹查詢演算法

紅黑樹的查詢演算法和二分搜尋樹一樣。

關於連結的顏色變換隻跟顏色轉換有關,而旋轉不會改變連結的顏色變換,只在被紅連結指向的節點變成紅色,被黑連結指向的節點變成黑色。

旋轉

旋轉是將不滿足紅黑樹性質的3-節點和4-節點進行旋轉,如果3-節點出現右連結,則將右連結通過左旋轉變成左連結;如果4-節點出現一個紅節點連著兩條紅連結,則將4-節點配平。

左旋轉


圖:左旋轉

右旋轉


圖:右旋轉


圖:3-節點和4-節點的旋轉

Code:右旋轉和左旋轉

顏色轉換

顏色轉換隻應用於4-節點。


圖:顏色轉換

Code:顏色轉換

紅黑樹插入演算法

回顧之前的2-3-4樹的插入演算法,它有兩個過程:沿著連結向下進行分解4-節點和樹底下插入一個元素。

紅黑樹的插入演算法和2-3-4樹的插入演算法類似,它不僅包含前面兩個過程,還增加了向上進行變換的過程,此過程是將3-節點左傾和4-節點配平。

紅黑樹插入演算法會先從根節點開始,沿著左右連結向下進行變換,目的是為了分解4-節點。如果該節點的左右孩子都是紅節點,則通過flipColors方法進行顏色轉換,接著進行下一個子節點;如果不是,則直接進行下一個子節點。

到達樹底的時候,則意味著可以開始插入新的元素。

如果紅黑樹目前是一顆空樹,插入紅色的元素作為第一個節點,然後該節點變成黑色。如果不是一顆空樹,插入元素分為三種情況:向2-節點插入新元素、向3-節點插入新元素和向4-節點插入新元素。

向2-節點插入新元素

向2-節點插入新元素很簡單,如果新元素的值小於父節點,直接插入紅色的節點即可;如果新元素的值大於父節點,則產生一個紅色右連結,插完之後則將3-節點進行左旋轉,將右連結變成左連結,被紅連結指向的節點變成紅色,被黑連結指向的節點變成黑色。


圖:向2-節點插入新元素

向3-節點插入新元素

因為前面的3-節點進行過旋轉,此時的3-節點肯定滿足左傾紅黑樹的性質。向3-節點插入新元素分為三種情況:

1)新元素的值位於3-節點中的兩元素之間;

2)新元素的值小於3-節點中的最小元素;

3)新元素的值大於3-節點中的最大元素。


圖:向3-節點插入新元素

##### 向4-節點插入新元素

向4-節點插入新元素之前需要先進行顏色轉換,才可以進行插入新的元素。


圖:向4-節點插入新元素

插完新元素之後需要滿足紅黑樹的性質,則在沿著父節點的連結向上進行變換,具體做法和向3-節點插入新元素的做法類似,通過左旋轉將3-節點左傾和左右旋轉將4-節點配平,沒有顏色轉換。

動畫:2-3-4樹與紅黑樹的插入

Code:紅黑樹插入演算法

紅黑樹刪除演算法

紅黑樹刪除演算法也需要進行旋轉和顏色轉換操作,在插入演算法中為了待插入元素所在的節點不是4-節點,所以在沿著左右連結向下進行變換時將4-節點分解成3個2-節點,中間的2-節點與父節點合併;而在刪除演算法中為了待刪除元素所在的節點不是2-節點,所以在沿著左右連結向下進行變換時將2-節點向其它不是2-節點的節點(兄弟節點或父節點)借一個元素過來,合併成3-節點。

所以,只要是2-節點的節點,如果兄弟節點不是2-節點,就將兄弟節點的與父節點鄰近的元素移到父節點,而父節點將與當前節點鄰近的元素移到當前節點;如果兄弟節點是2-節點,則將父節點的與當前節點鄰近的元素移到當前節點。(是不是很繞?待會在後面刪除最值演算法中詳細給出)

然後刪除完一個元素之後需要進行修復調整,將這個樹滿足紅黑樹的性質。如果右連結是紅色,將右連結通過左旋轉變成左連結;如果有連續的左連結,通過右旋轉配平,然後進行顏色轉換。

Code:向上變換(修復調整)

刪除最小元素

刪除最小元素演算法和二分搜尋樹一樣,一直遞迴它的左孩子,直到它的左孩子為空才進行刪除這個最小元素。但是紅黑樹在遞迴的同時如何旋轉和顏色轉換是個問題。

刪除最小元素演算法一直沿著左連結向下進行轉換,對照2-3-4樹,我們可以給出三種情況,從根節點開始:

1)當前節點(父節點位置)的左子節點不是2-節點,直接進行下一個節點(左子節點);

2)當前節點的左子節點和右子節點都是2-節點,則將左子節點、當前節點的最小元素和右子節點合併成4-節點,然後進行下一個節點;

3)當前節點的左子節點是2-節點,右子節點不是2-節點,則將右子節點的最小元素移到當前節點的位置,當前節點的最小元素移到左子節點,然後進行下一個節點。


圖:沿著左連結向下進行轉換

Code:沿著左連結向下變換

直到某元素左孩子為空的時候,此時的元素是這個樹的最小元素。因為通過前面的轉換,最小元素肯定被一個紅連結指向,刪除這個元素之後通過balance方法修復調整為紅黑樹。

Code:刪除最小元素演算法

刪除最大元素

刪除最大元素演算法和刪除最小元素演算法類似的,也分為三種情況:

1)當前節點(父節點位置)的右子節點不是2-節點,直接進行下一個節點(右子節點);

2)當前節點的右子節點和左子節點都是2-節點,則將右子節點、當前節點的最大元素和左子節點合併成4-節點,然後進行下一個節點;

3)當前節點的右子節點是2-節點,左子節點不是2-節點,則將左子節點的最大元素移到當前節點的位置,當前節點的最大元素移到左子節點,然後進行下一個節點。


圖:沿著右連結向下進行變換

Code:沿著右連結向下變換

Code:刪除最大元素演算法

刪除任意元素

學習過前面的刪除最小元素演算法和刪除最大元素演算法,刪除任意元素會變得很簡單。刪除最小元素演算法會一直沿著左連結向下進行變換,刪除最大元素演算法會一直沿著右連結向下進行變換,而刪除任意元素演算法需要同時存在著左右連結向下進行變換。

刪除任意元素演算法需要先進行命中查詢,在命中查詢的過程中會進行沿著左右連結向下變換,如果查詢命中則將右子樹的最小元素替換掉待刪除元素,然後進行右子樹的刪除最小元素演算法;如果查詢未命中,則直接返回balance函式,向上將3-節點左傾或將4-節點配平。

Code:刪除任意元素演算法

動畫:2-3-4樹與紅黑樹的刪除

學習完上面的演算法之後,可以總結下紅黑樹的性質:

1)每個節點或是紅色的,或是黑色的;

2)根節點是黑色的;

3)每個葉子節點(NIL)是黑色的;

4)如果一個節點是紅色的,則它的兩個子節點都是黑色的(NIL節點也是黑色的);

5)對每個結點,從該節點到其所有後代葉子節點的簡單路徑上,均包含相同數目的黑色節點(黑連結平衡)。

喜歡本文的朋友,歡迎關注公眾號「演算法無遺策」,收看更多精彩內容

相關推薦

動畫 | 什麼是2-3-4等價

二分搜尋樹是為了快速查詢而生,它是一顆二叉樹,每一個節點只有一個元素(值或鍵值對),左子樹所有節點的值均小於父節點的值,右子樹所有的值均大於父節點的值,左右子樹也是一顆二分搜尋樹,而且沒有鍵值相等的節點。它的查詢、插入和刪除的時間複雜度都與樹高成比例,期望值是O(log n)。 但是插入陣列如[],二分搜尋樹

2-32-3-4

2-3樹   2-3樹是一棵自平衡的多路查詢樹,它並不是一棵二叉樹,具有如下性質: (1)每個節點有1個或2個key,對應的子節點為2個子節點或3個子節點; (2)所有葉子節點到根節點的長度一致; (3)每個節點的key從左到右保持了從小到大的順序,兩個

2-3-4(下) JavaC的實現

歡迎探討,如有錯誤敬請指正 相關部落格: 1. 實現技巧 為了簡化程式碼和減少不必要的開銷,在具體的實現中我們定義一個偽根節點ROOT且只定義一個NIL節點。偽根節點的左子支永遠指向NIL節點,NIL節點的左右子支又指向它自身。偽根節點的右子支才表示真正的紅黑樹。 2. Java語言實現 packa

2-3-4

歡迎探討,如有錯誤敬請指正 相關部落格: 1. 2-3-4樹的定義 2-3-4樹是一種階為4的B樹。它是一種自平衡的資料結構,可以保證在O(lgn)的時間內完成查詢、插入和刪除操作。它主要滿足以下性質: (1)每個節點每個節點有1、2或3個key,分別稱為2(孩子)節點,3(孩子)節點,4(孩子)節點。

2-3-4

歡迎探討,如有錯誤敬請指正 相關部落格: 1. 紅黑樹的定義 2-3-4樹和紅黑樹是完全等價的,由於絕大多數程式語言直接實現2-3-4樹會非常繁瑣,所以一般是通過實現紅黑樹來實現替代2-3-4樹,而紅黑樹本也同樣保證在O(lgn)的時間內完成查詢、插入和刪除操作。 紅黑樹是每個節點都帶有顏色屬性的平衡二

經典搜尋演算法之2-3-4

1.2-3-4樹     在筆者上篇文章中,介紹了B樹和B+樹,這裡我所說的2-3-4樹就是階為4的B樹。根據離散數學的圖論相關知識,可以證明2-3-4樹和紅黑樹是等價的。對於m階(m指的結點的最大分支數)B樹,其結點的值的個數n:1<=n<m。因此,對於2-3

資料結構——2-3-4

                          2-3-4樹與紅黑樹 2-3-4樹        前面講到了2-3樹,2-3樹是允許節點最多有三個子節點的樹,2-3樹中有2節點和3節點,2節點跟普通的二叉樹節點一樣,3節點AB就是的左子樹上的所有節點的值小於A,中子樹上

通過2-3-4理解

文章 n+1 情況下 代碼實現 樹結構 沒有 case 多人 檢驗 前言 紅黑樹是數據結構中比較復雜的一種,最近與它交集頗多,於是花了一周的空閑時間跟它死磕,終於弄明白並實現了紅黑樹。寫文總結一下,希望能給試圖理解紅黑樹的同學一些靈感,也讓我能記得更深刻。 在研究紅黑樹時吃

2-3-4、B

2-3-4樹                   如上圖所示。          有的節點存一個值,則有2個孩子,如:                    W(比W小的為左海子,比W大的為右孩子)          有的結點存兩個值,則有3個孩子,如:         

資料結構和演算法(Golang實現)(30)查詢演算法-2-3-4和普通

文章首發於 閱讀更友好的GitBook。 2-3-4樹和普通紅黑樹 某些教程不區分普通紅黑樹和左傾紅黑樹的區別,直接將左傾紅黑樹拿來教學,並且稱其為紅黑樹,因為左傾紅黑樹與普通的紅黑樹相比,實現起來較為簡單,容易教學。在這裡,我們區分開左傾紅黑樹和普通紅黑樹。 紅黑樹是一種近似平衡的二叉查詢樹,從2-3樹或2

Java數據結構和算法十二——2-3-4

oid 樹的高度 n+1 tno != val post 節點數據 isp   通過前面的介紹,我們知道在二叉樹中,每個節點只有一個數據項,最多有兩個子節點。如果允許每個節點可以有更多的數據項和更多的子節點,就是多叉樹。本篇博客我們將介紹的——2-3

查詢三 多路查詢2-32-3-4,B、B+

應用場景:解決在硬碟中的大量資料中的查詢。因為大量資料儲存在硬碟中,不能一次全部載入到記憶體中,而每次查一個數據讀一次硬碟,讀取速度太慢,這時就需要使用一種資料結構一部分一部分讀入,這就是多路查詢樹的作用。 2-3樹 2結點:每個幾點包含一個元素和兩個孩

動畫 | 什麼是2-3-4

畫了一系列樹的動畫,從二分搜尋樹,到AVL樹,再到2-3樹,再到基於2-3樹的紅黑樹,都可以發現這些樹都跟二叉查詢樹很像啊。 嘿嘿!二分搜尋樹就是二叉查詢樹;AVL樹也是一顆二分搜尋樹,只多了高度差的限制;2-3樹雖滿足二分搜尋樹的性質,但不是一顆二分搜尋樹,2-3樹由2-節點和3-節點組成的,滿足了完美平衡

多路查詢2-3 2-3-4 、B 、B+

> 本文參考自《大話資料結構》 ## 計算機中資料的儲存 一般而言,我們都是在記憶體中處理資料,但假如我們要操作的資料集非常大,記憶體無法處理了,在這種情況下對資料的處理需要不斷地從硬碟等儲存裝置中調入或調出記憶體頁面。 對外存裝置的讀寫,效率並不樂觀。為了降低對外存裝置的訪問次數,我們需要新的

scala spark-streaming整合kafka spark 2.3 kafka 0.10

obj required word 錯誤 prope apache rop sta move Maven組件如下: <dependency> <groupId>org.apache.spark</groupId> <

java8下spark-streaming結合kafka程式設計spark 2.3 kafka 0.10

前面有說道spark-streaming的簡單demo,也有說到kafka成功跑通的例子,這裡就結合二者,也是常用的使用之一。 1.相關元件版本 首先確認版本,因為跟之前的版本有些不一樣,所以才有必要記錄下,另外仍然沒有使用scala,使用java8,spark 2.0.0,kafk

資料結構之2-3-4

1. 2-3-4樹是什麼 在二叉樹中,每個節點有一個數據項,最多有兩個子節點。如果允許每個節點可以有更多的資料項和更多的子節點,就是多叉樹(multiway tree)。 2-3-4樹就是一種階為4的多叉樹,它像紅黑樹一樣是平衡樹,可以保證在O(lgn)的時間內完成查詢、插入和刪除操

【資料結構和演算法06】2-3-4

    從第4節的分析中可以看出,二叉搜尋樹是個很好的資料結構,可以快速地找到一個給定關鍵字的資料項,並且可以快速地插入和刪除資料項。但是二叉搜尋樹有個很麻煩的問題,如果樹中插入的是隨機資料,則執行效果很好,但如果插入的是有序或者逆序的資料,那麼二叉搜尋樹的執行速度就變得很慢

多路查詢2-32-3-4、B、B+、B*、R

多路查詢樹 每一個結點的孩子數可以多於兩個,且每一個結點處可以儲存多個元素。由於它是查詢樹,所有元素之間存在某種特定的排序關係。 四種特殊形式:2-3樹、2-3-4樹、B樹和B+樹 2-3樹 概念: 1、2-3樹是這樣的一棵多路查詢樹:其中的每一個

python教程系列三.2.3、file模組

Python File(檔案) 方法 open() 方法 Python open() 方法用於開啟一個檔案,並返回檔案物件,在對檔案進行處理過程都需要使用到這個函式,如果該檔案無法被開啟,會丟擲 OSError。 **注意:**使用 open() 方法一定要保證關閉檔案