浅谈红黑树的添加删除操作

红黑树的性质(牢记)

1、每个结点的颜色只能是红色或黑色。

2、根结点必须是黑色的。

3、每个叶子结点都带有两个空的黑色结点(被称为黑哨兵null),如果一个结点n的只有一个左孩子,那么n的右孩子是一个黑哨兵;如果结点n只有一个右孩子,那么n的左孩子是一个黑哨兵。

4、如果一个结点是红的,则它的两个儿子都是黑的。也就是说在一条路径上不能出现相邻的两个红色结点。

5、从任何一个结点到其子孙叶结点的所有路径上包含相同数目的黑结点。

一、红黑树的插入

任何一个即将插入的新结点的初始颜色都为红色。这一点很容易理解,因为插入黑点会增加某条路径上黑结点的数目,从而导致整棵树黑高度的不平衡。但如果新结点父结点为红色时(如图2所示),将会违返红黑树性质:一条路径上不能出现相邻的两个红色结点。这时就需要通过一系列操作来使红黑树保持平衡。

注:“新”字表示一个新插入的结点;使用“父”字表示新插入点的父结点;使用“叔”字表示“父”结点的兄弟结点;使用“祖”字表示“父”结点的父结点。

1、 黑父

直接插入,不影响平衡。

2、 红父

叔父结点为红色时,无需进行旋转操作,只要将父和叔结点变为黑色,将祖父结点变为红色即可(当祖父节点为根节点时务必改为黑节点,见性质2)。但由于祖父结点的父结点有可能为红色,从而违反红黑树性质。此时必须将祖父结点作为新的判定点继续向上进行平衡操作。

*红黑树插入示例1

*红黑树插入示例2

二、红黑树的删除

红黑树上结点的删除

红黑树本身是一棵二叉查找树,它的删除和二叉查找树的删除类似。首先要找到真正的删除点,当被删除结点n存在左右孩子时,真正的删除点应该是n的中序遍在前驱,关于这一点请复习二叉查找树的删除。如图所示,当删除结点20时,实际被删除的结点应该为18,结点20的数据变为18。

所以可以推断出,在进行删除操作时,真正的删除点必定是只有一个孩子或没有孩子的结点。而根据红黑树的性质可以得出以下两个结论:

1、 删除操作中真正被删除的必定是只有一个红色孩子或没有孩子的结点。

2、 如果真正的删除点是一个红色结点,那么它必定是一个叶子结点。

在以下讨论中,真正的删除点使用“旧”标注,旧点所在位置将被它的的孩子结点所取代(最多只有一个孩子),我们使用“新”表示旧点的孩子结点。删除操作可分为以下几种情形:

1、旧点为红色结点

若旧点为红色结点,则它必定是叶子结点,直接删除即可。

2、一红一黑

当旧点为黑色结点,新点为红色结点时,将新点取代旧点位置后,将新点染成黑色即可。这里需要注意:旧点为红色,新点为黑色的情况不可能存在。

3、双黑

当旧点和新点都为黑色时(新点为空结点时,亦属于这种情况),情况比较复杂,需要根据旧点兄弟结点的颜色来决定进行什么样的操作。我们使用“兄”来表示旧点的兄弟结点。这里可分为红兄和黑兄两种情况:

3.1 红兄

由于兄弟结点为红色,所以父结点必定为黑色,而旧点被删除后,新点取代了它的位置。下图演示了两种可能的情况:

红兄的情况需要进行RR或LL型旋转,然后将父结点染成红色,兄结点染成黑色。然后重新以新点为判定点进行平衡操作。我们可以观察到,旋转操作完成后,判定点没有向上回溯,而是降低了一层,此时变成了黑兄的情况。

3.2 黑兄

黑兄的情况最为复杂,需要根据黑兄孩子结点(这里用“侄”表示)和父亲结点的颜色来决定做什么样的操作。

3.2.1 黑兄二黑侄红父

如图所示,这种情况比较简单,只需将父结点变为黑色,兄结点变为黑色,新结点变为黑色即可,删除操作到此结束。

3.2.2 黑兄二黑侄黑父

如图所示,此时将父结点染成新结点的颜色,新结点染成黑色,兄结点染成红色即可。当新结点为红色时,父结点被染成红色,此时需要以父结点为判定点继续向上进行平衡操作。

3.2.3 黑兄红侄

黑兄红侄有以下四种情形,下面分别进行图示:

情形1:

删除操作也可参考http://blog.csdn.net/goodluckwhh/article/details/12718233

//参考代码
#include "stdafx.h"
#define BLACK 1
#define RED 0
#include<iostream>
#include<string>
using namespace std;

class bst {
private:

