红黑树

1.前言

一棵高度为h的二叉搜索树,基本操作时间复杂度为O(h),当二叉搜索树高度较低时,效率较高,如果二叉搜索树高度较高则效率较低了,极限情况下,向二叉搜索树顺序插入一个数组,那么二叉搜索树的效率为O(n)。

红黑树也是一种二叉搜索树,它在每一个结点上添加了颜色,颜色可以是红或黑。通过相关规则约束,红黑树确保没有一条路径会比其它路径长出2倍,因此红黑树是近似平衡的,不会出现前文所说的极限情况。

红黑树必须满足以下五个条件:

  • 每个结点颜色是红色或者是黑色
  • 根结点是黑色的
  • 每个叶结点(指空结点,非叶子结点)是黑色的
  • 如果一个结点是红色的,那么它的两个子结点都是黑色的
  • 对每一个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点

一棵典型的红黑树:

rbtree.jpg

为什么红黑树没有一条路径会比其它路径长两倍呢?

红黑树中最短的路径,一定是全黑结点,最长的路径一定是黑红相间节点,要保持性质5,所以最长路径是最短路径的2倍

2、红黑树插入

红黑树的插入和二叉搜索树插入类似,根据结点值的大小,确定它的位置。

  public void rb_insert(RBNode z){
    RBNode y = null;
    RBNode x = mRoot;
    while (x != null) {
        y = x;
        if (z.value < x.value) {
            x = x.left;
        }else {
            x = x.right;
        }
    }
    z.parent = y;
    if (y == null) {
        mRoot = z;
    }else if (z.value < y.value) {
        y.left = z;
    }else {
        y.right = z;
    }
    z.left = null;
    z.right = null;
    z.color = RED;
    rb_insert_fixup(z);
}

由于新插入节点可能破坏红黑树的性质, 所以插入最后必须进行红黑树性质的修复。

为了尽量少违背红黑树的性质,设定新插入节点的颜色均为红色

由于新插入节点为红色,可能出现以下几种情况:

  • 新插入节点为根节点,直接置黑即可
  • 新插入节点的父节点为黑色,不违背任何规则
  • 新插入节点的父节点为红色,违背规则4

如果违背规则4,那么也有以下三种情况出现(新插入节点为z)

1、父节点及叔叔节点均为红色,祖父节点为黑色(根据红黑树性质,未插入前没有任何规则被破坏,那么祖父节点不可能为红色)

Paste_Image.png

此时,规则4被破坏,则规则5是正常的,只需将父节点、叔叔节点置为黑色,祖父节点置为红色,此当前子树完成平衡。采取递归思想,将整棵子树当成一个新的红色节点向上循环处理,设置z等于祖父节点

2、z的叔叔节点为黑色且z是右子节点

Paste_Image.png

红黑树插入修复的终极思想是,把多余的红色节点向根节点方向移动,变成根节点

根据插入修复思想,目前z是一个多余的红色节点,且此时节点不平衡,为了让z向根节点方向移动,则以z的父节点左旋转即可

3、z的叔叔节点为黑色且z是左子节点

Paste_Image.png

此时,以z的祖父节点右旋转,同时将z的父节点设置为黑色,祖父节点设置为红色,此时,红黑树平衡了。

仔细观察,其实情况2这么做,也是为了满足情况3的初始条件,以便旋转后,达到新的平衡。

//添加修复核心思想为,将多作的红色节点向根节点移动,最后把根节点弄成黑色即可
public void rb_insert_fixup(RBNode z){
    RBNode y = null;
    while (z.parent != null && z.parent.color == RED) {
        if (z.parent == z.parent.parent.left) {
            y = z.parent.parent.right;
            //z的父节点为红,叔叔节点也为红
            if (y.color == RED) {
                z.parent.color = BLACK;
                y.color = BLACK;
                z.parent.parent.color = RED;
                z = z.parent.parent;
            }else if (z == z.parent.right) {
                //叔叔节点为黑,且z是z的父亲的右子节点
                z = z.parent;
                leftRotate(z);
            }else {
                //叔叔节点为黑,且z是z的父亲的左子节点
                z.parent.color = BLACK;
                z.parent.parent.color = RED;
                rightRotate(z.parent.parent);
            }
        }else {
            y = z.parent.parent.left;
            if (y.color == RED) {
                z.parent.color = BLACK;
                y.color = BLACK;
                z.parent.parent.color = RED;
                z = z.parent.parent;
            }else if (z == z.parent.left) {
                //叔叔节点为黑,且z是z的父亲的右子节点
                z = z.parent;
                rightRotate(z);
            }else {
                //叔叔节点为黑,且z是z的父亲的左子节点
                z.parent.color = BLACK;
                z.parent.parent.color = RED;
                leftRotate(z.parent.parent);
            }
        }
    }
    mRoot.color = BLACK;
}

3、红黑树删除

