RB树(红黑树)插入以及删除

红黑树(Red Black Tree) 是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。

它是在1972年由Rudolf Bayer发明的,当时被称为平衡二叉B树(symmetric binary B-trees)。后来,在1978年被 Leo J. Guibas 和 Robert Sedgewick 修改为如今的“红黑树”。
红黑树和AVL树类似,都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能。
它虽然是复杂的,但它的最坏情况运行时间也是非常良好的,并且在实践中是高效的: 它可以在O(log n)时间内做查找,插入和删除,这里的n 是树中元素的数目。
好了废话不多说,直接上代码,这儿是一篇详细介绍插入删除的文章
github地址:这里

 1 #ifndef _RBTREE_H
  2 #define _RBTREE_H
  3
  4 #include<iostream>
  5 #include<stdlib.h>
  6 #include<assert.h>
  7 using namespace std;
  8
  9 enum COLOR{RED = 0,BLACK};
 10
 11 template<class T>
 12 class RBTree;
 13
 14 template<class T>
 15 class RBTreeNode                //红黑树结点类
 16 {
 17     friend class RBTree<T>;
 18 private:
 19     T               data;       //数据域
 20     COLOR           color;      //颜色
 21     RBTreeNode<T>   *parent;    //父结点
 22     RBTreeNode<T>   *leftChild,*rightChild;     //左右子女指针
 23 public:
 24     RBTreeNode():data(T(),color(RED),parent(NULL),leftChild(NULL),rightChild(NULL))     //无参构造函数
 25     {}
 26     RBTreeNode(T d,COLOR c = RED,RBTreeNode<T> *pr = NULL,RBTreeNode<T> *left = NULL,RBTreeNode<T> *ri    ght = NULL):data(d),color(c),parent(pr),leftChild(left),rightChild(right)                 //带参构造函27     {}
 28     ~RBTreeNode()
 29     {}
 30 };
 31
 32 template<class T>
 33 class RBTree                    //红黑树类定义
 34 {
 35 private:
 36     RBTreeNode<T> *root;        //根结点
 37 public:
 38     RBTree():root(NULL)         //空树
 39     {
 40     }
 41     bool Insert(const T& x)     //插入函数
 42     {
 43         Insert(root,x);
 44     }
 45 protected:
 46     bool Insert(RBTreeNode<T> *& t,const T& x)
 47     {
 48         RBTreeNode<T> *p = t;
 49         RBTreeNode<T> *pr = NULL;       //插入位置的父结点
 50         while(p != NULL)                    //找到要插入的位置
 51         {
 52             if(x == p->data)
 53                 return false;
 54
 55             pr = p;
 56
 57             if(x < p->data)
 58                 p = p ->leftChild;
 59             else
 60                 p = p->rightChild;
 61         }
 62
 63         p = _BuyNode(x);                    //申请结点
 64
 65         if(pr == NULL)                      //插入的为根位置
 66         {
 67             t = p;
 68             t->color = BLACK;
 69             return true;
 70         }
  71
 72         if(x < pr->data)                    //插入的位置为左子树
 73             pr->leftChild = p;
 74         else
 75             pr->rightChild = p;             //插入的位置为右子树
 76         p->parent = pr;
 77
 78         _Balance_Tree(t,p);         //调整树的位置 即平衡树
 79     }
 80     RBTreeNode<T>* _BuyNode(const T& x)
 81     {
 82         RBTreeNode<T> *p = new RBTreeNode<T>(x);
 83         assert(p != NULL);
 84         return p;
 85     }
 86     void _Balance_Tree(RBTreeNode<T> *& t,RBTreeNode<T> *p)
 87     {
 88         RBTreeNode<T> *s;
 89         while(p->parent != NULL && p->parent->color == RED)         //p插入的父结点的父亲的颜色是否为>    红色
 90         {
 91             if(p->parent == p->parent->parent->leftChild)       //p的父亲是在外侧插入
 92             {
 93                 s = p->parent->parent->rightChild;              //s为插入结点的父结点的兄弟结点
 94
 95                 if(s != NULL && s->color == RED)            //只要看到有某结点X的两个子节点皆为红色,>    就把X改为红色,并把两个子节点改为黑色, 但是此时如果X的父结点p亦为红色,就得像状况1一样地做一次单旋转>    并改变颜色,或是像状况2一样地做一次双旋转并改变颜色。
 96                 {
 97                     p->parent->color = BLACK;
 98                     s->color = BLACK;
 99                     p->parent->parent->color = RED;
100                     p = p->parent->parent;
101                     continue;
102                 }
103                 else if(p == p->parent->rightChild)         //情况2 <
104                 {
105                     p = p->parent;
106                     RotateL(p);
107                 }
108
109                 p->parent->color = BLACK;                   //情况3
110                 p->parent->parent->color = RED;
111                 RotateR(p->parent->parent);
112             }
113             else
114             {
115                 s = p->parent->parent->leftChild;
116
117                 if(s != NULL && s->color == RED)
118                 {
119                     s->color = BLACK;
120                     p->parent->color = BLACK;
121                     p->parent->parent->color = RED;
122                     p = p->parent->parent;
123                     continue;
124                 }
125                 else if(p == p->parent->leftChild)
126                 {
127                     p = p->parent;
128                     RotateR(p);
129                 }
130
131                 p->parent->color = BLACK;
132                 p->parent->parent->color = RED;
133                 RotateL(p->parent->parent);
134             }
135         }
136         t->color = BLACK;
137     }
138
139 /*
233 private:
234     void RotateR(RBTreeNode<T> * ptr)       //右旋函数
235     {
236         RBTreeNode<T> *subR = ptr;      //右结点
237         ptr = ptr->leftChild;           //新的根结点
238         subR->leftChild = ptr->rightChild;  //ptr成为新根前处理其右边的结点
239         if(ptr->rightChild != NULL)         //如果ptr的右子女结点存在
240             ptr->rightChild->parent = subR;
241         if(subR->parent == NULL)
242             root = ptr;
243         else
244         {
245             if(subR == subR->parent->leftChild) //subR为父结点的的左子树
246                 subR->parent->leftChild = ptr;
247             else
248                 subR->parent->rightChild = ptr;
249         }
250         ptr->parent = subR->parent;         //将父结点连接起来
251         ptr->rightChild = subR;             //ptr成为新结点
252         subR->parent = ptr;
253     }
254     void RotateL(RBTreeNode<T> *ptr)    //左旋函数
255     {
256         RBTreeNode<T> *subL = ptr;      //左结点
257         ptr = ptr->rightChild;          //新到的根节点
258         subL->rightChild = ptr->leftChild;  //ptr成为新根前处理其左边的结点
259         if(ptr->leftChild != NULL)          //如果ptr的左结点存在 连接其父结点
260             ptr->leftChild->parent = subL;
261         if(subL->parent == NULL)            //如果到达了根结点
262             root = ptr;
263         else
264         {
265             if(subL == subL->parent->leftChild) //确定新根的位置
266                 subL->parent->leftChild = ptr;
267             else
268                 subL->parent->rightChild = ptr;
269         }
270         ptr->parent = subL->parent;     //连接其父结点
271         ptr->leftChild = subL;          //连接子女
272         subL->parent = ptr;
273     }
274 };
275
276
277
278 #endif

测试代码

  1 #include"./rbtree.h"
  2
  3 int main()
  4 {
  5
  6     RBTree<int> rb;
  7     int ar[] = {100,70,80,50,40,75,73,72,74,71};
  8     int n = sizeof(ar)/sizeof(int);
  9
 10     for(int i = 0; i < n; ++i)
 11     {
 12         rb.Insert(ar[i]);
 13     }
 14     return 0;
 15 }

上面的做法太过于麻烦,每次都要判断结点是否为空,所以后面加入了头结点即哨兵位置。
github地址:这里

#ifndef _RBTREE_H
#define _RBTREE_H

#include<iostream>
#include<assert.h>
#include<stdlib.h>
#include<string.h>
using namespace std;

typedef enum{RED = 0,BLACK}COLOR;
typedef int Type;

typedef struct RBNode               //结点声明
{
    int value;                  //数据域
    COLOR color;                    //颜色
    struct RBNode* parent;      //父结点
    struct RBNode* left;            //左右子结点
    struct RBNode* right;
}RBNode;

typedef struct RBTree
{
    RBNode *root;           //根结点
    RBNode *NIL;            //哨兵位置
}RBTree;

RBNode* _Buynode(Type v)        //申请结点函数
{
    RBNode *s = (RBNode*)malloc(sizeof(RBNode));    //申请空间
    assert(s != NULL);
    memset(s,0,sizeof(RBNode));         //初始化
    s->value = v;
    s->color = RED;
    return s;
}

void InitRBTree(RBTree &t)      //初始化函数
{
    t.NIL = _Buynode(0);        //哨兵初始化
    t.root = t.NIL;
    t.NIL->color = BLACK;
}

void RotateL(RBTree &t,RBNode *p)       //左旋
{
    RBNode *s = p->right;           //新的根结点
    p->right = s->left;             //s成为新根前扔掉其左边结点
    if(s->left != NULL)
        s->left->parent = p;
    s->parent = p->parent;          //连接父结点
    if(p->parent == t.NIL)          //p的父亲为空
        t.root = s;                 //即根结点
    else if(p == p->parent->left)   //找到其应该存在的结点
        p->parent->left = s;
    else
        p->parent->right = s;
    s->left = p;                    //s成为新结点
    p->parent = s;
}

void RotateR(RBTree &t,RBNode *p)   //右旋
{
    RBNode *s = p->left;
    p->left = s->right;
    if(s->right != NULL)
        s->right->parent = p;
    s->parent = p->parent;
    if(p->parent != t.NIL)
        t.root = s;
    else if(p == p->parent->left)
        p->parent->left = s;
    else
        p->parent->right = s;
    s->right = p;
    p->parent = s;
}

void Insert_Fixup(RBTree &t,RBNode *z)  //删除调整函数
{
    RBNode *y;      //伯父结点
    while(z->parent->color == RED)      //其父结点为红色 就需要调整
    {
        if(z->parent == z->parent->parent->left)    //z的父结点是在左子树
        {
            y = z->parent->parent->right;   //伯父结点
            if(y->color == RED)         //伯父结点为红色
            {
                z->parent->color = BLACK;
                y->color = BLACK;
                z->parent->parent->color = RED;
                z = z->parent->parent;
                continue;       //向上回朔
            }
            else if(z == z->parent->right)      //伯父结点为黑色并且插入的新结点是在外侧
            {
                z = z->parent;
                RotateL(t,z);
            }
            //插入节点是在内测的情况下
            z->parent->parent->color = RED;
            z->parent->color = BLACK;
            RotateR(t,z->parent->parent);
        }
        else            //z的父结点是在右子树
        {
            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;
                continue;
            }
            else if(z == z->parent->left)
            {
                z = z->parent;
                RotateR(t,z);
            }
            z->parent->parent->color = RED;
            z->parent->color = BLACK;
            RotateL(t,z->parent->parent);
        }
    }
    t.root->color = BLACK;
}

bool Insert(RBTree &t,Type x)       //插入函数
{
    RBNode *pr = t.NIL;
    RBNode *s = t.root;
    while(s != t.NIL)       //不是根结点 就寻找应该插入的位置
    {
        if(x == s->value)
            return false;
        pr = s;
        if(x < s->value)
            s = s->left;
        else
            s = s->right;
    }

    RBNode *q = _Buynode(x);        //申请结点
    q->parent = pr;                 //连接
    q->left = t.NIL;
    q->right = t.NIL;
    q->color = RED;

    if(pr == t.NIL)
        t.root = q;
    else if(x < pr->value)
        pr->left = q;
    else
        pr->right = q;

        Insert_Fixup(t,q);
        return true;

}

RBNode* _Next(RBTree &t,RBNode *p)      //找到p结点对应的右边的前驱
{
    if(p != t.NIL && p->right != t.NIL)
    {
        p = p->right;
        while(p->right != t.NIL)
            p = p->left;
    }
    return p;
}

void Delete_Fixup(RBTree &t,RBNode *& x)        //删除调整平衡函数
{
    RBNode *w;
    while(x != t.root && x->color == BLACK)
    {
        if(x == x->parent->left)    //左分支
        {
            w = x->parent->right;       //w是x的兄弟结点
            if(w->color == RED)
            {
                w->color = BLACK;
                x->parent->color = RED;
                RotateL(t,x->parent);
            }
            if(w->left->color == BLACK && w->right->color == BLACK)
            {
                w->color = RED;
                x = x->parent;
            }
            else if(w->right->color == BLACK)
            {
                w->left->color = BLACK;
                w->color = RED;
                RotateR(t,w);
                w = x->parent->right;
            }   
            // \  情况
            w->color = x->parent->color;
            x->parent->color = BLACK;
            w->right->color = BLACK;
            RotateL(t,x->parent);       //左转
            x = t.root;
        }
        else                    //右分支
        {
            w = x->parent->left;    //w是x的兄弟结点
            if(w->color == RED)
            {
                w->color = BLACK;
                x->parent->color = RED;
                RotateR(t,x->parent);
            }
            if(w->left->color == BLACK && w->right->color == BLACK)
            {
                w->color = RED;
                x = x->parent;
            }
            else if(w->left->color == BLACK)
            {
                w->right->color = BLACK;
                w->color = RED;
                RotateL(t,w);
                w = x->parent->left;
            }
            w->color = x->parent->color;
            x->parent->color = BLACK;
            w->left->color = BLACK;
            RotateR(t,x->parent);
            x = t.root;
        }
    }
    x->color = BLACK;
}

bool Remove(RBTree &t,Type x)       //删除函数
{
    RBNode *p = t.root;
    RBNode *y;
    RBNode *s;
    while(p != t.NIL && p->value != x)
    {
        if(x < p->value)
            p = p->left;
        else
            p = p->right;
    }

    if(p->left != t.NIL && p->right != t.NIL)       //被删除的结点右两个子女结点
        y = _Next(t,p);                             //找到内删除的结点的后继
    else
        y = p;

    if(y->left != t.NIL)            //如果即将删除的结点有左子女
        s = y->left;
    else                            //有右子女
        s = y->right;

    s->parent = y->parent;          //连接父结点
    if(y->parent == t.NIL)          //要删除的结点是根结点
        t.root = s;
    else if(y == y->parent->left)
        y->parent->left = s;
    else
        y->parent->right = s;

    if(y != p)
        p->parent->value = y->value;            //用替换的结点的值去覆盖前面的结点

    if(y->color == BLACK)
        Delete_Fixup(t,s);          //恢复平衡函数
    delete y;
    return true;
}

#endif

测试代码

#include"./rbtree.h"

int main()
{
    int ar[] = {100,70,80,40,75,73,72,74};
    int n = sizeof(ar) / sizeof(int);
    RBTree rb;
    InitRBTree(rb);

    for(int i = 0; i < n; ++i)
    {
        Insert(rb,ar[i]);
    }
    Remove(rb,50);
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 好的,我可以给你一些关于红黑树的信息。 红黑树是一种自平衡二叉搜索树,具有以下性质: 1. 节点是红色或黑色。 2. 根节点是黑色。 3. 每个叶子节点(NIL)是黑色。 4. 每个红色节点的两个子节点都是黑色。 5. 从任一节点到其叶子节点的所有路径都包含相同数目的黑色节点。 以下是一个用 C 语言实现的红黑树的示例代码: ``` #include <stdio.h> #include <stdlib.h> typedef struct _rbtree { int key; char color; struct _rbtree *left; struct _rbtree *right; struct _rbtree *parent; } rbtree; #define NIL &sentinel /* all leafs are sentinels */ rbtree sentinel = { 0, 'B', NIL, NIL, NIL }; void insert(rbtree *tree, int key); void delete(rbtree *tree, int key); void search(rbtree *tree, int key); void rbtree_print(rbtree *tree); int main(int argc, char **argv) { rbtree *root = NIL; insert(root, 5); insert(root, 10); insert(root, 15); insert(root, 20); insert(root, 25); rbtree_print(root); delete(root, 15); delete(root, 20); rbtree_print(root); search(root, 25); search(root, 30); return 0; } void insert(rbtree *tree, int key) { rbtree *current, *parent, *x; /* find future parent */ current = tree; parent = 0; while (current != NIL) { if (key == current->key) return; parent = current; current = key < current->key ? current->left : current->right; } /* setup new node */ if ((x = malloc (sizeof(*x))) == 0) return; x->key = key; ### 回答2: 红黑树是一种自平衡的二叉查找树,可以通过颜色属性来保持平衡。下面是用C语言实现红黑树的大致步骤: 1. 定义红黑树的结构体:包括节点的关键字、颜色、父节点、左孩子、右孩子等属性。 2. 实现红黑树的基本操作函数:包括插入删除、搜索、旋转等。 3. 实现插入操作:插入节点时,首先按照二叉查找树的规则找到合适的位置,然后根据红黑树的规则调整颜色和结构,确保树的平衡性。 4. 实现删除操作:删除节点时,首先处理删除节点的子节点情况,然后根据红黑树的规则调整颜色和结构,确保树的平衡性。 5. 实现搜索操作:按照二叉查找树的规则搜索指定关键字的节点。 6. 实现旋转操作:包括左旋和右旋操作,用于调整树的结构。 通过上述步骤,可以完成红黑树的基本实现。在实际使用中,可以根据具体需求扩展并优化红黑树的功能。 ### 回答3: 红黑树是一种自平衡的二叉搜索树,它具有一些特殊的性质。为了用C语言实现红黑树,我们可以按照以下步骤进行: 1. 定义红黑树的结构体 首先,我们需要定义红黑树的结构体。结构体包含一个指向树根的指针和其他必要的变量,例如,节点的颜色。 2. 实现基本的操作函数 我们需要实现红黑树的基本操作函数,包括插入删除和查找。这些函数将根据红黑树的性质进行相应的操作,以保持树的平衡。 3. 实现节点的插入插入节点时,我们需要按照二叉搜索树的规则找到插入位置,并进行一系列的旋转操作以保持红黑树的性质。 4. 实现节点的删除 节点的删除涉及到红黑树性质的调整,它不同于普通二叉搜索树的删除。在删除节点后,我们需要对树进行旋转操作和重着色以保持平衡。 5. 实现查找函数 查找函数通过遍历红黑树并比较节点的值,找到目标节点并返回。这个函数可以按照二叉搜索树的查找方式实现。 通过以上步骤,我们可以实现一个红黑树的基本功能。当然,红黑树还有一些高级操作,例如,RB-Insert-Fixup 和 RB-Delete-Fixup,用于处理插入删除时的特殊情况。这些操作会在插入删除函数中被调用。 总之,用C语言实现一个红黑树需要定义适当的数据结构,并编写相应的插入删除和查找函数,同时保持树的平衡性质。完成这个任务需要一定的知识和编程经验,但通过充分理解红黑树的性质和操作,我们可以很好地完成这个任务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值