    struct Node {
        int value;
        bool color;
        Node *leftTree, *rightTree, *parent;

        Node() {
            color = RED;
            leftTree = NULL;
            rightTree = NULL;
            parent = NULL;
            value = 0;
        }

        Node* grandparent() {
            if (parent == NULL) {
                return NULL;
            }
            return parent->parent;
        }

        Node* uncle() {
            if (grandparent() == NULL) {
                return NULL;
            }
            if (parent == grandparent()->rightTree)
                return grandparent()->leftTree;
            else
                return grandparent()->rightTree;
        }

        Node* sibling() {
            if (parent->leftTree == this)
                return parent->rightTree;
            else
                return parent->leftTree;
        }
    };

    void rotate_right(Node *p) {
        Node *gp = p->grandparent();
        Node *fa = p->parent;
        Node *y = p->rightTree;

        fa->leftTree = y;

        if (y != NIL)
            y->parent = fa;
        p->rightTree = fa;
        fa->parent = p;

        if (root == fa)
            root = p;
        p->parent = gp;

        if (gp != NULL) {
            if (gp->leftTree == fa)
                gp->leftTree = p;
            else
                gp->rightTree = p;
        }

    }

    void rotate_left(Node *p) {
        if (p->parent == NULL) {
            root = p;
            return;
        }
        Node *gp = p->grandparent();
        Node *fa = p->parent;
        Node *y = p->leftTree;

        fa->rightTree = y;

        if (y != NIL)
            y->parent = fa;
        p->leftTree = fa;
        fa->parent = p;

        if (root == fa)
            root = p;
        p->parent = gp;

        if (gp != NULL) {
            if (gp->leftTree == fa)
                gp->leftTree = p;
            else
                gp->rightTree = p;
        }
    }

    string outputColor(bool color) {
        return color ? "BLACK" : "RED";
    }
    void inorder(Node *p) {
        string str;
        if (p == NIL)
            return;

        if (p->leftTree)
            inorder(p->leftTree);
        str = outputColor(p->color);
        cout << p->value << ":" << str << " ";

        if (p->rightTree)
            inorder(p->rightTree);
    }

    Node* getSmallestChild(Node *p) {
        if (p->leftTree == NIL)
            return p;
        return getSmallestChild(p->leftTree);
    }

    bool delete_child(Node *p, int data) {
        if (p->value > data) {
            if (p->leftTree == NIL) {
                return false;
            }
            return delete_child(p->leftTree, data);
        }
        else if (p->value < data) {
            if (p->rightTree == NIL) {
                return false;
            }
            return delete_child(p->rightTree, data);
        }
        else if (p->value == data) {
            if (p->rightTree == NIL) {
                delete_one_child(p);
                return true;
            }
            Node *smallest = getSmallestChild(p->rightTree);
            swap(p->value, smallest->value);
            delete_one_child(smallest);

            return true;
        }
    }

    void delete_one_child(Node *p) {
        Node *child = p->leftTree == NIL ? p->rightTree : p->leftTree;
        if (p->parent == NULL && p->leftTree == NIL && p->rightTree == NIL) {
            p = NULL;
            root = p;
            return;
        }

        if (p->parent == NULL) {
            delete  p;
            child->parent = NULL;
            root = child;
            root->color = BLACK;
            return;
        }

        if (p->parent->leftTree == p) {
            p->parent->leftTree = child;
        }
        else {
            p->parent->rightTree = child;
        }
        child->parent = p->parent;

        if (p->color == BLACK) {
            if (child->color == RED) {
                child->color = BLACK;
            }
            else
                delete_case(child);
        }

        delete p;
    }

    void delete_case(Node *p) {
        if (p->parent == NULL) {
            p->color = BLACK;
            return;
        }
        if (p->sibling()->color == RED) {
            p->parent->color = RED;
            p->sibling()->color = BLACK;
            if (p == p->parent->leftTree)
                rotate_left(p->sibling());
            else
                rotate_right(p->sibling());
        }
        if (p->parent->color == BLACK && p->sibling()->color == BLACK
            && p->sibling()->leftTree->color == BLACK && p->sibling()->rightTree->color == BLACK) {
            p->sibling()->color = RED;
            delete_case(p->parent);
        }
        else if (p->parent->color == RED && p->sibling()->color == BLACK
            && p->sibling()->leftTree->color == BLACK && p->sibling()->rightTree->color == BLACK) {
            p->sibling()->color = RED;
            p->parent->color = BLACK;
        }
        else {
            if (p->sibling()->color == BLACK) {
                if (p == p->parent->leftTree && p->sibling()->leftTree->color == RED
                    && p->sibling()->rightTree->color == BLACK) {
                    p->sibling()->color = RED;
                    p->sibling()->leftTree->color = BLACK;
                    rotate_right(p->sibling()->leftTree);
                }
                else if (p == p->parent->rightTree && p->sibling()->leftTree->color == BLACK
                    && p->sibling()->rightTree->color == RED) {
                    p->sibling()->color = RED;
                    p->sibling()->rightTree->color = BLACK;
                    rotate_left(p->sibling()->rightTree);
                }
            }
            p->sibling()->color = p->parent->color;
            p->parent->color = BLACK;
            if (p == p->parent->leftTree) {
                p->sibling()->rightTree->color = BLACK;
                rotate_left(p->sibling());
            }
            else {
                p->sibling()->leftTree->color = BLACK;
                rotate_right(p->sibling());
            }
        }
    }

