二叉樹滿足以下兩個條件的樹就是二叉樹:
簡單地理解,二叉樹(Binary tree)是每個節(jié)點最多只有兩個分支(即不存在分支度大于 2 的節(jié)點)的樹結(jié)構(gòu)。通常分支被稱作“左子樹”或“右子樹”。 二叉查找樹要了解紅黑樹之前,免不了先看下二叉查找樹是什么。 維基百科上的定義:二叉查找樹(英語:Binary Search Tree),也稱為二叉搜索樹、有序二叉樹(ordered binary tree)或排序二叉樹(sorted binary tree),是指一棵空樹或者具有下列性質(zhì)的二叉樹。 若任意節(jié)點的左子樹不空,則左子樹上所有節(jié)點的值均小于它的根節(jié)點的值;若任意節(jié)點的右子樹不空,則右子樹上所有節(jié)點的值均大于或等于它的根節(jié)點的值;任意節(jié)點的左、右子樹也分別為二叉查找樹。 圖示理解: 上圖為查找值為29的節(jié)點,有以下步驟:
退化二叉查找樹有個非常嚴(yán)重的問題,如果數(shù)據(jù)的插入是從大到小插入的,或者是從小到大插入的話,會導(dǎo)致二叉查找樹退化成單鏈表的形式,俗稱 **左瘸子:**例如,插入數(shù)據(jù)依次為 {5,4,3,2,1}(從大到?。瑒t如下圖所示: **右瘸子:**例如,插入數(shù)據(jù)依次為{1,2,3,4,5}(從小到大),則如下圖所示: 為了解決該問題,出現(xiàn)了一些解決方法,即平衡,能夠使得樹趨向平衡,這種自平衡的樹叫做平衡樹。 平衡樹平衡樹(Balance Tree,BT)指的是,任意節(jié)點的子樹的高度差都小于等于 1。 常見的符合平衡樹的有 AVL 樹(二叉平衡搜索樹),B 樹(多路平衡搜索樹,2-3 樹,2-3-4 樹中的一種),紅黑樹等。 AVL 樹AVL 樹(由發(fā)明者 Adelson-Velsky 和 Landis 的首字母縮寫命名),是指任意節(jié)點的兩個子樹的高度差不超過 1 的平衡樹。又稱自平衡二叉搜索樹。 AVL 樹能解決上文二叉查找樹中的右瘸子問題,例如,插入數(shù)據(jù)依次為 {1,2,3,4,5}(從小到大),則如下圖所示: AVL 樹會對不符合高度差的結(jié)構(gòu)進(jìn)行調(diào)整,從而使得二叉樹趨向平衡 2-3 樹2-3 樹,是指每個具有子節(jié)點的節(jié)點(內(nèi)部節(jié)點,internal node)要么有兩個子節(jié)點和一個數(shù)據(jù)元素,要么有三個子節(jié)點和兩個數(shù)據(jù)元素的自平衡的樹,它的所有葉子節(jié)點都具有相同的高度。 簡單點講,2-3 樹的非葉子節(jié)點都具有兩個分叉或者三個分叉,所以,稱作 2 叉-3 叉樹更容易理解。 另外一種說法,具有兩個子節(jié)點和一個數(shù)據(jù)元素的節(jié)點又稱作 2 節(jié)點,具有三個子節(jié)點和兩個數(shù)據(jù)元素的節(jié)點又稱作 3 節(jié)點,所以,整顆樹叫做 2-3 樹。 所有葉子點都在樹的同一層,一樣高:
創(chuàng)建 2-3 樹的規(guī)則插入操作如下: 向 2-節(jié)點中插入元素: 向一顆只含有一個 3-節(jié)點的樹中插入元素: 2-3-4 樹含義如下:
2-3-4 樹,它的每個非葉子節(jié)點,要么是 2 節(jié)點,要么是 3 節(jié)點,要么是 4 節(jié)點,且可以自平衡,所以稱作 2-3-4 樹。 規(guī)則如下:
插入操作原本的 2-3-4 樹,如下圖: 對于上圖的 2-3-4 樹,插入一個節(jié)點 17,由于規(guī)則 1,節(jié)點 17 不會加入節(jié)點 [16,18,20] 的子樹,而是與該節(jié)點融合。 ![]() 由于規(guī)則 2,節(jié)點 [16,17,18,20] 是一個 4 節(jié)點,將該節(jié)點進(jìn)行拆解成新的樹,將 18 作為子樹的根節(jié)點進(jìn)行拆分。 ![]() 此時樹暫時失去了平衡,我們需要將拆分后的子樹的根節(jié)點向上進(jìn)行融合。 ![]() 同理可得,由于規(guī)則 2,節(jié)點 [6,10,14,18] 是一個 4 節(jié)點,將該節(jié)點進(jìn)行拆解成新的樹,將 14 作為子樹的根節(jié)點進(jìn)行拆分,完成了 2-3-4 樹的構(gòu)建。 ![]() 總結(jié)了下插入節(jié)點的過程,無非也就為了符合兩條規(guī)則,那么,2-3 樹,2-3-4 樹都有了,那是不是也有 2-3-4-5 樹,2-3-4-5--...-n 樹的存在呢? 事實上是有的,世人把這一類樹稱為一個名字:B 樹。 B 樹B 樹,表示的是一類樹,它允許一個節(jié)點可以有多于兩個子節(jié)點,同時,也是自平衡的,葉子節(jié)點的高度都是相同的。 所以,為了更好地區(qū)分一顆 B 樹到底屬于哪一類樹,我們給它一個新的屬性:度(Degree):一個節(jié)點能有多少箭頭指向其他節(jié)點。 具有度為 3 的 B 樹,表示一個節(jié)點最多有三個子節(jié)點,也就是 2-3 樹的定義。具有度為 4 的 B 樹,表示一個節(jié)點最多有四個子節(jié)點,也就是 2-3-4 樹的定義。 圖為 4 的 B 樹的示例圖: ![]() 紅黑樹![]() R-B Tree,全稱是 Red-Black Tree,又稱為“紅黑樹”,它一種特殊的二叉查找樹。 紅黑樹的每個節(jié)點上都有存儲位表示節(jié)點的顏色,可以是紅(Red)或黑(Black)。 如何理解紅黑樹一個經(jīng)典的紅黑樹,如下圖所示(省略了葉子節(jié)點都是黑色的 NIL 節(jié)點): ![]() ![]() 如第二張圖所示,將該紅黑樹與上文講到的 2-3-4 樹對比,是否發(fā)現(xiàn),紅黑樹就是一個 2-3-4 樹:
**原因:**紅黑樹這些黑色節(jié)點在 2-3-4 樹中代表的是由 1 節(jié)點的一個 2-3-4 樹,而 2-3-4 樹是同一個子樹的深度是相同的,平衡的,所以從一個節(jié)點到該節(jié)點的子孫節(jié)點的所有路徑上包含相同數(shù)目的黑節(jié)點。 如下圖所示,藍(lán)色代表是黑色節(jié)點: ![]() 注意如下幾點:
由上面的例子所示,我們只要把紅黑樹當(dāng)做是 2-3-4 樹來處理,并且對應(yīng)的顏色進(jìn)行改變或者進(jìn)行左旋右旋的操作,即可達(dá)到使得紅黑樹平衡的目標(biāo)。 如何保持紅黑樹的結(jié)構(gòu)當(dāng)我們插入一個新的節(jié)點的時候,如何保證紅黑樹的結(jié)構(gòu)依然能夠符合上面的五個特性呢? 樹的旋轉(zhuǎn)分為左旋和右旋,下面借助圖來介紹一下左旋和右旋這兩種操作。 ①左旋 原本的狀態(tài): ![]() 過程圖: ![]() 結(jié)束圖: ![]() 如上圖所示,當(dāng)在某個目標(biāo)結(jié)點 E 上,做左旋操作時,我們假設(shè)它的右孩子 S 不是 NIL。 左旋以 S 到 E 之間的鏈為“支軸”進(jìn)行,它使 S 成為該子樹的新根,而 S 的左孩子則成為 E 的右孩子。 ②右旋 原先狀態(tài)圖: ![]() 過程圖: ![]() 結(jié)束圖: ![]() 同左旋類似,當(dāng)在某個目標(biāo)結(jié)點 S 上,做右旋操作時,我們假設(shè)它的右孩子 S 不是 NIL。 左旋以 S 到 E 之間的鏈為“支軸”進(jìn)行,它使 S 成為該子樹的新根,而 S 的左孩子則成為 E 的右孩子。 應(yīng)用紅黑樹的應(yīng)用比較廣泛,主要是用它來存儲有序的數(shù)據(jù),它的時間復(fù)雜度是 O(logn),效率非常之高。 例如,Java 集合中的 TreeSet 和 TreeMap,C++ STL 中的 set、map,以及 Linux 虛擬內(nèi)存的管理,都是通過紅黑樹去實現(xiàn)的。 碼農(nóng)有道 專注于服務(wù)器后臺開發(fā),包括c/c++、Linux、數(shù)據(jù)庫等技術(shù)棧。希望大家一起交流進(jìn)步! 72篇原創(chuàng)內(nèi)容 公眾號 |
|
|