紅黑樹介紹

概述

二叉搜索樹是優(yōu)化搜索效率最常用的數(shù)據(jù)結(jié)構(gòu)充边,時(shí)間復(fù)雜度為O(h),其中h是樹的高度蘑辑⊙蠡可以看出,樹的高度是影響搜索效率的關(guān)鍵因素洋魂。在樹退化為一個(gè)鏈表(節(jié)點(diǎn)都在左或都在右)绷旗,搜索效率也就退化為O(n)。為了防止這種情況的出現(xiàn)平衡二叉搜索樹出現(xiàn)副砍,本文所介紹的紅黑樹就是一種特殊的"平衡"二叉樹刁标,因?yàn)榧t黑樹只能保證沒有一條路徑會(huì)比其他路徑長出2倍,所以并不是嚴(yán)格意義上的平衡樹址晕。但是這個(gè)性質(zhì)卻能保證最壞情況下搜索操作的復(fù)雜度是O(h)。

定義及性質(zhì)

紅黑樹每個(gè)節(jié)點(diǎn)包含color顿锰,key谨垃,left,right和p硼控,如果一個(gè)節(jié)點(diǎn)沒有子節(jié)點(diǎn)或者父節(jié)點(diǎn)刘陶,那么該節(jié)點(diǎn)響應(yīng)指針的屬性值為NIL,我們將NIL視為指向也節(jié)點(diǎn)的指針牢撼。一個(gè)紅黑樹必須滿足一下性質(zhì):
(1) 每個(gè)節(jié)點(diǎn)只能是紅色或者黑色匙隔;
(2) 根節(jié)點(diǎn)是黑色;
(3) 每個(gè)葉節(jié)點(diǎn)(NIL)是黑色熏版;
(4) 紅節(jié)點(diǎn)的子節(jié)點(diǎn)一定是黑色纷责;
(5) 對(duì)于每個(gè)節(jié)點(diǎn)捍掺,從該節(jié)點(diǎn)到到期所有后代也節(jié)點(diǎn)的路徑上,均包含相同數(shù)目的黑節(jié)點(diǎn)再膳。

插入操作

紅黑樹的插入操作和一般的二叉搜索樹一樣挺勿,但是插入節(jié)點(diǎn)后需要進(jìn)行調(diào)整,以滿足紅黑樹的以上五個(gè)性質(zhì)喂柒。我們知道JDK8中的HashMap和ConcurrentHashMap在桶中鏈表長度大于等于8時(shí)會(huì)將鏈表轉(zhuǎn)換為紅黑樹以提高搜索效率不瓶,下面我們通過這塊代碼來了解下具體調(diào)整算法。下面代碼涉及兩個(gè)操作:左旋和右旋灾杰,大家可以認(rèn)為對(duì)x節(jié)點(diǎn)左旋就是用x節(jié)點(diǎn)的右子節(jié)點(diǎn)y代替x蚊丐,并且x成為y的左子節(jié)點(diǎn);對(duì)x節(jié)點(diǎn)進(jìn)行右旋就是用x的左子節(jié)點(diǎn)y代替x并且x成y的右子節(jié)點(diǎn)艳吠。


左旋右旋.png
static <K,V> ConcurrentHashMap.TreeNode<K,V> balanceInsertion(ConcurrentHashMap.TreeNode<K,V> root,
                                                                  ConcurrentHashMap.TreeNode<K,V> x) {
        //1.所有新插入的節(jié)點(diǎn)顏色都是紅色
        x.red = true;
        for (ConcurrentHashMap.TreeNode<K,V> xp, xpp, xppl, xppr;;) {
            //如果節(jié)點(diǎn)是根節(jié)點(diǎn)麦备,那么直接將該節(jié)點(diǎn)置為黑色,結(jié)束
            if ((xp = x.parent) == null) {
                x.red = false;
                return x;
            }
            //如果x的父節(jié)點(diǎn)是黑色讲竿,符合紅黑樹定義直接返回泥兰。
            else if (!xp.red || (xpp = xp.parent) == null)
                return root;
            //2.插入的節(jié)點(diǎn)x的父節(jié)點(diǎn)是紅色并且是左子樹
            if (xp == (xppl = xpp.left)) {
                //2.1查看x的叔叔節(jié)點(diǎn)的顏色,如果是紅色题禀,那么將x的父節(jié)點(diǎn)鞋诗,叔節(jié)點(diǎn)置為黑色,爺爺節(jié)點(diǎn)置為紅色迈嘹,并將要調(diào)整的節(jié)點(diǎn)置為爺爺節(jié)點(diǎn)
                if ((xppr = xpp.right) != null && xppr.red) {
                    xppr.red = false;
                    xp.red = false;
                    xpp.red = true;
                    x = xpp;
                }
                else {
                  //2.2 x節(jié)點(diǎn)的叔叔節(jié)點(diǎn)是黑色削彬,且x是右子樹,那么將x的父節(jié)點(diǎn)進(jìn)行右旋
                    if (x == xp.right) {
                        root = rotateLeft(root, x = xp);
                        xpp = (xp = x.parent) == null ? null : xp.parent;
                    }
                  //2.3 x節(jié)點(diǎn)的叔叔節(jié)點(diǎn)是黑色秀仲,且x是左子樹融痛,將父節(jié)點(diǎn)置為黑色,爺爺節(jié)點(diǎn)置為紅色并將爺爺節(jié)點(diǎn)進(jìn)行右旋
                    if (xp != null) {
                        xp.red = false;
                        if (xpp != null) {
                            xpp.red = true;
                            root = rotateRight(root, xpp);
                        }
                    }
                }
            }
           //3.插入節(jié)點(diǎn)x父節(jié)點(diǎn)是紅色并且是右子樹神僵,處理過程與情況2相同
            else {
                if (xppl != null && xppl.red) {
                    xppl.red = false;
                    xp.red = false;
                    xpp.red = true;
                    x = xpp;
                }
                else {
                    if (x == xp.left) {
                        root = rotateRight(root, x = xp);
                        xpp = (xp = x.parent) == null ? null : xp.parent;
                    }
                    if (xp != null) {
                        xp.red = false;
                        if (xpp != null) {
                            xpp.red = true;
                            root = rotateLeft(root, xpp);
                        }
                    }
                }
            }
        }
    }