    void insert(Node *p, int data) {
        if (p->value >= data) {
            if (p->leftTree != NIL)
                insert(p->leftTree, data);
            else {
                Node *tmp = new Node();
                tmp->value = data;
                tmp->leftTree = tmp->rightTree = NIL;
                tmp->parent = p;
                p->leftTree = tmp;
                insert_case(tmp);
            }
        }
        else {
            if (p->rightTree != NIL)
                insert(p->rightTree, data);
            else {
                Node *tmp = new Node();
                tmp->value = data;
                tmp->leftTree = tmp->rightTree = NIL;
                tmp->parent = p;
                p->rightTree = tmp;
                insert_case(tmp);
            }
        }
    }

    void insert_case(Node *p) {
        if (p->parent == NULL) {
            root = p;
            p->color = BLACK;
            return;
        }
        if (p->parent->color == RED) {
            if (p->uncle()->color == RED) {
                p->parent->color = p->uncle()->color = BLACK;
                p->grandparent()->color = RED;
                insert_case(p->grandparent());
            }
            else {
                if (p->parent->rightTree == p && p->grandparent()->leftTree == p->parent) {
                    rotate_left(p);
                    rotate_right(p);
                    p->color = BLACK;
                    p->leftTree->color = p->rightTree->color = RED;
                }
                else if (p->parent->leftTree == p && p->grandparent()->rightTree == p->parent) {
                    rotate_right(p);
                    rotate_left(p);
                    p->color = BLACK;
                    p->leftTree->color = p->rightTree->color = RED;
                }
                else if (p->parent->leftTree == p && p->grandparent()->leftTree == p->parent) {
                    p->parent->color = BLACK;
                    p->grandparent()->color = RED;
                    rotate_right(p->parent);
                }
                else if (p->parent->rightTree == p && p->grandparent()->rightTree == p->parent) {
                    p->parent->color = BLACK;
                    p->grandparent()->color = RED;
                    rotate_left(p->parent);
                }
            }
        }
    }

    void DeleteTree(Node *p) {
        if (!p || p == NIL) {
            return;
        }
        DeleteTree(p->leftTree);
        DeleteTree(p->rightTree);
        delete p;
    }
public:

    bst() {
        NIL = new Node();
        NIL->color = BLACK;
        root = NULL;
    }

    ~bst() {
        if (root)
            DeleteTree(root);
        delete NIL;
    }

    void inorder() {
        if (root == NULL)
            return;
        inorder(root);
        cout << endl;
    }

    void insert(int x) {
        if (root == NULL) {
            root = new Node();
            root->color = BLACK;
            root->leftTree = root->rightTree = NIL;
            root->value = x;
        }
        else {
            insert(root, x);
        }
    }

    bool delete_value(int data) {
        return delete_child(root, data);
    }
private:
    Node *root, *NIL;
};

int _tmain(int argc, _TCHAR* argv[])
{
    bst bt;
    int i,j;
    for (i = 0,j=21; i <= 3&&j>=18; i++,j--)
    {
        bt.insert(i);
        bt.insert(j);
    }
    bt.inorder();
    return 0;
}
时间: 2024-10-11 15:54:51

浅谈红黑树的添加删除操作的相关文章

浅谈红黑树(C语言代码实现)

定义: 我们先来看看<算法导论>中的红黑树的定义:"红黑树是许多'平衡'搜索树的一种,可以保证在最坏的情况下基本动态集合操作的时间复杂度为O(lgn)." 性质: 红黑树的性质如下: 1.每个节点是红色的,或者是黑色的. 2.根节点和叶子节点是黑色的. 3.如果一个节点是红色的,那么它的父节点和子节点必须是黑色的. 4.对于每一个节点来说,从该节点到叶子节点的简单路径上,所包含的黑色节点的数量必须一致. 节点属性: 红黑树每个节点的基本属性值有五个: 1.color:表示该

Qt树形控件QTreeView使用1——节点的添加删除操作 复选框的设置

