紅黑樹是怎么實(shí)現(xiàn)的火邓,看這篇真的就夠了!

紅黑樹是一個(gè)基本平衡的二叉樹,在查詢方面铲咨,與二叉查找樹思路相同;在插入方面躲胳,單次回溯不會(huì)超過2次旋轉(zhuǎn);在刪除方面,單次回溯不會(huì)超過3次旋轉(zhuǎn)!

紅黑樹由來:在1972年由Rudolf Bayer發(fā)明的纤勒,當(dāng)時(shí)被稱為平衡二叉B樹(symmetric binary B-trees)坯苹,后來,在1978年被 Leo J. Guibas 和 Robert Sedgewick 修改為如今的紅黑樹摇天,就此紅黑樹出現(xiàn)在軟件開發(fā)者的視野里!

一粹湃、摘要

在上篇文章中,我們詳細(xì)的介紹到平衡二叉查找樹的算法以及代碼實(shí)踐泉坐,我們知道平衡二叉查找樹是一個(gè)高度平衡的二叉樹为鳄,也就是說樹的高度差不能大于1,在刪除的時(shí)候腕让,可能需要多次調(diào)整孤钦,也就是左旋轉(zhuǎn)、右旋轉(zhuǎn)操作记某,在樹的深度很大的情況下司训,刪除效率會(huì)非常低,如何提高這種效率?

紅黑樹由此誕生了液南,了解過紅黑樹的朋友們一定知道壳猜,紅黑樹是一個(gè)基本平衡的二叉樹,英文全稱:red-black-tree滑凉,簡稱:RBT统扳,特性如下:

1.每個(gè)節(jié)點(diǎn)要么是黑色要么是紅色;

2.根節(jié)點(diǎn)是黑色;

3.每個(gè)葉子節(jié)點(diǎn)是黑色;(注意:這里葉子節(jié)點(diǎn),是指為空的葉子節(jié)點(diǎn))

4.如果一個(gè)節(jié)點(diǎn)是紅色的畅姊,則它的子節(jié)點(diǎn)必須是黑色的;(說明父子節(jié)點(diǎn)之間不能出現(xiàn)兩個(gè)連續(xù)的紅節(jié)點(diǎn))

5.從一個(gè)節(jié)點(diǎn)到該節(jié)點(diǎn)的子孫節(jié)點(diǎn)的所有路徑上包含相同數(shù)目的黑節(jié)點(diǎn);

關(guān)于它的特性咒钟,需要注意的是:

特性3中的葉子節(jié)點(diǎn),是只為空(NIL 或 null)的節(jié)點(diǎn);

特性5若未,確保沒有一條路徑會(huì)比其他路徑長出倆倍朱嘴,因而,紅黑樹是相對的接近平衡的二叉樹!(比如粗合,包含相同數(shù)目為3的黑節(jié)點(diǎn)路線萍嬉,最短路線:`黑節(jié)點(diǎn) -> 黑節(jié)點(diǎn) -> 黑節(jié)點(diǎn)`,長度為3;最長路線:`黑節(jié)點(diǎn) -> 紅節(jié)點(diǎn) -> 黑節(jié)點(diǎn) -> 紅節(jié)點(diǎn) -> 黑節(jié)點(diǎn)`隙疚,長度為5)

紅黑樹示例圖壤追,如下:

紅黑樹,與二叉樹供屉,在查詢行冰、插入溺蕉、刪除方面,都是一樣的悼做,最大的不同點(diǎn)是疯特,插入、刪除需要重新調(diào)整樹的形態(tài)贿堰,以保持紅黑樹的特性!

二辙芍、算法思路

在上篇平衡二叉樹的文章中啡彬,我們了解到為了保證樹的高度差不超過1羹与,我們通過樹高超過1這么一個(gè)判斷條件,通過左旋轉(zhuǎn)庶灿、右旋轉(zhuǎn)來調(diào)整纵搁,從而保證樹的高度平衡!

對于紅黑樹,其實(shí)也是一樣的往踢,對于插入腾誉、刪除操作,主要也是通過左旋轉(zhuǎn)峻呕、右旋轉(zhuǎn)來進(jìn)行調(diào)整利职,相比平衡二叉樹,紅黑樹因?yàn)楣?jié)點(diǎn)有顏色標(biāo)簽瘦癌,多了一個(gè)顏色轉(zhuǎn)變操作!

同理猪贪,我們只需要分析出哪些場景下需要進(jìn)行調(diào)整,即可總結(jié)出算法讯私,從而寫出實(shí)踐代碼!

廢話也不多說來热押,下面我們一起來分析一下紅黑樹,在插入斤寇、刪除操作時(shí)桶癣,應(yīng)該怎么處理!

2.1、插入場景

將一個(gè)節(jié)點(diǎn)插入到紅黑樹中娘锁,需要執(zhí)行哪些步驟呢?

第一步:將紅黑樹當(dāng)作一顆二叉查找樹牙寞,將節(jié)點(diǎn)插入樹的底部;

第二步:默認(rèn)將插入的節(jié)點(diǎn)著色為紅色,如果是根節(jié)點(diǎn)莫秆,顏色著為黑色;

第三步:通過一系列的旋轉(zhuǎn)或著色等操作间雀,使之重新成為一顆紅黑樹;

對于第一步,比較好理解馏锡,紅黑樹其實(shí)就是二叉樹的一種特殊形態(tài)的樹形結(jié)構(gòu)雷蹂,先找到合適的位置,然后將節(jié)點(diǎn)插入到樹上杯道。

對于第二步匪煌,為什么新插入的節(jié)點(diǎn)要設(shè)置為紅色呢?

因?yàn)椴迦胫八懈镣獠抗?jié)點(diǎn)的路徑上黑色節(jié)點(diǎn)數(shù)目都相同责蝠,所以如果插入的節(jié)點(diǎn)是黑色,肯定會(huì)導(dǎo)致黑色節(jié)點(diǎn)數(shù)目不相同!

而相對的插入紅節(jié)點(diǎn)可能也會(huì)違反不能出現(xiàn)兩個(gè)連續(xù)的紅節(jié)點(diǎn)萎庭,如果違反條件霜医,直接進(jìn)行顏色轉(zhuǎn)換或者旋轉(zhuǎn)操作即可!

