红黑树简单分析

一、引入:

        在理想情况下,二叉搜索树增删查改的时间复杂度为O(logN)。但是,在插入数据的时候,可能会导致树会倾斜,不同的插入顺序会导致树的高度不一样,树的高度决定了它查找的时间复杂度。例如,最坏的情况下是所有的节点都在一条斜线上,这样树的高度为N,查找的时间复杂度直接退化为O(N)

        基于二叉搜索树存在的问题,一种新的树——平衡二叉查找树产生了。平衡树在插入和删除的时候,会通过旋转操作将高度保持在logN。其中两款具有代表性的平衡树分别为AVL树和红黑树。AVL树由于实现比较复杂,而且插入和删除性能差,在实际环境下的应用不如红黑树。

最坏情况下例子:当插入顺序为 5-6-7-8-9-15-18时,二叉搜索树退化为链表,当查找18时,需要进行7次查找,时间复杂度为O(N)。

图1.1:最坏情况下退化为链表

二、红黑二叉树的定义:

        红黑树是每个节点都带有颜色属性的二叉查找树,颜色为红色或黑色。

        在二叉查找树强制一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求:

1.节点是红色或黑色。

2.根是黑色。

3.所有叶子都是黑色(叶子是NIL节点)。

4.每个红色节点必须有两个黑色的子节点。(从每个叶子到根的所有路径上不能有两个连续的红色节点。)

5.从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。

        正是红黑树的这5条性质,使一棵n个节点的红黑树始终保持了logN的高度,使得红黑树的查找、插入、删除的时间复杂度最坏为O(logN)

图2.1:具体的红黑树的图例 

三、旋转:

        当在对红黑树进行插入和删除等操作时,对树做了修改可能会破坏红黑树的性质。为了继续保持红黑树的性质,可以通过对节点进行重新着色,以及对树进行相关的旋转操作,来达到对红黑树进行插入或删除节点等操作后继续保持它的性质或平衡的目的。

        红黑树的旋转操作,准确地说是二叉树的旋转操作,也就是在二叉树中的一种子树调整操作, 旋转并不影响对该二叉树进行中序遍历的结果,也就是旋转前后两棵树上的节点直线投影来的序列一样的,这样旋转不会违反节点的大小关系(即左小右大)。树旋转通常应用于需要调整树的局部平衡性的场合。旋转分为左旋转右旋转。

左旋转:

图3.1:左旋转图示

如上图所示:以pivot节点为图心,向左旋转,此时pivot右子节点Y上升替代pivot原来位置,再将pivot右节点指向Y左节点,Y左节点指向pivot,左旋转操作完成。

右旋转:

图3.2:右旋转图示

右旋与左旋差不多,不做详细介绍。

四、插入操作:

首先,所以新增的节点都标记为红色。(如果标记    为黑色,就会导致根到叶子的路径上,有一条路径多一个额外的黑节点,破坏了红黑树的性质5。)

以下插入情景不会对红黑树造成性质破坏:

情景1:插入节点作为根节点的子节点

情景2:插入节点的父结节点是黑色的

以下插入情景需要修复:

情景1:当前节点为根节点,将根节点染成黑色即可。

图4.1:情景1修复

情景2:插入节点的父节点为红色:

        情景2.1:叔节点存在,并且为红色,将父叔节点染为黑色,将祖父节点染为红色,并且再以祖父节点为当前节点,进行递归处理,直到当前节点的父节点为黑色。

        情景2.2:父节点为祖父节点的右子树,叔节点不存在,或者为黑色。

                情景2.2.1:插入节点为其父节点的右子节点,以祖父节点为圈心左旋转,再将父节点染色为黑色,将祖父节点染为红色。

图4.2:情景2修复

                情景2.2.2:插入节点为其父节点的左子节点,以父节点为圆心进行右旋转,得到情景(2.2.1)然后将父节点设置为当前节点进行递归处理。

图4.3:情景2修复

        情景2.3:父节点为祖父节点的左子树,叔节点不存在,或者为黑色。

                情景2.3.1:插入节点为其父节点的左子节点,与情景2.2.1为镜像结构,只需要将对应的左旋转变成右旋转,右旋转变成左旋转即可。

                情景2.3.2:插入节点为其父节点的右子节点。与情景2.2.2为镜像结构,只需要将对应的左旋变成右旋转,右旋转变成左旋转即可。

五、 插入总结:

        在上面两种修复情况当中第二种是不会改变所在子树的黑色路径长度的,只有第一种情况可能改变黑色路径长度,因为它可能子树根节点涂红,如果子树根节点就是整棵树的根节点时,在修复结束后会被重新设置成黑色,黑色路径长度就加1了,但这个时候黑色路径增加针对的不再是这个子树了,而是整颗红黑树,所以是不会破坏性质5的至于性质4看修补后的图中结点的颜色就知道是不会破坏了。

        插入结束之后,这颗子树的满足了性质4(不能有两个连续的红色节点)和性质5(从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点),又是一颗新的红黑树了。

六:简单实现:

红黑树及节点节点定义:

//红黑定义

public static final boolean RED =true;

public static final boolean BLACK =false;

//树根的引用

private RBNoderoot;

static class RBNode<K extends Comparable<K>, V> {

    private RBNodeparent;

    private RBNodeleft;

    private RBNoderight;

    private boolean color;