刪除操作

相對(duì)于紅黑樹的插入操作雁刷,刪除操作比較麻煩,我們按照被刪除節(jié)點(diǎn)x的顏色和x的子節(jié)點(diǎn)情況分類如下保礼。為了更容易理解在有的情況下我們給出了操作圖沛励,紅色代表紅節(jié)點(diǎn),黑色代表黑節(jié)點(diǎn)炮障,白色代表不知道該節(jié)點(diǎn)是紅還是黑目派,并且為了簡(jiǎn)化圖示我們沒有將NIL節(jié)點(diǎn)畫出,大家可以認(rèn)為所有頁節(jié)點(diǎn)都隱含一個(gè)黑色節(jié)點(diǎn)NIL胁赢。
(1) x為紅色并且x沒有子節(jié)點(diǎn)
這種情況下較為簡(jiǎn)單企蹭,直接刪除x不會(huì)破壞紅黑樹上述五個(gè)限制。
(2) x為紅色并且x有一個(gè)子節(jié)點(diǎn)
這種情況實(shí)際是不存在的,因?yàn)槿绻鹸是紅色谅摄,其子節(jié)點(diǎn)必定是黑色徒河,而左右子樹的黑高就不相等。
(3) x為黑色并且x有一個(gè)子節(jié)點(diǎn)
這種情況下螟凭,x的這個(gè)子節(jié)點(diǎn)y必定是紅色虚青,因此只需要將y替換為x并且將y置為黑色即可。具體如下圖:

image

(4) x為紅色并且x有兩個(gè)子節(jié)點(diǎn)

這種情況下螺男,可以找到x節(jié)點(diǎn)的后繼節(jié)點(diǎn)s棒厘,s的情況可能有以下兩種:

image

刪除x時(shí)可以用s替換為x,并將s的顏色設(shè)置為x的顏色下隧。此時(shí)刪除x相當(dāng)于刪除s奢人。如果s沒有子節(jié)點(diǎn)則這種情況轉(zhuǎn)換為(1)或者(6),如果s有子節(jié)點(diǎn)淆院,這種情況轉(zhuǎn)換為(2)或者(3)何乎。我們以比較負(fù)責(zé)的情況x的后繼節(jié)點(diǎn)有一個(gè)子孩子并且s為黑色為例給出刪除示例:
image

(5) x為黑色并且x有兩個(gè)子節(jié)點(diǎn)

這種情況同(4)的處理機(jī)制一樣。

(6) x為黑色并且x沒有子節(jié)點(diǎn)

這種情況比較復(fù)雜土辩,因?yàn)閯h除黑節(jié)點(diǎn)會(huì)破壞黑高支救。可以分為如下幾種情況討論:

(a). x節(jié)點(diǎn)的兄弟節(jié)點(diǎn)b有一個(gè)與其方向一致的紅色子節(jié)點(diǎn)s

此時(shí)將父節(jié)點(diǎn)進(jìn)行旋轉(zhuǎn)拷淘,并將刪除節(jié)點(diǎn)的黑色轉(zhuǎn)移到父節(jié)點(diǎn)各墨,而父節(jié)點(diǎn)原來位置的顏色保持不變。

image

(b). x節(jié)點(diǎn)的兄弟節(jié)點(diǎn)b有一個(gè)與其方向不一致的紅色節(jié)點(diǎn)s

此時(shí)首先通過旋轉(zhuǎn)操作轉(zhuǎn)為情況(a)启涯,再按照(a)進(jìn)行處理贬堵。

image

(c) 兄弟節(jié)點(diǎn)為黑色,且兄弟節(jié)點(diǎn)無紅色子節(jié)點(diǎn)

如果父節(jié)點(diǎn)是紅色结洼,那么將父節(jié)點(diǎn)置為黑色黎做,兄弟節(jié)點(diǎn)置為紅色即可解決問題。