相對將插入的節(jié)點(diǎn)著色為黑色,紅色操作可能更簡單些!因?yàn)楦?jié)點(diǎn)為黑色驳规,如果是新插入的節(jié)點(diǎn)為根節(jié)點(diǎn)肴敛,直接將顏色設(shè)置為黑色!

既然新插入的節(jié)點(diǎn)為紅色,那么我們就繼續(xù)來分析一下吗购,新插入節(jié)點(diǎn)的場景医男,例如:

1.插入的節(jié)點(diǎn),父親為黑色;

2.插入的節(jié)點(diǎn)捻勉,父親為紅色;

當(dāng)新插入的節(jié)點(diǎn)的父親為黑色時(shí)!因?yàn)樾虏迦氲墓?jié)點(diǎn)為紅色镀梭,因此不會(huì)違反任何特性!

當(dāng)新插入的節(jié)點(diǎn)的父親為紅色時(shí)!因?yàn)樾虏迦氲墓?jié)點(diǎn)為紅色,違反不能出現(xiàn)兩個(gè)連續(xù)的紅節(jié)點(diǎn)踱启,因此需要進(jìn)行調(diào)整!

這種場景有3種調(diào)整情況报账,為了便于下面分析,假設(shè)將新插入節(jié)點(diǎn)用z代替埠偿,z的父節(jié)點(diǎn)用a代替透罢,a的父節(jié)點(diǎn)用c代替,z的叔節(jié)點(diǎn)用y代替冠蒋,如下:

情況1:z的叔節(jié)點(diǎn)y是紅色的

case1調(diào)整過程如下:

調(diào)整說明:因?yàn)楣?jié)點(diǎn) z 是一個(gè)紅色節(jié)點(diǎn)羽圃,其父節(jié)點(diǎn) a 是紅色的,違反了特性4浊服,因此需要進(jìn)行調(diào)整统屈。因?yàn)槠涫骞?jié)點(diǎn) y 是紅色的,于是可以修改節(jié)點(diǎn) a牙躺、節(jié)點(diǎn) y 為黑色愁憔,此時(shí)節(jié)點(diǎn) c 的黑高會(huì)發(fā)生變化,由原來的黑高1變成黑高2孽拷,為了節(jié)點(diǎn) c 保持黑高不變吨掌,將其變成紅色。

此時(shí)脓恕,由于節(jié)點(diǎn) c 由黑色變成了紅色膜宋,如果節(jié)點(diǎn) c 的父節(jié)點(diǎn)是紅色,也會(huì)違反特性4炼幔,繼續(xù)將節(jié)點(diǎn) c 看成是節(jié)點(diǎn) z音五,向上回溯調(diào)整樹!

需要注意的是:對于新插入的節(jié)點(diǎn) z 是節(jié)點(diǎn)a 的左子樹的情況宙彪,操作與上述一致;對于新插入的節(jié)點(diǎn) z 是節(jié)點(diǎn) c 的右子樹的節(jié)點(diǎn)的情況,操作與上述對稱!

情況2:z的叔節(jié)點(diǎn)y是黑色摆寄,且z是一個(gè)左孩子

case2調(diào)整過程如下:

調(diào)整說明:這種情況诱建,并不能像上面那樣改變節(jié)點(diǎn)顏色就可以滿足要求,因?yàn)槿绻麑⒐?jié)點(diǎn)z 的父節(jié)點(diǎn) a 變成了黑色, 那么樹的黑高就會(huì)發(fā)生變化,必然會(huì)引起對性質(zhì)5的違反殉农。比如,此時(shí)節(jié)點(diǎn)y為黑色局荚, 節(jié)點(diǎn)c 的右子樹高度為2(忽略子樹)超凳,左子樹高也相同,如果簡單的修改節(jié)點(diǎn)a 為黑色耀态,那么節(jié)點(diǎn)c 的左子樹的黑高會(huì)比右子樹大1轮傍, 此時(shí)即使將節(jié)點(diǎn)c 修改為紅色也于事無補(bǔ)!

因此,單靠顏色轉(zhuǎn)變無非解決問題茫陆,需要進(jìn)行旋轉(zhuǎn)調(diào)整金麸。先繞節(jié)點(diǎn) a 的父節(jié)點(diǎn)進(jìn)行右旋轉(zhuǎn),再將節(jié)點(diǎn) a簿盅、節(jié)點(diǎn) c 的顏色進(jìn)行互換!最終結(jié)果與插入前一致!

需要注意的是:對于新插入的節(jié)點(diǎn) z 是節(jié)點(diǎn) c 的右子樹的節(jié)點(diǎn)的情況,操作與上述對稱!

情況3:z的叔節(jié)點(diǎn)y是黑色揍魂,且z是一個(gè)右孩子

case3調(diào)調(diào)整過程如下:

調(diào)整說明:當(dāng)節(jié)點(diǎn) z 是一個(gè)右孩子時(shí)桨醋,先繞節(jié)點(diǎn) a 進(jìn)行左旋轉(zhuǎn),之后樹的形態(tài)就變成如上面介紹的情況2现斋,再進(jìn)行右旋轉(zhuǎn)喜最、顏色轉(zhuǎn)變,即可實(shí)現(xiàn)紅黑樹的特性!

需要注意的是:對于新插入的節(jié)點(diǎn) z 是節(jié)點(diǎn) c 的右子樹的節(jié)點(diǎn)的情況庄蹋,操作與上述對稱!

以上就是紅黑樹新增節(jié)點(diǎn)時(shí)瞬内,所有可能的操作以及調(diào)整方式!

可以得出如下結(jié)論:對插入節(jié)點(diǎn)后的調(diào)整所做的旋轉(zhuǎn)操作不會(huì)超過2次!

2.2、刪除場景

我們繼續(xù)來看看刪除場景限书,對于二叉查找樹操作虫蝶,我們知道有如下步驟:

當(dāng)刪除節(jié)點(diǎn),只有左子樹時(shí)倦西,將右子樹向上移動(dòng);

當(dāng)刪除節(jié)點(diǎn)能真,只有右子樹時(shí),將左子樹向上移動(dòng);

當(dāng)刪除節(jié)點(diǎn)扰柠,有左粉铐、右子樹時(shí),通過找到刪除節(jié)點(diǎn)的右節(jié)點(diǎn)的最末端左子樹卤档,也就是后繼節(jié)點(diǎn)蝙泼,進(jìn)行替換并刪除;

二叉查找樹刪除過程圖:

紅黑樹的操作也是如此,步驟如下;

第一步:將紅黑樹當(dāng)作一顆二叉查找樹劝枣,將節(jié)點(diǎn)刪除;

第二步:通過旋轉(zhuǎn)和變色等一系列來修正該樹汤踏,使之重新成為一棵紅黑樹;

在第一步中倡缠,首先我們重點(diǎn)要弄清楚什么是刪除節(jié)點(diǎn)?

這個(gè)刪除節(jié)點(diǎn),某些情況下并非我們真正傳入的刪除值茎活,對于擁有左子樹昙沦、右子樹的節(jié)點(diǎn)來說,刪除節(jié)點(diǎn)指的是被刪除節(jié)點(diǎn)的后繼節(jié)點(diǎn)或者前驅(qū)節(jié)點(diǎn)!

可能有點(diǎn)繞载荔,例如上圖中擁有左子樹盾饮、右子樹的刪除場景,我們傳入需要?jiǎng)h除的節(jié)點(diǎn)是 80懒熙,但是實(shí)際上刪除節(jié)點(diǎn)的是85節(jié)點(diǎn)(85是一個(gè)葉子節(jié)點(diǎn))丘损,然后將80節(jié)點(diǎn)內(nèi)容替換成85,做了一個(gè)偷天換日的操作!

因此無論對于哪種情況工扎,我們可以得出結(jié)論:刪除節(jié)點(diǎn)一定是一個(gè)單分支節(jié)點(diǎn)或者葉子節(jié)點(diǎn)徘钥,了解這個(gè)結(jié)論對于后面我們的紅黑樹刪除過程分析會(huì)非常有用!

清楚刪除流程之后,剩下的重點(diǎn)就是如何進(jìn)行修正肢娘,以滿足紅黑樹的特性呈础,那么,哪些場景下的刪除需要進(jìn)行調(diào)整橱健,我們一起來看一下!

2.2.1而钞、刪除的節(jié)點(diǎn)為紅色

當(dāng)刪除的節(jié)點(diǎn)為紅色時(shí),這種情況直接將刪除節(jié)點(diǎn)移除拘荡,理由如下:

樹中各個(gè)節(jié)點(diǎn)的黑高沒有變化;

刪除后滿足性質(zhì)4臼节,因?yàn)椴粫?huì)出現(xiàn)紅紅相連的情況;

刪除的不可能是根節(jié)點(diǎn),因?yàn)楦?jié)點(diǎn)是黑色的;

2.2.2珊皿、刪除的節(jié)點(diǎn)為黑色

當(dāng)刪除的節(jié)點(diǎn)為黑色時(shí)网缝,因?yàn)閯h除節(jié)點(diǎn)的父節(jié)點(diǎn)失去了一個(gè)黑色子節(jié)點(diǎn),這種情況會(huì)導(dǎo)致左右子樹不平衡蟋定,因此需要進(jìn)行調(diào)整粉臊,假設(shè)x為被刪節(jié)點(diǎn)的替換節(jié)點(diǎn),也就是說:

當(dāng)被刪節(jié)點(diǎn)的左子樹為空時(shí)溢吻,x為被刪節(jié)點(diǎn)的右孩子;

當(dāng)被刪節(jié)點(diǎn)的右子樹為空時(shí)维费,x為被刪節(jié)點(diǎn)的左孩子;

當(dāng)被刪節(jié)點(diǎn)的左、右子樹都為空時(shí)促王,x是空節(jié)點(diǎn)(即刪除的是終端節(jié)點(diǎn));

當(dāng)被刪節(jié)點(diǎn)的左犀盟、右子樹都不為空時(shí),x為被刪節(jié)點(diǎn)的右子樹的最末端的左子樹蝇狼,也就是中序遍歷直接后繼的右孩子;

w為x的兄弟節(jié)點(diǎn)阅畴,有以下幾種情況!

1)x的兄弟節(jié)點(diǎn)w是紅色的

case1調(diào)整過程如下:

調(diào)整說明:因?yàn)楣?jié)點(diǎn) c 的左子樹被刪去了一個(gè)黑色節(jié)點(diǎn),導(dǎo)致節(jié)點(diǎn) c 的左子樹黑高少了1迅耘,所以節(jié)點(diǎn)c 是不平衡的贱枣〖嗍穑可以對節(jié)點(diǎn)c 進(jìn)行一次左旋,然后修改節(jié)點(diǎn)80和節(jié)點(diǎn)120的顏色纽哥。

此時(shí)钠乏,x的父親節(jié)點(diǎn)c依然不平衡,節(jié)點(diǎn)x 的兄弟節(jié)點(diǎn)w 變成黑色的!

繼續(xù)看下面的分析春塌,這種不平衡由下面的幾種情況進(jìn)行處理!

2)x的兄弟節(jié)點(diǎn)w是黑色的晓避,并且w的兩個(gè)子節(jié)點(diǎn)都是黑色的

當(dāng)x的兄弟節(jié)點(diǎn) w 是黑色的,并且w的兩個(gè)子節(jié)點(diǎn)都是黑色的時(shí)只壳,此時(shí)需要分兩種情況!

情況2.1:x的父節(jié)點(diǎn)為紅色

case2.1調(diào)整過程如下:

調(diào)整說明:在刪除節(jié)點(diǎn)后俏拱,左圖節(jié)點(diǎn) c 不平衡,節(jié)點(diǎn)c 左子樹的黑高為hl+1吼句,節(jié)點(diǎn)c 左子樹的黑高為hr+2锅必,左子樹黑高小于右子樹黑高。因此直接將節(jié)點(diǎn)c 修改為黑色惕艳,節(jié)點(diǎn) w 修改為紅色搞隐,此時(shí)的黑高又恢復(fù)如初!但是節(jié)點(diǎn)c 作為子節(jié)點(diǎn),因?yàn)楹诟邷p少尔艇,需要繼續(xù)向上回溯調(diào)整樹的黑高尔许,此時(shí)節(jié)點(diǎn)c 作為新的節(jié)點(diǎn)x。

情況2.2:x的父節(jié)點(diǎn)為黑色

case2.2調(diào)整過程如下:

調(diào)整說明:只需要將節(jié)點(diǎn) w 修改為紅色终娃,繼續(xù)向上回溯調(diào)整樹的黑高,此時(shí)節(jié)點(diǎn) c 作為新的節(jié)點(diǎn)x蒸甜。