QtreeView是ui中最常用的控件,Qt中QTreeWidget比QTreeView更简单,但没有QTreeView那么灵活(QTreeWidget封装的和MFC的CTreeCtrl很类似,没有mvc的特点). 1. QStandardItemModel在QTreeView中的使用 使用QTreeView的对应模型是QStandardItemModel,这个是Qt对应ui界面最有用的模型,它可以用于树形控件.列表控件.表格控件等等和条目有关的控件.QStandardItemModel用于列表

红黑树、插入删除操作

二叉排序树 一棵自平衡的二叉排序树(二叉搜索树) 生成二叉排序树的过程是非常容易失衡的,最坏的情况就是一边倒(只有右/左子树),这样会导致二叉树的检索效率大大降低(O(n)). 为了维持二叉树的平衡,有各种的算法,如:AVL,SBT,伸展树,TREAP ,红黑树等等. 红黑树 红黑树需要满足5条性质: - 节点非红即黑 - 根节点是黑色 - 所有NULL结点称为叶子节点,且认为颜色为黑 - 所有红节点的子节点都为黑色,一条路径上不能出现相邻的两个红色结点 - 从任一节点到其叶子节点的所有路径上都

浅谈红黑树

红黑树是什么? 其实也是平衡二叉树,只是给每个节点标了红黑颜色 为什么需要红黑树? 红黑树其实基础还是二叉查找树,只是因为二叉查找树很容易出现不平衡的情况,最坏情况相当于O(n),红黑树和AVL树应运而生,AVL树的话,因为平衡度要求是[-1,1]太严格,所以插入和删除的时候的效率并不是很高,比不上红黑树,但是因为平衡度是[-1,1],所以查找速度比红黑树快,AVL适用于频繁查找,红黑树适用于频繁插入和删除 红黑树五大特性 1,每个节点不是黑色就是红色 2,根节点肯定是黑色 3,叶子节点肯定是黑

WinForm 控件TabelControl对TabelPage页的添加,删除操作

一般是写一个按钮点击事件 实现了选中那个关那个 //点击添加按钮 private void button1_Click(object sender, EventArgs e) { tabControl1.TabPages.Add("新建页面"); } //点击删除按钮 private void button2_Click(object sender, EventArgs e) { //获取选中选项卡的索引 int x = tabControl1.SelectedIndex; tabCo

C#环境datagidview添加删除操作

添加 行 dataGridView1.Rows.Add();//添加空行 dataGridView1.Rows.Add("a","b"……);//添加指定列数的行 删除 行 dataGridView1.Rows.Remove(dataGridView1 .CurrentRow);//删除当前光标所在的行 dataGridView1.Rows.Remove(dataGridView1.Rows[0]);//删除指定行数的行 dataGridView1.Rows.Rem

浅谈红黑树——java面试拦路虎

红黑树相信经过面试官折磨的人都不会太陌生,作为数据结构中较复杂都一种,一直是面试中面试官常用的虐杀手段.废话不多说,直接进入正题. 在了解红黑树之前,先要了解二叉查找数,又叫二叉树.二叉树顾名思义,是一种每个节点最多有两个子节点都树,同时遵循 左节点的值<父节点的值<右节点的值 这样的规律,如下图所示. 它是一种查找次数小于等于树高的数据结构.如图中树有4层,即树高为4,当我们需要查找8时,经过的路线是这样的: 1.8<9,往左查找 2.8>5,往右查找 3.8>7,往右查找

第五十六课 树中结点的删除操作

返回的指针谁来负责释放呢?我们采取的措施是使用智能指针来管理这棵树的生命周期. 返回一棵子树的好处是在某些场合,我们能够将H.I.J.M重组,并将它们重新的加回原来的树中. 示例: main函数使用了p指针指向的内存,但是不负责释放,因为从main函数的角度来看,这片内存不是main函数申请的,而从func函数的角度来看,这片内存是申请给main函数用的,func返回之后就无法控制这片内存了.而C++本身又没有内存释放机制.因此,这片内存处于三不管地带,我们要用智能指针来管理. 于是改造成如下的

红黑树的删除操作详解

注:本文转载自博客园,博主原址:http://www.cnblogs.com/tongy0/p/5460623.html,感谢博主帮我弄清楚了红黑树删除操作,转载做收藏用. 红黑树的删除操作 1:节点命名约定 D表示要被删除的节点.即:取 Delete 的首字母: P 表示父节点.即:取 Parent 的首字母: S表示兄弟姐妹节点.即:取 Sibling的首字母: U表示叔伯节点.即:取Uncle的首字母: G表示祖父节点.即:取 Grandfather的首字母: L表示左树.即:取Left的