image

如果父節(jié)點(diǎn)是黑色松忍,那么確實(shí)沒有紅節(jié)點(diǎn)可以作為黑節(jié)點(diǎn)轉(zhuǎn)移的節(jié)點(diǎn)蒸殿,只能對(duì)兄弟節(jié)點(diǎn)重新設(shè)置顏色,已平衡被刪除節(jié)點(diǎn)側(cè)減小的黑高鸣峭,并即將節(jié)點(diǎn)一直上移知道根節(jié)點(diǎn)使得所有的路徑的黑高都減1伟桅。

(d) 兄弟節(jié)點(diǎn)為紅色

這種情況可以通過旋轉(zhuǎn)父節(jié)點(diǎn),轉(zhuǎn)換為父節(jié)點(diǎn)為紅色叽掘,兄弟節(jié)點(diǎn)為黑色的情況處理。

從以上的刪除過程可以看出玖雁,如果刪除節(jié)點(diǎn)是紅色節(jié)點(diǎn)更扁,不會(huì)破會(huì)黑高,可以直接刪除。如果刪除的節(jié)點(diǎn)是黑色節(jié)點(diǎn)浓镜,并且刪除的節(jié)點(diǎn)的父節(jié)點(diǎn)或者兄弟節(jié)點(diǎn)溃列,兄弟節(jié)點(diǎn)的子節(jié)點(diǎn)存在紅色節(jié)點(diǎn),那么可以通過旋轉(zhuǎn)操作即將紅色節(jié)點(diǎn)旋轉(zhuǎn)到被刪除節(jié)點(diǎn)側(cè)并置為黑色保持黑高不改變膛薛。如果以上節(jié)點(diǎn)都不存在紅色節(jié)點(diǎn)听隐,那么只能向上回溯整個(gè)樹的黑高整體減一。

原文

袁瓊瓊的技術(shù)博客哄啄,歡迎指針
https://yuanqiongqiong.cn/2019/06/09/%E7%BA%A2%E9%BB%91%E6%A0%91/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末雅任,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子咨跌,更是在濱河造成了極大的恐慌沪么,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锌半,死亡現(xiàn)場(chǎng)離奇詭異禽车,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)刊殉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門殉摔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人记焊,你說我怎么就攤上這事逸月。” “怎么了亚亲?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵彻采,是天一觀的道長。 經(jīng)常有香客問我捌归,道長肛响,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任惜索,我火速辦了婚禮特笋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘巾兆。我一直安慰自己猎物,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布角塑。 她就那樣靜靜地躺著蔫磨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪圃伶。 梳的紋絲不亂的頭發(fā)上堤如,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天蒲列,我揣著相機(jī)與錄音,去河邊找鬼搀罢。 笑死蝗岖,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的榔至。 我是一名探鬼主播抵赢,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼唧取!你這毒婦竟也來了铅鲤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤兵怯,失蹤者是張志新(化名)和其女友劉穎彩匕,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體媒区,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡驼仪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了袜漩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绪爸。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖宙攻,靈堂內(nèi)的尸體忽然破棺而出奠货,到底是詐尸還是另有隱情,我是刑警寧澤座掘,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布递惋,位于F島的核電站,受9級(jí)特大地震影響溢陪,放射性物質(zhì)發(fā)生泄漏萍虽。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一形真、第九天 我趴在偏房一處隱蔽的房頂上張望杉编。 院中可真熱鬧,春花似錦咆霜、人聲如沸邓馒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽光酣。三九已至,卻和暖如春脉课,著一層夾襖步出監(jiān)牢的瞬間救军,已是汗流浹背改览。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留缤言,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓视事,卻偏偏與公主長得像胆萧,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子俐东,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

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

  • - 簡(jiǎn)介 紅黑樹(Red Black Tree) 是一種近似平衡二叉查找樹跌穗,具有基本二叉樹的所有特性的同時(shí),還...
    廈門張明爽閱讀 545評(píng)論 0 1
  • 紅黑樹是平衡二叉查找樹的一種虏辫。為了深入理解紅黑樹蚌吸,我們需要從二叉查找樹開始講起。 BST 二叉查找樹(Binary...
    kanehe閱讀 1,375評(píng)論 0 8
  • 1.HashMap是一個(gè)數(shù)組+鏈表/紅黑樹的結(jié)構(gòu)砌庄,數(shù)組的下標(biāo)在HashMap中稱為Bucket值羹唠,每個(gè)數(shù)組項(xiàng)對(duì)應(yīng)的...
    誰在烽煙彼岸閱讀 1,025評(píng)論 2 2
  • Map集合萌焰、散列表哺眯、紅黑樹介紹 前言 聲明,本文用得是jdk1.8 前面已經(jīng)講了Collection的總覽和剖析L...
    Java3y閱讀 1,090評(píng)論 2 22
  • 曾經(jīng)癡迷于海子的 面朝大海春暖花開 今天扒俯, 在這繁華的天子腳下 我是個(gè)窮人 沒有完美的身姿 沒有高端的收入 也沒有...
    予咪王閱讀 119評(píng)論 0 0