樹(五,紅黑樹)

db.jpg
概念:

紅黑樹或者是一顆空樹,或者是一顆具有以下性質的二叉查找樹.

  1. 結點非紅即黑.
  2. 根結點為黑.
  3. 所有的NULL為葉子結點,且認為顏色為黑
  4. 所有紅結點的子結點為黑
  5. 任一結點到其葉子結點的所有路徑,經過的黑結點數量相同
  6. 任意一個結點,他的左右子樹層次不超過一倍.


    image.png
結點插入:
  1. 先按照二叉排序樹的方式插入一個節點(紅色).

  2. 插入的是黑結點>直接將結點涂黑.

  3. 插入結點的父節點是黑色>不違背任何性質,不用調整.

  4. 插入結點的父結點是紅色>
    4.1 父結點是祖父結點的左孩子
    4.1.1 祖父節點的另一個子結點(叔叔結點)是紅色>
    將當前節點的父結點和叔叔結點涂黑,祖父結點涂紅,將當前節點指定為祖父結點,從新的當前節點開始算法.


    image.png

    4.1.2 叔叔結點是黑色>
    4.1.2.1 當前節點是其父結點的右孩子>當前節點的父結點作為新的當前節點,以新的當前節點為支點進行左旋


    image.png

    4.1.2.2 當前節點是其父結點的左孩子>父結點變為黑色,祖父結點變為紅色,再以祖父結點為支點進行右旋
    image.png

    4.2 父結點是祖父結點右孩子>和上面一樣,只是把左全部換成右.

image.png
刪除結點

先進行二叉排序樹的刪除操作,然后將替換結點作為新的當前節點進行后面的平衡操作.

  1. 當前節點是紅色>直接把當前節點染黑,結束.

  2. 當前節點是黑色>
    2.1 被刪除節點是父結點的左孩子>
    2.1.1 當前節點是根結點>什么都不做
    2.1.2 當前節點X的兄弟結點是紅色(此時,父結點和兄弟節點的子結點為黑)>把父結點染紅,兄弟節點染黑,以父結點為支點進行左旋,重新設置X的兄弟節點.


    image.png

    2.1.3 當前節點X的兄弟節點是黑色>
    2.1.3.1 兄弟節點的兩個孩子都為黑色>將當前節點的兄弟節點染黑,父結點染紅,然后以父結點作為新的當前節點,從新開始算法.


    image.png

    2.1.3.2 兄弟的右孩子是黑色,左孩子是紅色>將X兄弟節點的左孩子置黑,將X節點的兄弟節點置紅,將X節點的兄弟節點進行右旋,然后重置x節點的兄弟節點.
    image.png

    2.1.3.3 兄弟節點的右孩子是紅色>兄弟節點染成當前節點父結點的顏色,兄弟節點的右孩子染成黑色,父結點染成黑色,以當前節點的父結點為支點,進行左旋,算法結束.
    image.png

    2.2 被刪除節點是父結點的右孩子>把上邊的左置為右

代碼

紅黑樹的插入刪除規則就講完了,是有點復雜,但其實不難.
那么,我們來看看紅黑樹的代碼吧,jdk1.8之后,為了適用大數據時代,很多數據結構都用到了紅黑樹
比如:HashTable,TreeSet,TreeMap
我們以TreeMap為例,來看看紅黑樹的源碼,對照上面的插入規則和刪除規則來一步步看

  1. TreeMap插入操作