    private K key;

    private V value;

}

旋转操作:

private void leftRotate(RBNode x) { //左旋方法

RBNode y = x.right;

    // 1.将x的右子节点指向y的左子节点,将y的左子节点的父节点更新为x

    x.right = y.left;

    if (y.left !=null)

        y.left.parent = x;

   if (x.parent !=null) {  //2.当x的父节点(不为空时) ,更新y的父节点为x的父节点,并将x的父节点指定为y

        y.parent = x.parent;

        if (x == x.parent.left)

            x.parent.left = y;

        else

            x.parent.right = y;

    }else {

        this.root = y;

        this.root.parent =null;

    }

//3.将x的父节点更新为y,将y的左子节点更新为x

    x.parent = y;

    y.left = x;

}

private void rightRotate(RBNode y) { //右旋方法

    RBNode x = y.left;

    //1.将y的左子节点指向x的右子节点,并且更新x的右子节点的父节点为y

    y.left = x.right;

    if (x.right !=null)

        x.right.parent = y;

    //2.当y的父节点不为空时,更新x的父节点为y的父节点,更新y的父节点的指定为x

    if (y.parent !=null) {

        x.parent = y.parent;

        if (y == y.parent.left)

            y.parent.left = x;

        else

            y.parent.right = x;

    }else {

        this.root = y;

        this.root.parent =null;

    }

//3.更新y的父节点为x,更新x的右子节点为y

    y.parent = x;

    x.right = y;

}

插入操作:

public void insert(RBNode node) {

//查找当前node的父节点

    RBNode parent =null;

    RBNode x =this.root;

    while (x !=null) {

        parent = x;

        //cmp>0 说明node.key 大于 x.key 需要x的右子树查找

        //cmp==0 说明node.key 等于 x.key 说明需要进行替换操作

        //cmp<0 说明node.key 小于 x.key 需要x的左子树查找

        int cmp = node.key.compareTo(x.key);

        if (cmp >0) 

            x = x.right;

        else if (cmp ==0) {

            x.setValue(node.getValue());

            return;

        }else 

            x = x.left;

}

    node.parent = parent;

    if (parent !=null) {

        //判断node应该插入parent的左节点还是右节点

        int cmp = node.key.compareTo(parent.key);

        if (cmp >0)

            parent.right = node;

        else

            parent.left = node;

    }else 

        this.root = node;

    //进行红黑树平衡

    insertFixUp(node);

}

修复:

private void insertFixUp(RBNode node) {

    this.root.setColor(BLACK);

    RBNode parent = parentOf(node);

    RBNode Gparent = parentOf(parent);

    //插入节点的父节点为红色

    if (parent !=null && isRed(parent)) {

           //如果父节点是红色,那么一定存在祖父节点。因为根节点不可能是红色

        RBNode uncle =null;

        if (parent == Gparent.left) {//父节点为祖父节点的左子树

            uncle = Gparent.right;

            //叔节点存在,并且为红色

            if (uncle !=null && isRed(uncle)) {

                setBlack(parent);

                setBlack(uncle);

                setRed(Gparent);

                insertFixUp(Gparent);

                return;

            }

            if (uncle ==null || isBlack(uncle)) {  //叔节点不存在,或者为黑色

                if (node == parent.left) {

                    setBlack(parent);

                    setRed(Gparent);

                    rightRotate(Gparent);

                    return;

                }

            if (node == parent.right) { //插入节点为其父节点的右子节点

                    leftRotate(parent);

                    insertFixUp(parent);

                    return;

                }

}

}else { //父节点为爷节点的右子数

            uncle = Gparent.left;

            if (uncle !=null && isRed(uncle)) {

                setBlack(parent);

                setBlack(uncle);

                setRed(Gparent);

                insertFixUp(Gparent);

                return;

            }

if (uncle ==null || isBlack(uncle)) {  //插入节点为其父节点的左子节点

                if (node == parent.right) {

                    setBlack(parent);

                    setRed(Gparent);

                    leftRotate(Gparent);

                    return;

                }

if (node == parent.left) {  //插入节点为其父节点的右子节点

                    rightRotate(parent);

                    insertFixUp(parent);

                    return;

                 }

             }

        }

    }

}

七、参考文献:

    红黑树深入剖析及Java实现

    红黑树——维基百科

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

推荐阅读更多精彩内容

  • 红黑树是平衡二叉查找树的一种。为了深入理解红黑树,我们需要从二叉查找树开始讲起。 BST 二叉查找树(Binary...
    kanehe阅读 1,374评论 0 8
  • 最近花了些时间重拾数据结构的基础知识,先尝试了红黑树,花了大半个月的时间研究其原理和实现,下面是学习到的知识和一些...
    hoohack阅读 1,518评论 8 30
  • 红黑树 红黑树也是一种自平衡的二叉搜索树以前也叫做平衡二叉B树(Symmetric Binary B-tree) ...
    ducktobey阅读 763评论 0 1
  • - 简介 红黑树(Red Black Tree) 是一种近似平衡二叉查找树,具有基本二叉树的所有特性的同时,还...
    厦门张明爽阅读 542评论 0 1
  • 写作也许是每一个人都会的事情,但有些人没有发掘出自己的潜能,甚至还在这条道路上退缩。 在来到简书前,我看到过很多关...
    焉羽入江南阅读 3,375评论 57 130