紅黑樹底層實(shí)現(xiàn)原理分析及JAVA代碼實(shí)現(xiàn)

------------ 本文來(lái)自 阿P官方博客
------------ 在線測(cè)試紅黑樹:紅黑樹在線測(cè)試

一囱挑、紅黑樹

    自平衡二叉查找樹(Binary Search Tree)
    二叉查找樹:
        基于二叉樹
            左子樹小于根醉顽,右子樹大于根
            缺點(diǎn):如果選錯(cuò)根節(jié)點(diǎn),整個(gè)樹就不再平衡
    特點(diǎn)
        所有節(jié)點(diǎn)非紅即黑
        根節(jié)點(diǎn)一定是黑色
        紅節(jié)點(diǎn)的子節(jié)點(diǎn)一定是黑色
        最低層的葉子節(jié)點(diǎn)一定是黑色
        從根節(jié)點(diǎn)到任意葉子節(jié)點(diǎn)經(jīng)歷過(guò)的黑色節(jié)點(diǎn)一定相同
        新增的節(jié)點(diǎn)顏色一定是紅色節(jié)點(diǎn)
    紅黑樹時(shí)間復(fù)雜度:O(logN) 與二分查找法一致
        第一次查找數(shù)量 n/2
        第二次查找數(shù)量 n/2/2
        第三次查找數(shù)量 n/2/2/2
        …...
        第m次查找數(shù)量 n/(2^m)
        由此我們可以得知時(shí)間復(fù)雜度=logN

二平挑、紅黑樹修正(遵循以下步驟進(jìn)行修正)

    當(dāng)前節(jié)點(diǎn)為紅游添,父節(jié)點(diǎn)為紅,并且叔父節(jié)點(diǎn)為紅或?yàn)榭?        父節(jié)點(diǎn)通熄、叔父節(jié)點(diǎn)涂黑唆涝,祖父節(jié)點(diǎn)涂紅。對(duì)祖父節(jié)點(diǎn)繼續(xù)操作
    當(dāng)前節(jié)點(diǎn)為紅且是右子葉唇辨,父節(jié)點(diǎn)為紅廊酣,并且叔父節(jié)點(diǎn)為黑
        以當(dāng)前節(jié)點(diǎn)為軸,進(jìn)行左旋
    當(dāng)前節(jié)點(diǎn)為紅且是左子葉赏枚,父節(jié)點(diǎn)為紅亡驰,并且叔父節(jié)點(diǎn)為黑
        父節(jié)點(diǎn)涂黑,祖父節(jié)點(diǎn)涂紅嗡贺,以父節(jié)點(diǎn)為軸隐解,進(jìn)行右旋

三、紅黑樹JAVA實(shí)現(xiàn)類

package RBTree;

/**
 * 紅黑樹
 *
 */
public class RBTreeDemo<T extends Comparable<T>> {
    
    Node root;//根節(jié)點(diǎn)
    Node min;//最左節(jié)點(diǎn)
    Node max;//最右節(jié)點(diǎn)
    