红黑树的删除比插入更复杂,情况更多,但思想是一致的。类似二叉搜索树,找节点删除,维持二叉搜索树的性质,再修复红黑树的性质

  public void rb_delete(RBNode z){
    RBNode y = z;
    RBNode x = null;
    int yOriginColor = y.color;
    if (z.left == null) {
        x = z.right;
        rb_transplant(z, z.right);
    }else if (z.right == null) {
        x = z.left;
        rb_transplant(z, z.left);
    }else {
        y = treeMin(z.right);
        yOriginColor = y.color;
        x = y.right;
        if (y.parent == z) {
            x.parent = y;
        }else {
            rb_transplant(y, y.right);
            y.right = z.right;
            y.right.parent = y;
        }
        rb_transplant(z, y);
        y.left = z.left;
        y.left.parent = y;
        y.color = z.color;
    }
    if (yOriginColor == BLACK) {
        rb_delete_fixup(x);
    }
}

删除节点的关键是:

  • 如果删除的是红色节点,那么不会破坏性质
  • 如果删除的是黑色节点,那么,这个路径上会少一个黑色节点,性质5被破坏。所以删除算法就是通过重新着色、旋转,来恢复性质5

1、节点n为黑色,兄弟节点s也为黑色,s的子节点也为黑色

Paste_Image.png

将s节点设置为红色,当前子树已经恢复平衡,但由于删除了一个黑色节点,整体仍未平衡。以递归思想处理,将n赋值为p,以整个子树为新的n

2、承接上文,s节点为红,且s的子节点都为黑

Paste_Image.png

将s和p节点颜色互换,同时在p节点左旋

3、s左节点为红,自身为黑时

Paste_Image.png

交换s和sl颜色,同时以s中心右旋转

4、s右节点为红,自向为黑

Paste_Image.png

将s颜色置为s父节点的颜色,s父节点颜色置黑,右节点颜色置黑,同时以s父节点左旋转

//删除修复的核心思想是,x代替了y原来的位置,如果y是黑的,y位置移动了,那么规则5可能被破坏
//如果想象x有两个颜色,自身加一个黑色,替补y的黑色,那规则5则不再破坏
//如果x自身为红色加额外黑色,则此时所有规则都ok
//如果x自身为黑,额外也是黑,那么规则5则被破坏
//现在则要想办法将x弄成红色+黑色的模式,将多余黑色向根节点移动
public void rb_delete_fixup(RBNode x){
    if (x == null) {
        return;
    }
    RBNode w = null;
    while (x != mRoot && x.color == BLACK) {
        if (x == x.parent.left) {
            w = x.parent.right;
            if (w.color == RED) {
                w.color = BLACK;
                x.parent.color = RED;
                leftRotate(x.parent);
                w = x.parent.right;
            }else if ((w.left == null || w.left.color == BLACK)
                    && (w.right == null || w.right.color == BLACK)) {
                w.color = RED;
                x = x.parent;
            }else if (w.right == null || w.right.color == BLACK) {
                w.left.color = BLACK;
                w.color = RED;
                rightRotate(w);
                w = x.parent.right;
            }else {
                w.color = x.parent.color;
                x.parent.color = BLACK;
                w.right.color = BLACK;
                leftRotate(x.parent);
                x = mRoot;
            }
        }else {
            w = x.parent.left;
            if (w.color == RED) {
                w.color = BLACK;
                x.parent.color = RED;
                rightRotate(x.parent);
                w = x.parent.left;
            }else if ((w.left == null || w.left.color == BLACK) 
                    && (w.right == null || w.right.color == BLACK)) {
                w.color = RED;
                x = x.parent;
            }else if (w.left == null || w.left.color == BLACK) {
                w.right.color = BLACK;
                w.color = RED;
                leftRotate(w);
                w = x.parent.left;
            }else {
                w.color = x.parent.color;
                x.parent.color = BLACK;
                w.left.color = BLACK;
                rightRotate(x.parent);
                x = mRoot;
            }
        }
    }
    x.color = BLACK;
}    

以上即是红黑树删除操作,在算法导论上,红黑树删除思想是,设置N节点有两重颜色,自已本身颜色加上额外黑色,用以补偿被删除的黑色节点,然后想办法将N的颜色置为红色加黑色或者是根节点,然后置为黑色,则整个红黑树重新平衡。但以上四种情况也是一样的

红黑树的插入删除操作都挺复杂的,本人自己也有很多不理解的,现在记录如上,相信随意时间推移,会有更多新的理解。

以上所有代码均上传到本人github,欢迎访问。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容

  • 1、红黑树介绍 红黑树又称R-B Tree,全称是Red-Black Tree,它是一种特殊的二叉查找树,红黑树的...
    文哥的学习日记阅读 9,761评论 1 35
  • 一. 算法之变,结构为宗 计算机在很多情况下被应用于检索数据,比如航空和铁路运输业的航班信息和列车时刻表的查询,都...
    Leesper阅读 6,692评论 13 42
  • 原文链接 二叉查找树 由于红黑树本质上就是一棵二叉查找树,所以在了解红黑树之前,咱们先来看下二叉查找树。 二叉查找...
    非典型程序员阅读 2,784评论 2 5
  • 最近花了些时间重拾数据结构的基础知识,先尝试了红黑树,花了大半个月的时间研究其原理和实现,下面是学习到的知识和一些...
    hoohack阅读 1,478评论 8 30
  • 数据结构与算法--从平衡二叉树(AVL)到红黑树 上节学习了二叉查找树。算法的性能取决于树的形状,而树的形状取决于...
    sunhaiyu阅读 7,579评论 4 32