3)x的兄弟節(jié)點(diǎn)w是黑色的棠耕,并且w的右孩子是紅色的

當(dāng)x的兄弟節(jié)點(diǎn)w是黑色的,并且w的右孩子是紅色的柠新,此時(shí)也需要分四種情況!

情況3.1:x的父節(jié)點(diǎn)為黑色窍荧,w的左孩子是黑色的

case3.1調(diào)整過程如下:

調(diào)整說明:因?yàn)閯h除節(jié)點(diǎn)導(dǎo)致節(jié)點(diǎn)c 不平衡,對節(jié)點(diǎn)c 進(jìn)行一次左旋轉(zhuǎn)恨憎,將節(jié)點(diǎn)w 的右孩子顏色修改為黑色蕊退。此時(shí)節(jié)點(diǎn)c 已經(jīng)達(dá)到平衡,同時(shí)節(jié)點(diǎn)w 也達(dá)到平衡憔恳,整棵樹已經(jīng)平衡了!

情況3.2:x的父節(jié)點(diǎn)為黑色瓤荔,w的左孩子是紅色的

case3.2調(diào)整過程如下:

調(diào)整說明:同樣的,對節(jié)點(diǎn)c 進(jìn)行一次左旋轉(zhuǎn)钥组,將節(jié)點(diǎn)w 的右孩子顏色修改為黑色输硝。此時(shí)節(jié)點(diǎn)c 已經(jīng)達(dá)到平衡,同時(shí)節(jié)點(diǎn)w 也達(dá)到平衡程梦,整棵樹已經(jīng)平衡了!

情況3.3:x的父節(jié)點(diǎn)為紅色点把,w的左孩子是黑色的

case3.3調(diào)整過程如下:

調(diào)整說明:對節(jié)點(diǎn)c 進(jìn)行一次左旋轉(zhuǎn)橘荠,將節(jié)點(diǎn) w 的右孩子顏色修改為黑色,同時(shí)將節(jié)點(diǎn)80 和節(jié)點(diǎn)100 顏色進(jìn)行互換郎逃。此時(shí)節(jié)點(diǎn)c 已經(jīng)達(dá)到平衡哥童,同時(shí)節(jié)點(diǎn)w 也達(dá)到平衡,整棵樹已經(jīng)平衡了!

情況3.4:x的父節(jié)點(diǎn)為紅色褒翰,w的左孩子是紅色的

case3.4調(diào)整過程如下:

調(diào)整說明:同樣的贮懈,對節(jié)點(diǎn)c 進(jìn)行一次左旋轉(zhuǎn),將節(jié)點(diǎn) w 的右孩子顏色修改為黑色影暴,同時(shí)將節(jié)點(diǎn)80 和節(jié)點(diǎn)100 顏色進(jìn)行互換错邦。此時(shí)節(jié)點(diǎn)c 已經(jīng)達(dá)到平衡,同時(shí)節(jié)點(diǎn)w 也達(dá)到平衡型宙,整棵樹已經(jīng)平衡了!

4)x的兄弟節(jié)點(diǎn)w是黑色的撬呢,而且w的左孩子是紅色的,w的右孩子是黑色的

當(dāng)x的兄弟節(jié)點(diǎn)w是黑色的妆兑,而且w的左孩子是紅色的魂拦,w的右孩子是黑色的,此時(shí)也需要分2種情況!

情況4.1:x的父節(jié)點(diǎn)為紅色

case4.1調(diào)整過程如下:

調(diào)整說明:對節(jié)點(diǎn)w 進(jìn)行一次右旋轉(zhuǎn)搁嗓,將節(jié)點(diǎn)90和節(jié)點(diǎn)100 進(jìn)行顏色互換芯勘,此時(shí)節(jié)點(diǎn)x 和節(jié)點(diǎn)w 的關(guān)系變成:x的兄弟節(jié)點(diǎn)w是黑色的,并且w的右孩子是紅色的腺逛。此時(shí)按照case3.3情況進(jìn)行處理即可!

情況4.2:x的父節(jié)點(diǎn)為黑色

case4.2調(diào)整過程如下:

調(diào)整說明:同樣的荷愕,對節(jié)點(diǎn)w 進(jìn)行一次右旋轉(zhuǎn),將節(jié)點(diǎn)90和節(jié)點(diǎn)100進(jìn)行顏色互換棍矛,此時(shí)節(jié)點(diǎn)x 和節(jié)點(diǎn)w 的關(guān)系變成:x的兄弟節(jié)點(diǎn)w是黑色的安疗,并且w的右孩子是紅色的。此時(shí)按照case3.1情況進(jìn)行處理即可!

刪除的場景相比插入要多很多够委,情況也比較復(fù)雜荐类,但是基本有自己的規(guī)律,我們只需要把規(guī)律總結(jié)出來茁帽,然后就可以用邏輯代碼來實(shí)現(xiàn)!

需要注意的是:此次節(jié)點(diǎn)x 位于節(jié)點(diǎn)c 的左子樹玉罐,如果位于右子樹,操作與之對稱!

可以得出如下結(jié)論:對刪除節(jié)點(diǎn)后的調(diào)整所做的旋轉(zhuǎn)操作不會(huì)超過3次!

三潘拨、代碼實(shí)踐

接下來吊输,我們從代碼層面來定義一下樹的實(shí)體結(jié)構(gòu),如下:

public?class?RBTNode<E?extends?Comparable<E>>?{?

????/**節(jié)點(diǎn)顏色*/?

????boolean?color;?

????/**節(jié)點(diǎn)關(guān)鍵字*/?

Ekey;?

????/**父節(jié)點(diǎn)*/?

????RBTNode<E>?parent;?

????/**左子節(jié)點(diǎn)*/?

RBTNodeleft;?

????/**右子節(jié)點(diǎn)*/?

RBTNoderight;?

public?RBTNode(E?key,?boolean?color,?RBTNode<E>?parent,?RBTNode<E>?left,?RBTNode<E>?right)?{?

this.key?=?key;?

????????this.color?=?color;?

????????this.parent?=?parent;?

this.left?=?left;?

this.right?=?right;?

????}?

????@Override?

public?String?toString()?{?

return?"RBTNode{"?+?

"color="?+?(color???"red":"black")?+?

",?key="?+?key?+?

'}';?

????}?

}?

我們創(chuàng)建一個(gè)算法類RBTSolution战秋,完整實(shí)現(xiàn)如下:

public?class?RBTSolution<E?extends?Comparable<E>>?{?

????/**根節(jié)點(diǎn)*/?

public?RBTNode<E>?root;?

????/**?

*?顏色常量false表示紅色璧亚,true表示黑色?

?????*/?

privatestatic?final?boolean?RED?=?false;?

privatestatic?final?boolean?BLACK?=?true;?

????/*?

*?新建結(jié)點(diǎn)(key),并將其插入到紅黑樹中?

*?參數(shù)說明:key?插入結(jié)點(diǎn)的鍵值?

?????*/?

public?void?insert(E?key)?{?

System.out.println("插入["?+?key?+?"]:");?

RBTNode?node=new?RBTNode(key,?BLACK,null,null,null);?

????????//?如果新建結(jié)點(diǎn)失敗,則返回癣蟋。?

if?(node?!=null)?

insert(node);?

????}?

????/*?

?????*?將結(jié)點(diǎn)插入到紅黑樹中?

?????*?

?????*?參數(shù)說明:?

?????*?????node?插入的結(jié)點(diǎn)????????//?對應(yīng)《算法導(dǎo)論》中的node?

?????*/?

private?voidinsert(RBTNode<E>?node)?{?

int?cmp;?

RBTNode?y?=null;?

????????RBTNode<E>?x?=?this.root;?

????????//?1.?將紅黑樹當(dāng)作一顆二叉查找樹透硝,將節(jié)點(diǎn)添加到二叉查找樹中。?

while?(x?!=null)?{?

????????????y?=?x;?

cmp?=?node.key.compareTo(x.key);?

????????????if?(cmp?<?0)?

x?=?x.left;?

else?

x?=?x.right;?

????????}?

????????node.parent?=?y;?

if?(y!=null)?{?

cmp?=?node.key.compareTo(y.key);?

????????????if?(cmp?<?0)?

y.left?=?node;?

else?

y.right?=?node;?

}else?{?

????????????this.root?=?node;?

????????}?

????????//?2.?設(shè)置節(jié)點(diǎn)的顏色為紅色?

????????node.color?=?RED;?

????????//?3.?將它重新修正為一顆二叉查找樹?

????????insertFixUp(node);?

????}?

????/*?

?????*?紅黑樹插入修正函數(shù)?

?????*?

?????*?在向紅黑樹中插入節(jié)點(diǎn)之后(失去平衡)疯搅,再調(diào)用該函數(shù)濒生;?

?????*?目的是將它重新塑造成一顆紅黑樹。?

?????*?

?????*?參數(shù)說明:?

?????*?????node?插入的結(jié)點(diǎn)????????//?對應(yīng)《算法導(dǎo)論》中的z?

?????*/?

????private?void?insertFixUp(RBTNode<E>?node)?{?

????????RBTNode<E>?parent,?gparent;?

????????//?若“父節(jié)點(diǎn)存在幔欧,并且父節(jié)點(diǎn)的顏色是紅色”?

while?(((parent?=?parentOf(node))!=null)?&&?isRed(parent))?{?

????????????gparent?=?parentOf(parent);?

????????????//若“父節(jié)點(diǎn)”是“祖父節(jié)點(diǎn)的左孩子”?

if?(parent?==?gparent.left)?{?

//Case?1條件:叔叔節(jié)點(diǎn)是紅色?

RBTNode?uncle?=?gparent.right;?

if?((uncle!=null)?&&?isRed(uncle))?{?

????????????????????setBlack(uncle);?

????????????????????setBlack(parent);?

????????????????????setRed(gparent);?

????????????????????node?=?gparent;?

continue;?

????????????????}?

//Case?3條件:叔叔是黑色罪治,且當(dāng)前節(jié)點(diǎn)是右孩子?

if?(parent.right?==?node)?{?

????????????????????RBTNode<E>?tmp;?

????????????????????leftRotate(parent);?

????????????????????tmp?=?parent;?

????????????????????parent?=?node;?

????????????????????node?=?tmp;?

????????????????}?

//Case?2條件:叔叔是黑色,且當(dāng)前節(jié)點(diǎn)是左孩子礁蔗。?

????????????????setBlack(parent);?

????????????????setRed(gparent);?

????????????????rightRotate(gparent);?

}else?{????//若“z的父節(jié)點(diǎn)”是“z的祖父節(jié)點(diǎn)的右孩子”?

//Case?1條件:叔叔節(jié)點(diǎn)是紅色?

RBTNode?uncle?=?gparent.left;?

if?((uncle!=null)?&&?isRed(uncle))?{?

????????????????????setBlack(uncle);?

????????????????????setBlack(parent);?

????????????????????setRed(gparent);?

????????????????????node?=?gparent;?

continue;?

????????????????}?

//Case?2條件:叔叔是黑色觉义,且當(dāng)前節(jié)點(diǎn)是左孩子?

if?(parent.left?==?node)?{?

????????????????????RBTNode<E>?tmp;?

????????????????????rightRotate(parent);?

????????????????????tmp?=?parent;?

????????????????????parent?=?node;?

????????????????????node?=?tmp;?

????????????????}?

//Case?3條件:叔叔是黑色,且當(dāng)前節(jié)點(diǎn)是右孩子浴井。?

????????????????setBlack(parent);?

????????????????setRed(gparent);?

????????????????leftRotate(gparent);?

????????????}?

????????}?

????????//?將根節(jié)點(diǎn)設(shè)為黑色?

????????setBlack(this.root);?

????}?

????/*?

?????*?刪除結(jié)點(diǎn)(z)晒骇,并返回被刪除的結(jié)點(diǎn)?

?????*?

?????*?參數(shù)說明:?

?????*?????tree?紅黑樹的根結(jié)點(diǎn)?

?????*?????z?刪除的結(jié)點(diǎn)?

?????*/?

public?void?remove(E?key)?{?

????????RBTNode<E>?node;?

if?((node?=?search(root,key))?!=?null)?

????????????remove(node);?

????}?

????/*?

?????*?刪除結(jié)點(diǎn)(node),并返回被刪除的結(jié)點(diǎn)?

?????*?

?????*?參數(shù)說明:?

?????*?????node?刪除的結(jié)點(diǎn)?

?????*/?

????private?void?remove(RBTNode<E>?node)?{?

????????RBTNode<E>?child,?parent;?

????????boolean?color;?

//?被刪除節(jié)點(diǎn)的"左右孩子都不為空"的情況磺浙。?

if?(?(node.left!=null)?&&?(node.right!=null)?)?{?

//?被刪節(jié)點(diǎn)的后繼節(jié)點(diǎn)洪囤。(稱為"取代節(jié)點(diǎn)")?

//?用它來取代"被刪節(jié)點(diǎn)"的位置,然后再將"被刪節(jié)點(diǎn)"去掉撕氧。?

RBTNodereplace?=?node;?

????????????//?獲取后繼節(jié)點(diǎn)?

replace?=?replace.right;?

while?(replace.left?!=?null)?

replace?=?replace.left;?

//"node節(jié)點(diǎn)"不是根節(jié)點(diǎn)(只有根節(jié)點(diǎn)不存在父節(jié)點(diǎn))?

if?(parentOf(node)!=null)?{?

if?(parentOf(node).left?==?node)?

parentOf(node).left?=?replace;?

else?

parentOf(node).right?=?replace;?

}else?{?

//"node節(jié)點(diǎn)"是根節(jié)點(diǎn)瘤缩,更新根節(jié)點(diǎn)。?

this.root?=replace;?

????????????}?

//?child是"取代節(jié)點(diǎn)"的右孩子伦泥,也是需要"調(diào)整的節(jié)點(diǎn)"剥啤。?

//"取代節(jié)點(diǎn)"肯定不存在左孩子!因?yàn)樗且粋€(gè)后繼節(jié)點(diǎn)不脯。?

child?=replace.right;?

parent?=?parentOf(replace);?

//?保存"取代節(jié)點(diǎn)"的顏色?

color?=?colorOf(replace);?

//"被刪除節(jié)點(diǎn)"是"它的后繼節(jié)點(diǎn)的父節(jié)點(diǎn)"?

????????????if?(parent?==?node)?{?

parent?=replace;?

}else?{?

????????????????//?child不為空?

if?(child!=null)?

????????????????????setParent(child,?parent);?

parent.left?=?child;?

replace.right?=?node.right;?

setParent(node.right,?replace);?

????????????}?

replace.parent?=?node.parent;?

replace.color?=?node.color;?

replace.left?=?node.left;?

node.left.parent?=?replace;?

????????????if?(color?==?BLACK)?

????????????????removeFixUp(child,?parent);?

node?=null;?

return?;?

????????}?

if?(node.left?!=null)?{?

child?=?node.left;?

}else?{?

child?=?node.right;?

????????}?

????????parent?=?node.parent;?

//?保存"取代節(jié)點(diǎn)"的顏色?

????????color?=?node.color;?

if?(child!=null)?

????????????child.parent?=?parent;?

//"node節(jié)點(diǎn)"不是根節(jié)點(diǎn)?

if?(parent!=null)?{?

if?(parent.left?==?node)?

parent.left?=?child;?

else?

parent.right?=?child;?

}else?{?

????????????this.root?=?child;?

????????}?

????????if?(color?==?BLACK)?

????????????removeFixUp(child,?parent);?

node?=null;?

????}?

????/*?

?????*?紅黑樹刪除修正函數(shù)?

?????*?

?????*?在從紅黑樹中刪除插入節(jié)點(diǎn)之后(紅黑樹失去平衡)铐殃,再調(diào)用該函數(shù);?

?????*?目的是將它重新塑造成一顆紅黑樹跨新。?

?????*?

?????*?參數(shù)說明:?

?????*?????node?待修正的節(jié)點(diǎn)?

?????*/?

????private?void?removeFixUp(RBTNode<E>?node,?RBTNode<E>?parent)?{?

????????RBTNode<E>?other;?

while?((node==null?||?isBlack(node))?&&?(node?!=?this.root))?{?

if?(parent.left?==?node)?{?

other?=?parent.right;?

????????????????if?(isRed(other))?{?

//Case?1:?x的兄弟w是紅色的?

????????????????????setBlack(other);?

????????????????????setRed(parent);?

????????????????????leftRotate(parent);?

other?=?parent.right;?

????????????????}?

if?((other.left==null?||?isBlack(other.left))?&&?

(other.right==null?||?isBlack(other.right)))?{?

//Case?2:?x的兄弟w是黑色,且w的倆個(gè)孩子也都是黑色的?

????????????????????setRed(other);?

????????????????????node?=?parent;?

????????????????????parent?=?parentOf(node);?

}else?{?

if?(other.right==null?||?isBlack(other.right))?{?

//Case?4:?x的兄弟w是黑色的坏逢,并且w的左孩子是紅色域帐,右孩子為黑色。?

setBlack(other.left);?

????????????????????????setRed(other);?

????????????????????????rightRotate(other);?

other?=?parent.right;?

????????????????????}?

//Case?3:?x的兄弟w是黑色的是整;并且w的右孩子是紅色的肖揣,左孩子任意顏色。?

????????????????????setColor(other,?colorOf(parent));?

????????????????????setBlack(parent);?

setBlack(other.right);?

????????????????????leftRotate(parent);?

????????????????????node?=?this.root;?

????????????????????break;?

????????????????}?

}else?{?

other?=?parent.left;?

????????????????if?(isRed(other))?{?

//Case?1:?x的兄弟w是紅色的?

????????????????????setBlack(other);?

????????????????????setRed(parent);?

????????????????????rightRotate(parent);?

other?=?parent.left;?

????????????????}?

if?((other.left==null?||?isBlack(other.left))?&&?

(other.right==null?||?isBlack(other.right)))?{?

//Case?2:?x的兄弟w是黑色浮入,且w的倆個(gè)孩子也都是黑色的?

????????????????????setRed(other);?

????????????????????node?=?parent;?

????????????????????parent?=?parentOf(node);?

}else?{?

if?(other.left==null?||?isBlack(other.left))?{?

//Case?4:?x的兄弟w是黑色的龙优,并且w的左孩子是紅色,右孩子為黑色事秀。?

setBlack(other.right);?

????????????????????????setRed(other);?

????????????????????????leftRotate(other);?

other?=?parent.left;?

????????????????????}?

//Case?3:?x的兄弟w是黑色的彤断;并且w的右孩子是紅色的野舶,左孩子任意顏色。?

????????????????????setColor(other,?colorOf(parent));?

????????????????????setBlack(parent);?

setBlack(other.left);?

????????????????????rightRotate(parent);?

????????????????????node?=?this.root;?

????????????????????break;?

????????????????}?

????????????}?

????????}?

if?(node!=null)?

????????????setBlack(node);?

????}?

????/**?

?????*?查詢節(jié)點(diǎn)?

*?@paramkey?

*?@return?

?????*/?

public?RBTNode<E>?search(E?key)?{?

return?search(root,?key);?

????}?

????/*?

*?(遞歸實(shí)現(xiàn))查找"紅黑樹x"中鍵值為key的節(jié)點(diǎn)?

?????*/?

private?RBTNode?search(RBTNode?x,?Ekey)?{?

if?(x==null)?

return?x;?

int?cmp?=?key.compareTo(x.key);?

????????if?(cmp?<?0)?

return?search(x.left,?key);?

else?if?(cmp?>?0)?

return?search(x.right,?key);?

else?

return?x;?

????}?

????/**?

?????*?中序遍歷?

?????*?@param?node?

?????*/?

public?void?middleTreeIterator(RBTNode<E>?node){?

if(node?!=null){?

middleTreeIterator(node.left);//遍歷當(dāng)前節(jié)點(diǎn)左子樹?

System.out.println("key:"?+?node.key);?

middleTreeIterator(node.right);//遍歷當(dāng)前節(jié)點(diǎn)右子樹?

????????}?

????}?

????private?RBTNode<E>?parentOf(RBTNode<E>?node)?{?

return?node!=null???node.parent?:?null;?

????}?

????private?boolean?colorOf(RBTNode<E>?node)?{?

return?node!=null???node.color?:?BLACK;?

????}?

????private?boolean?isRed(RBTNode<E>?node)?{?

return?((node!=null)&&(node.color==RED))???true?:?false;?

????}?

????private?boolean?isBlack(RBTNode<E>?node)?{?

return?!isRed(node);?

????}?

????private?void?setBlack(RBTNode<E>?node)?{?

if?(node!=null)?

????????????node.color?=?BLACK;?

????}?

????private?void?setRed(RBTNode<E>?node)?{?

if?(node!=null)?

????????????node.color?=?RED;?

????}?

????private?void?setParent(RBTNode<E>?node,?RBTNode<E>?parent)?{?

if?(node!=null)?

????????????node.parent?=?parent;?

????}?

????private?void?setColor(RBTNode<E>?node,?boolean?color)?{?

if?(node!=null)?

????????????node.color?=?color;?

????}?

????/*?

?????*?對紅黑樹的節(jié)點(diǎn)(x)進(jìn)行左旋轉(zhuǎn)?

?????*?

?????*?左旋示意圖(對節(jié)點(diǎn)x進(jìn)行左旋):?

?????*??????px??????????????????????????????px?

?????*?????/???????????????????????????????/?

?????*????x???????????????????????????????y?

*???/??\--(左旋)-.???????????/?\????????????????#?

?????*??lx???y??????????????????????????x??ry?

?????*?????/???\???????????????????????/??\?

?????*????ly???ry?????????????????????lx??ly?

?????*?

?????*?

?????*/?

????private?void?leftRotate(RBTNode<E>?x)?{?

????????//?設(shè)置x的右孩子為y?

RBTNode?y?=?x.right;?

????????//?將?“y的左孩子”?設(shè)為?“x的右孩子”宰衙;?

????????//?如果y的左孩子非空平道,將?“x”?設(shè)為?“y的左孩子的父親”?

x.right?=?y.left;?

if?(y.left?!=?null)?

y.left.parent?=?x;?

????????//?將?“x的父親”?設(shè)為?“y的父親”?

????????y.parent?=?x.parent;?

if?(x.parent?==null)?{?

????????????this.root?=?y;????????????//?如果?“x的父親”?是空節(jié)點(diǎn),則將y設(shè)為根節(jié)點(diǎn)?

}else?{?

if?(x.parent.left?==?x)?

x.parent.left?=?y;????//?如果?x是它父節(jié)點(diǎn)的左孩子供炼,則將y設(shè)為“x的父節(jié)點(diǎn)的左孩子”?

else?

x.parent.right?=?y;????//?如果?x是它父節(jié)點(diǎn)的左孩子一屋,則將y設(shè)為“x的父節(jié)點(diǎn)的左孩子”?

????????}?

????????//?將?“x”?設(shè)為?“y的左孩子”?

y.left?=?x;?

????????//?將?“x的父節(jié)點(diǎn)”?設(shè)為?“y”?

????????x.parent?=?y;?

????}?

????/*?

?????*?對紅黑樹的節(jié)點(diǎn)(y)進(jìn)行右旋轉(zhuǎn)?

?????*?

?????*?右旋示意圖(對節(jié)點(diǎn)y進(jìn)行左旋):?

?????*????????????py???????????????????????????????py?

?????*???????????/????????????????????????????????/?

?????*??????????y????????????????????????????????x?

*?????????/??\--(右旋)-.????????????/??\?????????????????????#?

?????*????????x???ry???????????????????????????lx???y?

?????*???????/?\???????????????????????????????????/?\???????????????????#?

?????*??????lx??rx????????????????????????????????rx??ry?

?????*?

?????*/?

????private?void?rightRotate(RBTNode<E>?y)?{?

????????//?設(shè)置x是當(dāng)前節(jié)點(diǎn)的左孩子。?

RBTNode?x?=?y.left;?

????????//?將?“x的右孩子”?設(shè)為?“y的左孩子”袋哼;?

//?如果"x的右孩子"不為空的話冀墨,將?“y”?設(shè)為?“x的右孩子的父親”?

y.left?=?x.right;?

if?(x.right?!=?null)?

x.right.parent?=?y;?

????????//?將?“y的父親”?設(shè)為?“x的父親”?

????????x.parent?=?y.parent;?

if?(y.parent?==null)?{?

????????????this.root?=?x;????????????//?如果?“y的父親”?是空節(jié)點(diǎn),則將x設(shè)為根節(jié)點(diǎn)?

}else?{?

if?(y?==?y.parent.right)?

y.parent.right?=?x;????//?如果?y是它父節(jié)點(diǎn)的右孩子涛贯,則將x設(shè)為“y的父節(jié)點(diǎn)的右孩子”?

else?

y.parent.left?=?x;????//?(y是它父節(jié)點(diǎn)的左孩子)?將x設(shè)為“x的父節(jié)點(diǎn)的左孩子”?

????????}?

????????//?將?“y”?設(shè)為?“x的右孩子”?

x.right?=?y;?

????????//?將?“y的父節(jié)點(diǎn)”?設(shè)為?“x”?

????????y.parent?=?x;?

????}?

}?