    Boolean RED = true;
    Boolean BLACK = false;
    /**
     * 新增
     * @param val
     */
    public void add(T val)
    {
        if (this.root == null) {
            //根節(jié)點(diǎn)為黑色
            this.root = new Node<T>(val, this.BLACK, null, null, null);
            return;
        }
        Node node = this.root;
        //當(dāng)前節(jié)點(diǎn)
        Node current = new Node<T>(val, this.RED, null, null, null);
        //遍歷樹诫睬,進(jìn)行插入
        while (true) {
            if (val.compareTo((T) node.val) > 0) {//放右子節(jié)點(diǎn)
                if (node.right == null) {
                    node.right = current;
                    current.parent = node;
                    break;
                }
                node=node.right;
            } else {//放左子節(jié)點(diǎn)
                if (node.left == null) {
                    node.left = current;
                    current.parent = node;
                    break;
                }
                node=node.left;
            }
        }
        //插入完進(jìn)行自平衡
        fixUp(current);
    }
    /**
     * 自平衡
     */
    public void fixUp(Node node)
    {
        //當(dāng)前節(jié)點(diǎn)沒(méi)父節(jié)點(diǎn)煞茫,則涂黑
        if (node.parent == null) {
            node.color = this.BLACK;
            this.root = node;
            return;
        }
        //當(dāng)前節(jié)點(diǎn)沒(méi)有祖父節(jié)點(diǎn)
        if (node.parent.parent == null) {
            return;
        }
        //叔父節(jié)點(diǎn) 可以為空
        Node uncleNode = this.getUncleNode(node);
        //當(dāng)前節(jié)點(diǎn)為紅,且父節(jié)點(diǎn)為紅
        if (node.color == this.RED && node.parent.color == this.RED) {
            //叔父節(jié)點(diǎn)為空或者為紅摄凡,就進(jìn)行涂色
            if (uncleNode == null || uncleNode.color == this.RED) {
                node.parent.color = this.BLACK;
                if (uncleNode != null) {
                    uncleNode.color=this.BLACK;
                }
                node.parent.parent.color = this.RED;
                this.fixUp(node.parent.parent);
            } else if (uncleNode.color == this.BLACK) {
                //自己是左子葉
                if (node.parent.left.equals(node)) {
                    this.right(node);
                    this.fixUp(node.parent);//右旋后续徽,修改當(dāng)前節(jié)點(diǎn)顏色
                } else {//自己是右子葉
                    this.left(node);
                    this.fixUp(node.left);//曾經(jīng)的父節(jié)點(diǎn)
                }
            }
        }
    }
    /**
     * 叔父節(jié)點(diǎn),可以為空
     * @param node
     * @return
     */
    private Node getUncleNode(Node node) {
        Node uncleNode= node.parent.parent.left;
        if (uncleNode == null || node.parent.equals(uncleNode)) {
            uncleNode = node.parent.parent.right;
        }
        return uncleNode;
    }
    /**
     * 當(dāng)前結(jié)點(diǎn)為紅亲澡,且處于右子葉上钦扭。父節(jié)點(diǎn)為紅,叔父節(jié)點(diǎn)為黑或空時(shí)床绪。以當(dāng)前節(jié)點(diǎn)為軸進(jìn)行左旋
     * 當(dāng)前節(jié)點(diǎn)的祖父節(jié)點(diǎn)客情,變成自己的父節(jié)點(diǎn)
     * 當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)其弊,變成自己的左節(jié)點(diǎn)
     * 當(dāng)前節(jié)點(diǎn)的左節(jié)點(diǎn),變成當(dāng)前右節(jié)點(diǎn)的右節(jié)點(diǎn)
     */
    private void left(Node node) {
        Node parent = node.parent;
        Node left = node.left;
        Node pParent = node.parent.parent;
        //祖父節(jié)點(diǎn)
        pParent.left = node;
        //父節(jié)點(diǎn)
        parent.parent = node;
        parent.right = left;
        //左節(jié)點(diǎn)
        left.parent = parent;
        //當(dāng)前節(jié)點(diǎn)
        node.parent = pParent;
        node.left = parent;
    }
    /**
     * 當(dāng)前結(jié)點(diǎn)為紅膀斋,且處于左子葉上梭伐。父節(jié)點(diǎn)為紅,叔父節(jié)點(diǎn)為黑時(shí)仰担。以父節(jié)點(diǎn)為軸進(jìn)行右旋
     */
    private void right(Node node) {
        Node parent = node.parent;
        Node right = parent.right;
        Node pParent = node.parent.parent;
        Node ppParent = node.parent.parent.parent;
        //涂色
        pParent.color = this.RED;
        parent.color = this.BLACK;
        if (ppParent != null) {
            //祖祖父節(jié)點(diǎn)
            if (ppParent.right.equals(pParent)) {
                ppParent.right = parent;
            } else {
                ppParent.left = parent;
            }
        }
        //祖父節(jié)點(diǎn)
        pParent.left = right;
        pParent.parent=parent;
        //父節(jié)點(diǎn)
        parent.right = pParent;
        parent.parent = ppParent;
        //右子節(jié)點(diǎn)
        right.parent = pParent;
    }
    /**
     * 前序遍歷 從根開始遍歷
     */
    private String preOrder(Node node) {
        if (node == null) {
            return null;//如果左側(cè)樹遍歷完成糊识,返回null
        }
        String strLeft = this.preOrder(node.left);
        if (strLeft == null) {
            strLeft="";
        }
        String strRight = this.preOrder(node.right);
        if (strRight == null) {
            strRight="";
        }
        return strLeft + node.toString() + strRight;
    }
    @Override
    public String toString() {
        //前序遍歷
        return preOrder(this.root);
    }
    /**
     * 結(jié)點(diǎn)類
     */
    private class Node<T>{
        public T val;
        public Boolean color;//紅為true
        public Node left;
        public Node right;
        public Node parent;
        public Node(T val, Boolean color, Node left, Node right, Node parent) {
            super();
            this.val = val;
            this.color = color;
            this.left = left;
            this.right = right;
            this.parent = parent;
        }
        @Override
        public String toString() {
            String left = "-";
            String right = "-";
            if (this.left != null) {
                left = this.left.val.toString();
            }
            if (this.right != null) {
                right =  this.right.val.toString();
            }
            return "[" + left + ", "+this.val.toString() + ", " + right +", "+ getColorName(this.color) + "]";
        }
        private String getColorName(Boolean color) {
            return color == true? "紅" : "黑";
        }
        @Override
        public boolean equals(Object obj) {
            Node obj1 = (Node)obj;
            return obj1.val == this.val;
        }
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市摔蓝,隨后出現(xiàn)的幾起案子赂苗,更是在濱河造成了極大的恐慌,老刑警劉巖贮尉,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拌滋,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡绘盟,警方通過(guò)查閱死者的電腦和手機(jī)鸠真,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)龄毡,“玉大人,你說(shuō)我怎么就攤上這事锡垄÷倭悖” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵货岭,是天一觀的道長(zhǎng)路操。 經(jīng)常有香客問(wèn)我,道長(zhǎng)千贯,這世上最難降的妖魔是什么屯仗? 我笑而不...
    開封第一講書人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮搔谴,結(jié)果婚禮上魁袜,老公的妹妹穿的比我還像新娘。我一直安慰自己敦第,他們只是感情好峰弹,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著芜果,像睡著了一般鞠呈。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上右钾,一...
    開封第一講書人閱讀 49,764評(píng)論 1 290
  • 那天蚁吝,我揣著相機(jī)與錄音旱爆,去河邊找鬼。 笑死窘茁,一個(gè)胖子當(dāng)著我的面吹牛疼鸟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播庙曙,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼空镜,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了捌朴?” 一聲冷哼從身側(cè)響起吴攒,我...
    開封第一講書人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎砂蔽,沒(méi)想到半個(gè)月后洼怔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡左驾,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年镣隶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片诡右。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡安岂,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出帆吻,到底是詐尸還是另有隱情域那,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布猜煮,位于F島的核電站次员,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏王带。R本人自食惡果不足惜淑蔚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望愕撰。 院中可真熱鬧刹衫,春花似錦、人聲如沸盟戏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)柿究。三九已至邮旷,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蝇摸,已是汗流浹背婶肩。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工办陷, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人律歼。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓民镜,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親险毁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子制圈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

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

  • 01.原則 昨天早上坐車的時(shí)候我還在和胖說(shuō),這邊的樹好奇怪啊畔况,冬天樹葉也沒(méi)有全部枯黃掉落鲸鹦,春天它也沒(méi)有重新發(fā)芽,就...
    怡采在成長(zhǎng)閱讀 121評(píng)論 0 1
  • 老伴的日歷本記事 由春寫到冬 字跡密密麻麻 他將一頁(yè)頁(yè)折疊在兩側(cè) 立于窗臺(tái) 猶如一只蝴蝶落在窗口 這只日歷蝶羽翼豐...
    寒樺閱讀 335評(píng)論 1 10
  • 前兩天和一個(gè)朋友吃飯跷跪,不知道怎么說(shuō)的就說(shuō)到他女朋友上去了馋嗜。他向我抱怨現(xiàn)任女友怎么樣怎么樣不好吵瞻,“飯都不會(huì)做葛菇,蛋炒飯...
    念永恒閱讀 154評(píng)論 4 1
  • 很想念過(guò)去的日子 卻又不知道想念過(guò)去的什么日子 就像有一片葉子 需要悄悄靠近 靠近 很想念過(guò)去的日子 卻又...
    喬棪閱讀 414評(píng)論 3 7
  • idea 下,spring boot項(xiàng)目啟動(dòng)的時(shí)候報(bào)錯(cuò)Circular placeholder reference...
    xiao碼閱讀 8,410評(píng)論 0 1