public V put(K key, V value) {
        TreeMapEntry<K,V> t = root;
        if (t == null) {//根結點為空
            // BEGIN Android-changed: Work around buggy comparators. http://b/34084348
            // We could just call compare(key, key) for its side effect of checking the type and
            // nullness of the input key. However, several applications seem to have written comparators
            // that only expect to be called on elements that aren't equal to each other (after
            // making assumptions about the domain of the map). Clearly, such comparators are bogus
            // because get() would never work, but TreeSets are frequently used for sorting a set
            // of distinct elements.
            //
            // As a temporary work around, we perform the null & instanceof checks by hand so that
            // we can guarantee that elements are never compared against themselves.
            //
            // **** THIS CHANGE WILL BE REVERTED IN A FUTURE ANDROID RELEASE ****
            //
            // Upstream code was:
            // compare(key, key); // type (and possibly null) check
            if (comparator != null) {//這個comparator表示傳進來的比較器
                if (key == null) {
                    comparator.compare(key, key);
                }
            } else {
                if (key == null) {
                    throw new NullPointerException("key == null");
                } else if (!(key instanceof Comparable)) {
                    throw new ClassCastException(
                            "Cannot cast" + key.getClass().getName() + " to Comparable.");
                }
            }
            // END Android-changed: Work around buggy comparators. http://b/34084348
            root = new TreeMapEntry<>(key, value, null);//插入結點作為根結點
            size = 1;
            modCount++;//表示TreeMap被修改一次
            return null;
        }
        int cmp;
        TreeMapEntry<K,V> parent;
        // split comparator and comparable paths
        //這里是確認插入結點的位置,分為comparator為空和不為空兩種情況
        Comparator<? super K> cpr = comparator;
        if (cpr != null) {
            do {
                parent = t;
                cmp = cpr.compare(key, t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        else {
            if (key == null)
                throw new NullPointerException();
            @SuppressWarnings("unchecked")
                Comparable<? super K> k = (Comparable<? super K>) key;
            do {
                parent = t;
                cmp = k.compareTo(t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        //插入節點,平衡操作
        TreeMapEntry<K,V> e = new TreeMapEntry<>(key, value, parent);
        if (cmp < 0)
            parent.left = e;
        else
            parent.right = e;
        fixAfterInsertion(e);
        size++;
        modCount++;
        return null;
    }


    /** From CLR */
    private void fixAfterInsertion(TreeMapEntry<K,V> x) {
        x.color = RED;

        while (x != null && x != root && x.parent.color == RED) {//4
            if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {//4.1
                TreeMapEntry<K,V> y = rightOf(parentOf(parentOf(x)));//x的叔叔結點y
                if (colorOf(y) == RED) {//4.1.1
                    setColor(parentOf(x), BLACK);//父結點置黑
                    setColor(y, BLACK);//叔叔結點置黑
                    setColor(parentOf(parentOf(x)), RED);//祖父結點置紅
                    x = parentOf(parentOf(x));//祖父結點作為當前節點
                } else {//4.1.2
                    if (x == rightOf(parentOf(x))) {//4.1.2.1
                        x = parentOf(x);
                        rotateLeft(x);
                    }
                    //4.1.2.2
                    setColor(parentOf(x), BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    rotateRight(parentOf(parentOf(x)));
                }
            } else {//4.2
                TreeMapEntry<K,V> y = leftOf(parentOf(parentOf(x)));
                if (colorOf(y) == RED) {
                    setColor(parentOf(x), BLACK);
                    setColor(y, BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    x = parentOf(parentOf(x));
                } else {
                    if (x == leftOf(parentOf(x))) {
                        x = parentOf(x);
                        rotateRight(x);
                    }
                    setColor(parentOf(x), BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    rotateLeft(parentOf(parentOf(x)));
                }
            }
        }
        root.color = BLACK;//2
    }
  1. TreeMap刪除操作
/**
     * Delete node p, and then rebalance the tree.
     */
    private void deleteEntry(TreeMapEntry<K,V> p) {
        modCount++;
        size--;

        // If strictly internal, copy successor's element to p and then make p
        // point to successor.
        if (p.left != null && p.right != null) {
            TreeMapEntry<K,V> s = successor(p);//找到替換結點,并替換
            p.key = s.key;
            p.value = s.value;
            p = s;
        } // p has 2 children

        // Start fixup at replacement node, if it exists.
        TreeMapEntry<K,V> replacement = (p.left != null ? p.left : p.right);

        if (replacement != null) {
            // Link replacement to parent
            replacement.parent = p.parent;
            if (p.parent == null)
                root = replacement;
            else if (p == p.parent.left)
                p.parent.left  = replacement;
            else
                p.parent.right = replacement;

            // Null out links so they are OK to use by fixAfterDeletion.
            p.left = p.right = p.parent = null;

            // Fix replacement
            if (p.color == BLACK)//2
                fixAfterDeletion(replacement);
        } else if (p.parent == null) { // return if we are the only node.
            root = null;
        } else { //  No children. Use self as phantom replacement and unlink.
            if (p.color == BLACK)//2
                fixAfterDeletion(p);

            if (p.parent != null) {
                if (p == p.parent.left)
                    p.parent.left = null;
                else if (p == p.parent.right)
                    p.parent.right = null;
                p.parent = null;
            }
        }
    }

    /** From CLR */
    private void fixAfterDeletion(TreeMapEntry<K,V> x) {
        while (x != root && colorOf(x) == BLACK) {//2
            if (x == leftOf(parentOf(x))) {//2.1
                TreeMapEntry<K,V> sib = rightOf(parentOf(x));//sib,當前節點的兄弟結點

                if (colorOf(sib) == RED) {//2.1.2
                    setColor(sib, BLACK);
                    setColor(parentOf(x), RED);
                    rotateLeft(parentOf(x));
                    sib = rightOf(parentOf(x));
                }

                if (colorOf(leftOf(sib))  == BLACK &&
                    colorOf(rightOf(sib)) == BLACK) {//2.1.3.1
                    setColor(sib, RED);
                    x = parentOf(x);
                } else {
                    if (colorOf(rightOf(sib)) == BLACK) {//2.1.3.2
                        setColor(leftOf(sib), BLACK);
                        setColor(sib, RED);
                        rotateRight(sib);
                        sib = rightOf(parentOf(x));
                    }
                    //2.1.3.3
                    setColor(sib, colorOf(parentOf(x)));
                    setColor(parentOf(x), BLACK);
                    setColor(rightOf(sib), BLACK);
                    rotateLeft(parentOf(x));
                    x = root;
                }
            } else { // symmetric
                //2.2
                TreeMapEntry<K,V> sib = leftOf(parentOf(x));

                if (colorOf(sib) == RED) {
                    setColor(sib, BLACK);
                    setColor(parentOf(x), RED);
                    rotateRight(parentOf(x));
                    sib = leftOf(parentOf(x));
                }

                if (colorOf(rightOf(sib)) == BLACK &&
                    colorOf(leftOf(sib)) == BLACK) {
                    setColor(sib, RED);
                    x = parentOf(x);
                } else {
                    if (colorOf(leftOf(sib)) == BLACK) {
                        setColor(rightOf(sib), BLACK);
                        setColor(sib, RED);
                        rotateLeft(sib);
                        sib = leftOf(parentOf(x));
                    }
                    setColor(sib, colorOf(parentOf(x)));
                    setColor(parentOf(x), BLACK);
                    setColor(leftOf(sib), BLACK);
                    rotateRight(parentOf(x));
                    x = root;
                }
            }
        }

        setColor(x, BLACK);//1
    }

      /**
     * Returns the successor of the specified Entry, or null if no such.
     */
    static <K,V> TreeMapEntry<K,V> successor(TreeMapEntry<K,V> t) {
        if (t == null)
            return null;
        else if (t.right != null) {//右子樹不為空時,得到刪除結點右子樹的左子樹中最小的結點,替換被刪除的結點
            TreeMapEntry<K,V> p = t.right;
            while (p.left != null)
                p = p.left;
            return p;
        } else {//右子樹為空,從當前節點一直右上找,找到頭
            TreeMapEntry<K,V> p = t.parent;
            TreeMapEntry<K,V> ch = t;
            while (p != null && ch == p.right) {
                ch = p;
                p = p.parent;
            }
            return p;
        }
    }

ok,紅黑樹就介紹到這里了,如果對這些樹感興趣呢,其實在計算科學中還有很多有趣的樹
比如:


image.png

大家感興趣可以自行去學習下.

日拱一卒,貴在堅持.

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,283評論 6 530
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 97,947評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,094評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,485評論 1 308
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,268評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,817評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,906評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,039評論 0 285
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,551評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,502評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,662評論 1 366
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,188評論 5 356
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,907評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,304評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,563評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,255評論 3 389
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,637評論 2 370

推薦閱讀更多精彩內容

  • 寫在前面 當在10億數據進行不到30次比較就能查找到目標時,不禁感嘆編程之魅力!人類之偉大呀! —— 學紅黑樹有感...
    安卓大叔閱讀 659,868評論 262 1,258
  • 1、紅黑樹介紹 紅黑樹又稱R-B Tree,全稱是Red-Black Tree,它是一種特殊的二叉查找樹,紅黑樹的...
    文哥的學習日記閱讀 9,894評論 1 35
  • 0.目錄 1.算法導論的紅黑樹本質上是2-3-4樹 2.紅黑樹的結構和性質 3.紅黑樹的插入 4.紅黑樹的刪除 5...
    王偵閱讀 2,506評論 1 2
  • 1.平衡與非平衡樹 樹的平衡樹的平衡指的是:樹中每個節點的左邊后代的數目,應該和其右邊后代的數目大致相等。對于隨機...
    王偵閱讀 362評論 0 0
  • 你知道剩男剩女是怎么剩下的嗎? 長相不能太丑吧? 個子不能太矮吧? 人不能太無趣吧? 收入不能太低吧? 學歷不能太...
    忠良162閱讀 262評論 0 0