測試代碼诽嘉,如下:

public?class?RBTClient?{?

public?static?void?main(String[]?args)?{?

RBTSolution

????????//插入節(jié)點(diǎn)?

System.out.println("========插入元素========");?

tree.insert(new?Integer(100));?

tree.insert(new?Integer(85));?

tree.insert(new?Integer(120));?

tree.insert(new?Integer(60));?

tree.insert(new?Integer(90));?

tree.insert(new?Integer(80));?

tree.insert(new?Integer(130));?

System.out.println("========中序遍歷元素========");?

????????//中序遍歷?

????????tree.middleTreeIterator(tree.root);?

System.out.println("========查找key為100的元素========");?

????????//查詢節(jié)點(diǎn)?

RBTNode

System.out.println("查找結(jié)果:"?+?searchResult);?

System.out.println("========刪除key為90的元素========");?

????????//刪除節(jié)點(diǎn)?

????????tree.remove(90);?

System.out.println("========再次中序遍歷元素========");?

????????//中序遍歷?

????????tree.middleTreeIterator(tree.root);?

????}?

}?

輸出結(jié)果如下:

========插入元素========?

插入[100]:?

插入[85]:?

插入[120]:?

插入[60]:?

插入[90]:?

插入[80]:?

插入[130]:?

========中序遍歷元素========?

