树(五,红黑树)

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阅读 213,864评论 6 494
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,175评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,401评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,170评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,276评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,364评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,401评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,179评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,604评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,902评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,070评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,751评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,380评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,077评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,312评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,924评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,957评论 2 351

推荐阅读更多精彩内容

  • 写在前面 当在10亿数据进行不到30次比较就能查找到目标时,不禁感叹编程之魅力!人类之伟大呀! —— 学红黑树有感...
    安卓大叔阅读 659,092评论 262 1,258
  • 1、红黑树介绍 红黑树又称R-B Tree,全称是Red-Black Tree,它是一种特殊的二叉查找树,红黑树的...
    文哥的学习日记阅读 9,863评论 1 35
  • 0.目录 1.算法导论的红黑树本质上是2-3-4树 2.红黑树的结构和性质 3.红黑树的插入 4.红黑树的删除 5...
    王侦阅读 2,472评论 1 2
  • 1.平衡与非平衡树 树的平衡树的平衡指的是:树中每个节点的左边后代的数目,应该和其右边后代的数目大致相等。对于随机...
    王侦阅读 357评论 0 0
  • 你知道剩男剩女是怎么剩下的吗? 长相不能太丑吧? 个子不能太矮吧? 人不能太无趣吧? 收入不能太低吧? 学历不能太...
    忠良162阅读 251评论 0 0