红黑树

参照:
http://daoluan.net/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/%E7%AE%97%E6%B3%95/2013/09/25/rbtree-is-not-difficult.html
http://daoluan.net/%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/%E7%AE%97%E6%B3%95/2013/09/28/rbtree-is-not-difficult-2.html

wiki:https://en.wikipedia.org/wiki/Red–black_tree

什么是红黑树


红黑树是自平衡的二叉搜索树,就是插入或者删除节点时可以自己保持高度尽量小,以提高搜索的性能。

红黑树有5个性质:
1.树的节点要么是红色,要么是黑色;
2.根是黑色;
3.树的所有叶子都是黑色(叶子都是NIL节点,即是实际节点的左右节点,都是空的节点,都设为黑色的);
4.如果节点是红色的,那么它的两个孩子节点都是黑色的;

5.从任一节点到其叶子(NIL)节点的所有路径都包含相同数量的黑色节点。



有上面几个属性的约束,使得红黑树有一个很关键的特点:从根到最远的叶子节点的高度不会超过根到最近的叶子节点的高度的2倍,这使得红黑树接近于树的高度平衡,所以就算是最坏的情况,查找节点的时间最长也只是树的高度。

红黑树主要是由性质4和性质5一起来保证红黑树的结构特点。假如有红黑树T,树根root到叶子节点的最短路径的黑色数量为B,由于性质5,插入节点应该是红色才能保证路径上黑色节点不变,而插入了红色节点则会使得树根root到叶子节点路径变长,而由性质4,不能插入两个连续的红色节点,所以树根root到叶子节点的最长路径是2 * B。

上面说的最短路径黑色节点数量为B,可能包含B个黑色节点,即全是黑色节点,则在这棵树中,最长的路径则只能是红色和黑色轮流交替,即最长路径的节点数量2 * B。

当红黑树插入或者删除节点时,会使得树的结构发生变化,为使得树的结构满足红黑树的性质,需要调整树的结构使得满足红黑树。

调整有两种,一种是节点的颜色改变,一种是调整树的结构,调整结构基本分两种:左旋和右旋。

左旋

节点X的右子树rTree的根Y变为节点X的父节点,而右子树rTree它的左子树变成节点X的右子树。

借助源码:

/** From CLR */
private void rotateLeft(Entry<K,V> p) {
    if (p != null) {
        Entry<K,V> r = p.right;
        p.right = r.left;
        if (r.left != null)
            r.left.parent = p;
        r.parent = p.parent;
        if (p.parent == null)
            root = r;
        else if (p.parent.left == p)
            p.parent.left = r;
        else
            p.parent.right = r;
        r.left = p;
        p.parent = r;
    }
}

右旋

节点Y的左子树lTree的根X变为节点Y的父节点,而左子树lTree它的右子树变成节点Y的左子树。

借助源码:

/** From CLR */
private void rotateRight(Entry<K,V> p) {
    if (p != null) {
        Entry<K,V> l = p.left;
        p.left = l.right;
        if (l.right != null) l.right.parent = p;
        l.parent = p.parent;
        if (p.parent == null)
            root = l;
        else if (p.parent.right == p)
            p.parent.right = l;
        else p.parent.left = l;
        l.right = p;
        p.parent = l;
    }
}

插入新节点


在红黑树中,新增加的节点是红色的,在插入新节点后需要重新修复红黑树的平衡。

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

    while (x != null && x != root && x.parent.color == RED) {
        if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
            Entry<K,V> y = rightOf(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 == rightOf(parentOf(x))) {
                    x = parentOf(x);
                    rotateLeft(x);
                }
                setColor(parentOf(x), BLACK);
                setColor(parentOf(parentOf(x)), RED);
                rotateRight(parentOf(parentOf(x)));
            }
        } else {
            Entry<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;
}

删除节点


在红黑树中,删除节点后也需要重新修复红黑树的平衡。
/** From CLR */
    private void fixAfterDeletion(Entry<K,V> x) {
        while (x != root && colorOf(x) == BLACK) {
            if (x == leftOf(parentOf(x))) {
                Entry<K,V> sib = rightOf(parentOf(x));

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

                if (colorOf(leftOf(sib))  == BLACK &&
                    colorOf(rightOf(sib)) == BLACK) {
                    setColor(sib, RED);
                    x = parentOf(x);
                } else {
                    if (colorOf(rightOf(sib)) == BLACK) {
                        setColor(leftOf(sib), BLACK);
                        setColor(sib, RED);
                        rotateRight(sib);
                        sib = rightOf(parentOf(x));
                    }
                    setColor(sib, colorOf(parentOf(x)));
                    setColor(parentOf(x), BLACK);
                    setColor(rightOf(sib), BLACK);
                    rotateLeft(parentOf(x));
                    x = root;
                }
            } else { // symmetric
                Entry<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);
    }
...
发布了184 篇原创文章 · 获赞 60 · 访问量 27万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览