key:60?

key:80?

key:85?

key:90?

key:100?

key:120?

key:130?

========查找key為100的元素========?

查找結(jié)果:RBTNode{color=red,key=100}?

========刪除key為90的元素========?

========再次中序遍歷元素========?

key:60?

key:80?

key:85?

key:100?

key:120?

key:130?

四、總結(jié)

本篇文章疫蔓,前前后后寫了大概一個(gè)星期含懊,尤其是刪除邏輯,比較復(fù)雜衅胀,如果有理解不對的地方岔乔,歡迎網(wǎng)友們指出!

以下是紅黑樹總結(jié):

1、紅黑樹是一個(gè)基本平衡的二叉樹滚躯,在查詢方面雏门,與二叉查找樹思路相同;在插入方面,單次回溯不會(huì)超過2次旋轉(zhuǎn);在刪除方面掸掏,單次回溯不會(huì)超過3次旋轉(zhuǎn)!

2茁影、相比于平衡二叉樹,紅黑樹在查詢丧凤、插入方面募闲,效率差不多;在刪除方面,平衡二叉樹最多需要log(n)次變化愿待,以達(dá)到嚴(yán)格平衡浩螺,而紅黑樹最多不會(huì)超過3次變化,因此效率要高于平衡二叉樹!

3仍侥、在實(shí)際應(yīng)用中要出,很多語言都實(shí)現(xiàn)了紅黑樹的數(shù)據(jù)結(jié)構(gòu),比如 Java 中的 TreeMap农渊、 TreeSet患蹂,以及 jdk1.8 中的 HashMap!

以上內(nèi)容都是我自己的一些感想,分享出來歡迎大家指正,順便求一波關(guān)注传于,有問題的或者更好的想法的小伙伴可以評論私信我哦~或者點(diǎn)擊Java分享交流群一起聊天啊

作者:炸雞可樂

來源:Java極客技術(shù)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末囱挑,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子格了,更是在濱河造成了極大的恐慌看铆,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盛末,死亡現(xiàn)場離奇詭異弹惦,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)悄但,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進(jìn)店門棠隐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人檐嚣,你說我怎么就攤上這事助泽。” “怎么了嚎京?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵嗡贺,是天一觀的道長。 經(jīng)常有香客問我鞍帝,道長诫睬,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任帕涌,我火速辦了婚禮摄凡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蚓曼。我一直安慰自己亲澡,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布纫版。 她就那樣靜靜地躺著床绪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪其弊。 梳的紋絲不亂的頭發(fā)上会涎,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天,我揣著相機(jī)與錄音瑞凑,去河邊找鬼。 笑死概页,一個(gè)胖子當(dāng)著我的面吹牛籽御,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼技掏,長吁一口氣:“原來是場噩夢啊……” “哼铃将!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起哑梳,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤劲阎,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后鸠真,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體悯仙,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年吠卷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了锡垄。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,424評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡祭隔,死狀恐怖货岭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情疾渴,我是刑警寧澤千贯,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站搞坝,受9級特大地震影響搔谴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜瞄沙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一己沛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧距境,春花似錦申尼、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至诬滩,卻和暖如春霹粥,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背疼鸟。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工后控, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人空镜。 一個(gè)月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓浩淘,卻偏偏與公主長得像捌朴,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子张抄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 紅黑樹是平衡二叉查找樹的一種砂蔽。為了深入理解紅黑樹,我們需要從二叉查找樹開始講起署惯。 BST 二叉查找樹(Binary...
    kanehe閱讀 1,378評論 0 8
  • 紅黑樹為一棵二叉搜索樹左驾,它為每個(gè)結(jié)點(diǎn)增加一個(gè)變量存儲(chǔ)結(jié)點(diǎn)顏色,利用結(jié)點(diǎn)顏色對樹的形狀進(jìn)行約束极谊,使其近似平衡(并非完...
    LRC_cheng閱讀 482評論 0 1
  • - 簡介 紅黑樹(Red Black Tree) 是一種近似平衡二叉查找樹诡右,具有基本二叉樹的所有特性的同時(shí),還...
    廈門張明爽閱讀 550評論 0 1
  • 最近花了些時(shí)間重拾數(shù)據(jù)結(jié)構(gòu)的基礎(chǔ)知識(shí)怀酷,先嘗試了紅黑樹稻爬,花了大半個(gè)月的時(shí)間研究其原理和實(shí)現(xiàn),下面是學(xué)習(xí)到的知識(shí)和一些...
    hoohack閱讀 1,523評論 8 30
  • 0.目錄 1.算法導(dǎo)論的紅黑樹本質(zhì)上是2-3-4樹 2.紅黑樹的結(jié)構(gòu)和性質(zhì) 3.紅黑樹的插入 4.紅黑樹的刪除 5...
    王偵閱讀 2,485評論 1 2