红黑树详解

前言:

         之所以要写这篇文章,第一个目的是为了各位朋友在查看我写的源代码之前有一个可以理解理论的文章因为红黑树还是有点难的,

如果不想搞懂理论,而直接看代码,那绝对是云里雾里,不知所云。第二个目的是我觉得网上虽然后不少我文章也在讲,但是我就是理解

不上有点困难,在我参考了很多文章之后,认真阅读才慢慢摸透了其中的原理,所以我想用自己的方式来表达,希望有助于各位的朋友理解。

你可以在这里获得配套源代码


红黑树由来:

         他是在1972年 由Rudolf Bayer发明的,他称之为“对称二叉B树”,它现代的名字是Leo J. Guibas和 Robert Sedgewick 于1978

年写的一篇论文中获得的。它是复杂的,但它的操作有着良好的最坏情况运行时间,并且在实践中是高效的: 它可以在O(log n)时间内做查找,

插入和删除,这里的n 是树中元素的数目。


红黑树性质:

1. 每个结点或红或黑。

2. 根结点为黑色。

3. 每个叶结点(实际上就是NULL指针)都是黑色的。

4. 如果一个结点是红色的,那么它的周边3个节点都是黑色的。

5. 对于每个结点,从该结点到其所有子孙叶结点的路径中所包含的黑色结点个数都一样。


讨论的前提:

1,我们只讨论往树的左边和从树的左边删除的情况,与之对称的情况一样。

2,假设我们要删除一个元素的方法都是采取删除后继节点,而非前驱节点。

3,NL或全黑表示黑空节点,也可以不用画出。

4,“=>”这个符号我们用来表示“变成”的意思。

一. 插入

当红黑树中没有节点的时候,新节点直接涂黑就可以了。

当树中已有节点,我们就将新节点涂红,并且底下挂两个黑空节点。

1.1 新节点的父亲为黑色

这种情况最简单,只接插入将新节点可以了,不会出现红色警戒。

1.2 新节点的父亲为红色

这种情况出现红色警戒,并且通过红色的父亲,我们可以推出一定有一个黑色的父, 并且父亲不可能为树根(树根必须为黑)。

这种情况需要修复。

1.2.1 新节点的叔叔是红色。(红叔)

图1.2.1-1


图1.2.1-2

注解:在这种情况下,我们可以通过这样的方式来修复红黑树的性质。因为遇到红 色警戒所以我们首先可以想到的就是将父亲变成黑色,但这样祖父的左子树的黑高 就增加了,为了达到祖父的平衡,我们红叔变成黑色,这样祖父就平衡了。但是整 个祖父这颗树的高度增高了,所以再此将祖父的颜色变成红色来保持祖父这颗树的 高度不变。因为祖父变成了红色,因此往上遍历。

       方法:父=>黑;叔=>黑;祖=>红;往上遍历;

1.2.2 新节点的叔叔是黑色(黑叔)

图1.2.2-1

图1.2.2-2

注解:首先可以说明的是,这种情况下我们都可以通过改变颜色和旋转的方式到达 平衡,并且不再出现红色警戒,因为无需往上遍历。图1.2.2-1:首先我们将红父变 成黑色,祖父变成红色,然后对祖父进行右旋转。这样我们可以看到,整颗树的黑 高不变,并且这颗树的左右子树也达到平衡。新的树根为黑色。因此无需往上遍历。

方法:图1.2.2-1  父=>黑;祖=>红;祖父右旋转;

                 图1.2.2-2    新=>黑;祖=>红;父左旋转;祖右旋转;


插入我们就算做完了,与之对称的右边插入的情况完全一样,请自己下来分析;

一. 删除

删除是比较经典但也是最困难的一件事了,所以我们必须一步一步地理解。为了中途思想不混乱,请始终记住一点,下面我们删除的节点都已经表示的是实际要删除的后继节点了。因此可以得出一下结论。

    首先,可以肯定的是我们要删除的节点要么是红色,要么是黑色。

     其次,既然我们要删除的结点是后继节点,那么要删除的节点的左子树一定为空。所以当删除的节点为黑色时只剩下两种情况。

     最后,如果删除的节点为红色,那么它必为叶子节点。(自己好好想象为什么)。

请在看下面的内容前先牢记上面的结论,这样更加方便让你理解下面的知识。

a:当删除的节点为黑色时

               删黑a                删黑b


b:当删除的节点为红色时

      上面的几附图都是很简单的。因为你可以将空节点 去掉不看。所就形成了要 删除的节点要么有一个右孩子,要么为叶子节点。


下面我们就开始真正的删除操作了。

2.1 删除红色节点

注解:这种情况是最简单的,因为根据我们可以推出子节点     一定为空, 也就是说删除的红色节点为叶子节点。只需将这个旧节点的右孩子付给父亲的左孩子就 可以了,高度不变。

方法:略


2.2 删除黑色节点

          遇到黑色节点情况就将变得复杂起来,因此我们一定要慢慢来,仔细分析。

          2.2.1当删除的节点有一个红色子孩子

注解:这种情况其实就是上面我们分析的三种情况之一,如图""。这种情况 是非常简单的,只需将旧节点的右孩子取代旧节点,并将子孩子的颜色变为黑色, 树平衡;

        方法:子取代旧;子=>黑;

2.2.2当删除的节点无左右孩子

这种情况其实就是上面我们分析的三种情况之一,如图"删黑a"。我们推出子节点 一定为空,请务必记住这点,不然在后面你将很容易被混淆,父亲的颜 色我们标记为绿色,是表示,父亲的颜色可为红或黑。黄色的子节点其实就 是一个黑空节点,这样方便后面分析。

a:红兄


注解:当我们删除的节点拥有一个红色的兄弟时,这种情况还相对比较简单,因为 兄弟为黑色,我们可以推出父亲一定为黑色。因为父节点的左树高度减一,所 以我们可以通过左旋转父节点,来将节点1旋转到左边来恢复左边的高度。然 后将父变成红,兄变成黑。这样整颗树的高度不变,父节点也平衡记住子节点 为空所以可以删除看,这样便于理解。       

        方法:父=>红;兄=>黑;左旋转父节点;


b :黑兄

      遇到黑兄就又麻烦了,我们又必须引入要删除的节点的侄子了。所以我们这里 再次细分为b1: 黑兄 双黑侄 b2: 黑兄 左黑侄右红侄 b3: 黑兄 右黑侄左红侄。 可能你会问b4呢,双红侄的情况呢?其实双红侄的情况同属于b2,b3的情况,所以 可以默认用 b2,b3其中一种情况来处理就可以了。

现在我们开始了

      b1黑兄 双黑侄



注解:我们首先可以肯定的是父节点的左子树高度减一了,所以我们必须想方设法 来弥补这个缺陷。如果我们把父节点的右子树高度也减一(兄变成红色)那么 父节点这颗树就可以保持平衡了,但整颗树的高度减一,所以我们可以判断, 如果父亲是红色,那么我们可以通过把父亲变成黑色来弥补这一缺陷。但如果 父亲是黑色呢,既然遇到到黑色了我们就只好往上遍历了。

方法:兄=>红;子=黑;    红父=>黑;

                                  往上遍历(黑父);

补充:其实子节点就是空节点,没有必要变。就算遍历上去,父节点也为黑

b2黑兄 左黑侄右红侄


注解:绿色表示,颜色不影响修复的方式。依然我们可以肯定父节点的左子树高度减一,所以我们可以通过将父节点旋转下来并且变为黑色来弥补,但由于兄弟被旋转上去了,又导致右子树高度减一,但我们这有一个红侄,所以可以通过红侄变成黑色来弥补。父亲所在位置的颜色不变;(子为空)
方法:兄=>父色;父=>黑;侄=>黑;(子=>黑);左旋转父节点;

b3 黑兄 左红侄右黑侄


注解:绿色表示,颜色不影响修复的方式。依然我们可以肯定父节点的左子树高度减一,同样我们通过父节点左旋转到左子树来弥补这一缺陷。但如果直接旋转的话,我们可以推出左右子树将不平衡(黑父),或者两个红色节点相遇(红父);这样将会更加的复杂,甚至不可行。因此,我们考虑首先将兄弟所在子树右旋转,然后再左旋转父子树。这样我们就可以得到旋转后的树。然后通过修改颜色来使其达到平衡,且高度不变。
方法:侄=>父色;父=>黑;右旋转兄;左旋转父;


总结:

如果我们通过上面的情况画出所有的分支图,我们可以得出如下结论

插入操作:解决的是 红-红 问题

删除操作:解决的是 黑-黑 问题

即你可以从分支图中看出,需要往上遍历的情况为红红(插入);或者为黑黑黑(删除)的情况,,如果你认真分析并总结所有的情况后,并坚持下来,红黑树也就没有想象中的那么恐怖了,并且很美妙;

源码:

/***************************************************

filename:rbtree.h

****************************************************/

#ifndef RB_TREE_H

#define RB_TREE_H

/***********************************************************/

/* 相关结构体定义*/

/* 平衡因子类型*/

typedef enum{BLACK, RED}COLOR;

/* 左右类型*/

typedef enum{left, right}type_t;/* 删除节点的时候会用到*/

/* 红黑树节点*/

typedef struct node{

     int          data;    /* 数据   */

    COLOR         color;   /* 颜色   */

     struct node* parent;  /* 父节点 */

     struct node* left;    /* 左孩子 */

     struct node* right;   /* 右孩子 */

}RNode,RTree;

/*BOOL类型*/

typedef enum{truefalse}BOOL;

/***********************************************************/

/* 二叉查找树基本操作函数*/

int     InitTree(RTree**root_p);              /* 二叉树初始化函数*/

RNode*  GetRNode(int data, RNode* parent, RNode* left, RNode*right);  /* 创建二叉树节点*/

RNode*  Search(RNode* root,const int Key);     /* 在查找二叉树中搜索Key */

//覆盖int  Insert(RTree** root_p, int data);   /* 向查找二叉树中插入一个新的节点*/

//覆盖int  Delete(RNode**node_p);            /* 从查找二叉树中删除一个节点*/

int     Remove(RTree**root);                  /* 删除二叉树*/

void LNR(RNode* root, void process(RNode*));   /* 中序遍历二叉树(左、节点、右)*/

void LRN(RNode* root, void process(RNode*));   /* 后序遍历二叉树(左、右、节点)*/

void NLR(RNode* root, void process(RNode*));   /* 前序遍历二叉树(节点、左、右)*/

/***********************************************************/

/* 其他操作*/

RNode*  CopyRTree(RNode*root);        /* 拷贝二叉树*/

int     CountLeaf(RNode*root);        /* 计算二叉树子叶节点个数*/

int     Depth(RNode*root);            /* 计算二叉树深度*/

/***********************************************************/

/* 红黑树操作*/

/* 红黑树的插入、删除*/

int Insert(RTree** root_p, int data);

int Delete(RTree** root_p, int data);

#endif

/*******************************************************

filename:rbtree.c

*******************************************************/

 

#include <stdio.h>      /* printf() */

#include <stdlib.h>     /* malloc() */

#include "rbtree.h"

/********************************

本地红黑树辅助函数声明

*/

/* 右高----左旋转,右平衡*/

static void right_balance(RNode** sub_root_p);

static void rotate_left(RNode** sub_root_p);

/* 左高----右旋转,左平衡*/

static void left_balance(RNode** sub_root_p);

static void rotate_right(RNode** sub_root_p);

static void dright_balance(RTree** root_p, RNode* node, type_ttype);

/* 递归辅助函数*/

static int RBInsert(RTree** root_p, RNode* parent, RTree**sub_root_p, int data);

static int RBDelete(RTree** root_p, RNode* parent, RNode*child);

/* 直接后继函数*/

static RNode* Successor(RNode* node);

/* 定义一个全局的黑空节点*/

RNode BEN;  /*black empty null */

/*

我们定义一个黑空节点指针BNULL,相当于NULL的作用,

但它却能标记空节点,且节点具有黑色的属性,所以请

在下面的程序中始终将BNULL想象成NULL

*/

#define BNULL  &BEN

/********************************

下面是二叉树基本操作

*/

/*---------------------------------------------------------------------

函数名称:InitRTree

  数:root_p   -- 指向树根节点的指针的指针

返回参数:-- 初始化成功

功能描述:初始化一颗二叉树

-----------------------------------------------------------------------

*/

int InitTree(RTree** root_p)

{

    *root_p = BNULL;

     /* 初始化一个黑空节点*/

    BEN.data   = -100;

    BEN.color  = BLACK;

    BEN.parent = NULL;

    BEN.left   = NULL;

    BEN.right  = NULL;

     return 0;

}

 

/*---------------------------------------------------------------------

函数名称:GetRNode

  数:data  --创建节点的数据

parent--新节点的父亲

left--新节点的左子树

right--新节点的右子树

返回参数:nCount -- 叶子的数目

功能描述:创建一个新节点的函数

-----------------------------------------------------------------------

*/

RNode*  GetRNode(int data, RNode* parent, RNode* left, RNode* right)

{

     RNode* newnode = (RNode*)malloc(sizeof(RNode));

     if(newnode == NULL){

         printf("error:no memory!\n");

         return NULL;

    }

    newnode->data   = data;

     newnode->color  =RED;   /* 初始化为红色*/

    newnode->parent = parent;

    newnode->left   = left;

    newnode->right  = right;

     return newnode;

}

 

/*---------------------------------------------------------------------

函数名称:DeleteRTree

  数:root_p   -- 指向树根地址的指针

返回参数:      -- 成功

功能描述:清除一颗二叉树

-------------------------------------------------------------------*/

int Remove(RNode** root_p)

{

     if(*root_p == BNULL){

         return 0;

     }else{

        Remove(&((*root_p)->left));

        Remove(&((*root_p)->right));

        free(*root_p);

        *root_p = BNULL;

    }

     return 0;

}

 

/*---------------------------------------------------------------------

函数名称:Search

  数:root   -- 树的根节点   Key    -- 查找的数据

返回参数:root   -- 指向找到的树节点

BNULL  -- 未找到数据

功能描述:在查找二叉树中搜索Key

-----------------------------------------------------------------------

*/

RNode* Search(RNode* root, const int data)

{

     if(root == BNULL ||root->data == data){

         return root;      

    }

     if(data < root->data)

         return Search(root->left,data);

     else

         return Search(root->right,data);

}

 

/*---------------------------------------------------------------------

函数名称:LNR LRN NLR

  数:root   -- 树的跟节点   process  -- 函数指针

返回参数:无

功能描述:遍历

-----------------------------------------------------------------------

*/

/* 中序遍历二叉树(左、节点、右)*/

void LNR(RNode* root, void process(RNode*))

{

     if(root != BNULL){

        LNR(root->left, process);

        process(root);

        LNR(root->right, process);

    }

}

/* 后序遍历二叉树(左、右、节点)*/

void LRN(RNode* root, void process(RNode*))

{

     if(root != BNULL){

        LRN(root->left, process);  /* 遍历左子树*/

        LRN(root->right, process); /* 遍历右子树*/

        process(root);       /* 访问节点*/

    }

}

/* 前序遍历二叉树(节点、左、右)*/

void NLR(RNode* root, void process(RNode*))

{

     if(root != BNULL){

        process(root);

        NLR(root->left, process);

        NLR(root->right, process);

    }

}

 

/***********************************************************/

/* 其他操作*/

 

/*---------------------------------------------------------------------

函数名称:CopyRTree

  数:root     -- 树的根节点

返回参数:newroot  -- 新术的根节点指针

BNULL    -- 空树

功能描述:利用后序遍历的方法拷贝一个二叉树

-----------------------------------------------------------------------

*/

RNode* CopyRTree(RTree* root)

{

     if(root != BNULL){

        RNode* newlptr = CopyRTree(root->left);

        RNode* newrptr = CopyRTree(root->right);

        RNode* newroot = GetRNode(root->data, root->parent, newlptr, newrptr);

        newroot->color = root->color;

         return newroot;

    }

     return BNULL;

}

 

/*---------------------------------------------------------------------

函数名称:CountLeaf

  数:root   -- 树的根节点

返回参数:nCount -- 叶子的数目

功能描述:计算二叉树的叶子

-----------------------------------------------------------------------

*/

int CountLeaf(RNode*root)

{

     int nCount = 0;

     if(root != BNULL){

        nCount += CountLeaf(root->left);

        nCount += CountLeaf(root->right);

        nCount++;

    }

     return nCount;

}

 

/*---------------------------------------------------------------------

函数名称:Depth

  数:root   -- 树的根节点

返回参数:无

功能描述:计算二叉树的深度

---------------------------------------------------------------------*/

int Depth(RNode*root)

{

     int depth = -1,ldepth=0, rdepth=0;

     if(root != BNULL){

        ldepth = Depth(root->left);

        rdepth = Depth(root->right);

        depth  = 1 + (ldepth > rdepth ? ldepth : rdepth); 

    }

     return depth;

}

 

/***********************************************************/

/*RB树操作*/

 

 

/*---------------------------------------------------------------------

函数名称:Insert

  数:root_p   -- 指向节点之指针的指针

data    -- 插入数的数据

返回参数:--成功  -1 --失败

功能描述:向红黑树中插入一个新的节点

----------------------------------------------------------------------*/

int Insert(RTree** root_p, int data)

{

     int error = 0;

     if(*root_p == BNULL){ /* 红黑树中没有节点*/

        RNode* new =GetRNode(data, BNULL, BNULL, BNULL);

         new->color = BLACK;

        *root_p    = new;

         return 0;

     }else if(data < (*root_p)->data)

         error =RBInsert(root_p, *root_p, &((*root_p)->left), data); /* 此时*root_p不为空*/

     else

         error =RBInsert(root_p, *root_p, &((*root_p)->right), data); /* 此时*root_p不为空*/

     /* 当插入之后当前节点变成了红色,且当前节点为根节点,那么将它变成黑色*/

     if((*root_p)->color ==RED)

        (*root_p)->color = BLACK;

     return error;

}

 

/*---------------------------------------------------------------------

函数名称:RBInsert

  数:parent       --*sub_root_p的父节点指针

sub_root_p  -- 指向树根地址的指针

data        -- 插入的数据

返回参数:         -- 插入成功

-1          -- 插入失败

功能描述:插入递归辅助函数

----------------------------------------------------------------------*/

int RBInsert(RTree** root_p, RNode* parent, RTree**sub_root_p, int data)

{

     int error = 0;

    RNode* grand = BNULL;

    RNode* uncle = BNULL;

     if(*sub_root_p == BNULL){

        *sub_root_p = GetRNode(data, parent, BNULL, BNULL);

         return error;

     }else if(data < (*sub_root_p)->data){

        RBInsert(root_p, *sub_root_p, &((*sub_root_p)->left), data); /* 将新节点插入到当前节点的左子树*/

         if(!((*sub_root_p)->color== RED && (*sub_root_p)->left->color == RED))/* 判断当前节点和父亲是否遇到红色警戒*/

              return error;

         switch((*sub_root_p)->color){     /* 当前节点为父亲*/

              case BLACK: /* 在黑色节点处插入*/

                   break;

              case RED:   /* 在红色节点处插入,需考虑叔叔*/

                  grand =(*sub_root_p)->parent;                /* 获得新节点的祖父*/

                   if(grand->left ==*sub_root_p)                /* 获得新节点的叔叔;参考.2.1的情况*/

                      uncle = grand->right;

                   else

                      uncle = grand->left;

                   switch(uncle->color){

              case RED:  /* 参考图.2.1-1 还有一种未画出的情况这种情况部分叔与父的位置关系*/

                  (*sub_root_p)->color = BLACK;      /* 父=>黑*/

                  uncle->color =BLACK;              /* 叔=>黑*/

                  grand->color =RED;                /* 祖=>红这种情况会往上遍历*/

                   break;

              case BLACK: /* 参考图.2.2-1 */

                   if(grand->right ==uncle){/* 叔在右边*/

                      (*sub_root_p)->color = BLACK;      /* 父=>黑*/

                      grand->color =RED;                /* 祖=>红*/

                       if(grand->parent ==BNULL)         /* 祖父右旋转*/

                           rotate_right(root_p);               

                       else if(grand->parent->left== grand)

                           rotate_right(&(grand->parent->left));

                       else

                           rotate_right(&(grand->parent->right));

                  }else{/* |叔在左边,未画出*/

                      (*sub_root_p)->left->color = BLACK;  /* |新=>黑*/

                      grand->color =RED;                  /* |祖=>红*/

                      rotate_right(sub_root_p);           /* |父亲右旋转*/

                       if(grand->parent ==BNULL)           /* |祖父左旋转*/

                           rotate_left(root_p);               

                       else if(grand->parent->left== grand)

                           rotate_left(&(grand->parent->left));

                       else

                           rotate_left(&(grand->parent->right));

                  }

                   break;

                  }

                   break;

        }

     }else{

        RBInsert(root_p, *sub_root_p, &((*sub_root_p)->right), data); /* 将新节点插入到当前节点的右子树*/

         if(!((*sub_root_p)->color== RED && (*sub_root_p)->right->color == RED))/* 判断当前节点和父亲是否遇到红色警戒*/

              return error;

         switch((*sub_root_p)->color){

              case BLACK: /* 在黑色节点处插入*/

                   break;

              case RED:   /* 在红色节点处插入,需考虑叔叔*/

                  grand = (*sub_root_p)->parent;        /* 获得新节点的祖父,一定存在*/

                   if(grand->left ==*sub_root_p)         /* 获得新节点的叔叔;参考.2.1的情况*/

                      uncle = grand->right;

                   else

                      uncle = grand->left;

                   switch(uncle->color){

              case RED:   /* 参考图.2.1-2 还有一种未画出的情况这种情况部分叔与父的位置关系*/

                  (*sub_root_p)->color =BLACK;        /* 父=>黑*/

                  uncle->color =BLACK;                /* 叔=>黑*/

                  grand->color =RED;                  /* 祖=>红这种情况会往上遍历*/

                   break;

              case BLACK: /* 参考图.2.2-2 */

                   if(grand->right ==uncle){/* 叔在右边*/

                      (*sub_root_p)->right->color = BLACK;/* 新=>黑*/

                      grand->color =RED;                 /* 祖=>红*/

                      rotate_left(sub_root_p);         /* 父左旋转*/                                      

                       if(grand->parent ==BNULL)          /* 祖父右旋转*/

                           rotate_right(root_p);               

                       else if(grand->parent->left== grand)

                           rotate_right(&(grand->parent->left));

                       else

                           rotate_right(&(grand->parent->right));

                  }else{/* |叔在左边,未画出*/

                      (*sub_root_p)->color =BLACK;        /* |父=>黑*/

                      grand->color =RED;                  /* |祖=>红*/

 

                       if(grand->parent ==BNULL)           /* |祖父左旋转*/

                           rotate_left(root_p);               

                       else if(grand->parent->left== grand)

                           rotate_left(&(grand->parent->left));

                       else

                           rotate_left(&(grand->parent->right));

                  }

                   break;

                  }

                   break;

         }/* end switch */

     }/*end if */

     return error;

}

 

/*---------------------------------------------------------------------

函数名称:Delete

  数:node_p  指向节点之指针的指针

返回参数:--成功  -1 --失败

功能描述:从红黑树中删除一个节点

-----------------------------------------------------------------------

*/

int Delete(RTree** root_p, int data)

{

     int error = 0;

     /* 第一步:定位到需要删除的那个节点*/

    RNode* del = Search(*root_p, data);

    RNode* suc = BNULL;

     if(del == BNULL){

         return -1;

    }

 

     /* 第二步:找到需要删除的那个节点的后继节点*/

     if(del->right == BNULL){/* 要删除的节点del只有左孩子或无孩子,无需找后继节点*/

         if(del->parent ==BNULL){/* 删除根节点*/

             *root_p = del->left;

             (*root_p)->color = BLACK;

         }else if(del->parent->left== del)

              del->parent->left= del->left;

         else

              del->parent->right= del->left;

         /* 更新孩子的父亲*/

         if(del->left != BNULL)

              del->left->parent= del->parent;

         /* suc用于清除内存空间*/

        suc = del;

     }else{/* del的右孩子不为空,有后继节点*/

        suc = Successor(del);

         del->data= suc->data;

         /* 第三步:递归调用更新红黑树*/

         if(suc->color == RED){/* 说明要删除的节点是红色叶节点,这种情况最简单*/

              if(suc->parent->right== suc)

                 suc->parent->right = suc->right; /*suc->right = BNULL */

              else

                  suc->parent->left = suc->right;

 

              /* 不需要往上更新,结束*/

         }else if(suc->right == BNULL){/* 删除黑色叶节点参考图"删黑a"*/

              if(suc->parent->left== suc){

                  suc->parent->left = BNULL;

                  RBDelete(root_p, suc->parent, suc->parent->left);/* 往上更新*/

             }else{

                  suc->parent->right = BNULL;

                  RBDelete(root_p, suc->parent, suc->parent->right);

             }

         }else{/* 右子树不为空,那么右子树一定为一红节点参考图"删黑b"*/

             suc->right->parent = suc->parent;  /* 更新suc右下节点的父亲属性*/

              if(suc->parent->left== suc){

                  suc->parent->left = suc->right; /*suc->right == BNULL */

                  RBDelete(root_p, suc->parent, suc->parent->left);/* 往上更新*/

             }else{

                  suc->parent->right = suc->right;

                  RBDelete(root_p, suc->parent, suc->parent->right);

             }

        }

    }

     /* 第四步:释放节点所占的空间*/

    free(suc);

     return error;

}

 

/*---------------------------------------------------------------------

函数名称:RBDelete

  数:root_p  -- 指向树根节点地址的指针

parent-- child的父节点指针

child -- 需要判定更新的节点指针

返回参数:无

功能描述:其实RBDelete更像一个检测更新函数,而非删除函数,因为

child有可能为BNULL节点,所以它的parent=NULL,所以

需要传递一个parent参数。

-----------------------------------------------------------------------

*/

int RBDelete(RTree**root_p, RNode* parent, RNode* child)

{

     int   error    = 0;

     type_ttype     = left;      /* 用来标记child为parent的左孩子还是右孩子*/

     RNode* brother  =BNULL;         /* 子的兄弟*/

     RNode* grand    =BNULL;         /* 子的祖父*/

     RNode* nephew1  =BNULL;         /* 子的左侄子*/

     RNode* nephew2  =BNULL;         /* 子的右侄子*/

 

     /* 处理parent为BNULL的情况*/

     if(parent == BNULL){

         return error;

    }

     if(parent->left ==child){

        brother = parent->right;

        type = left;

     }else{

        brother = parent->left;

        type = right;

    }

     switch(brother->color){

     case RED:

        parent->color  = RED;        /* 父=>红*/

        brother->color = BLACK;      /* 兄=>黑*/

        dright_balance(root_p, parent, type);  /* parent进行平衡*/

         break;

     case BLACK:

         nephew1 =brother->left;      /* 当child的兄弟节点为黑色的时候,我们引入侄子*/

        nephew2 = brother->right;

         if(nephew1->color ==BLACK && nephew2->color == BLACK){ /* 双黑侄*/

             brother->color = RED;        /* 兄=>红*/

              if(parent->color == RED)

                  parent->color = BLACK; /* 父=>黑*/

              else{

                  RBDelete(root_p, parent->parent, parent); /* 或往上遍历*/

             }

         }else if(nephew1->color ==RED){/* 左红侄*/

              if(type == left){/* child是parent的左孩子*/

                  nephew1->color = parent->color;       /* 侄=>父色*/

                  parent->color  =BLACK;               /* 父=>黑*/

                  rotate_right(&(parent->right));       /* 兄右旋转*/

                   if(parent->parent ==BNULL)

                      rotate_left(root_p);            /* 父左旋转*/

                   else if(parent->parent->right== parent)

                      rotate_left(&(parent->parent->right));

                   else

                      rotate_left(&(parent->parent->left));

                   if(nephew1->color ==BLACK)/* 通过旋转brother已经取代了parent的位置,所以判断brother的颜色*/

                      RBDelete(root_p, nephew1->parent, nephew1);/* 往上遍历*/ /* nephew1一定不为空*/

             }else{/* child是parent的右孩子*/

                  nephew1->color =BLACK;         /* 侄=>黑*/

                  brother->color = parent->color; /* 兄=>父色*/

                   if(parent->parent ==BNULL)     /* 父右旋转*/

                      rotate_right(root_p);

                   else if(parent->parent->right== parent)

                      rotate_right(&(parent->parent->right));

                   else

                      rotate_right(&(parent->parent->left));

                   if(brother->color ==BLACK)

                      RBDelete(root_p, brother->parent, brother);/* 往上遍历*/

             }

         }else{/* 右红侄+左右红侄默认当右红侄来处理*/

              if(type == left){/* child是parent的左孩子*/

                  nephew2->color =BLACK;         /* 侄=>黑*/

                  brother->color = parent->color; /* 兄=>父色*/

                   if(parent->parent ==BNULL)     /* 父左旋转*/

                      rotate_left(root_p);

                   else if(parent->parent->right== parent)

                      rotate_left(&(parent->parent->right));

                   else

                      rotate_left(&(parent->parent->left));

                   if(brother->color ==BLACK)

                      RBDelete(root_p, brother->parent, brother);/* 往上遍历*/

             }else{/* child是parent的右孩子*/

                  nephew2->color = parent->color;    /* 侄=>父色*/

                  parent->color  =BLACK;            /* 父=>黑*//* 其实父亲一定为黑*/

                  rotate_left(&(parent->right));     /* 兄左旋转*/

                   if(parent->parent ==BNULL)

                      rotate_right(root_p);        /* 父右旋转*/

                   else if(parent->parent->right== parent)

                      rotate_right(&(parent->parent->right));

                   else

                      rotate_right(&(parent->parent->left));

                   if(nephew2->color ==RED)

                      RBDelete(root_p, nephew2->parent, nephew2);/* 往上遍历*/

             }

         }/* end of if双黑侄*/

         break;

     }/*end of switch */

}

 

/*---------------------------------------------------------------------

函数名称:dright_balance

  数:root_p   -- 指向树根节点地址的指针

node   -- 需要平衡的节点指针

type   -- 标记旋转的方向

返回参数:无

功能描述:左树节点减少、导致右高,需要右平衡RBDelete专用函数

-----------------------------------------------------------------------

*/

void dright_balance(RTree**root_p, RNode* node, type_t type)

{

     if(node->parent ==BNULL)

        rotate_left(root_p);

     else if(node->parent->left== node){

         if(type == left)

             rotate_left(&(node->parent->left));

         else

             rotate_right(&(node->parent->left));

     }else{

         if(type == left)

             rotate_left(&(node->parent->right));

         else

             rotate_right(&(node->parent->right));

    }

}

 

/*---------------------------------------------------------------------

函数名称:rotate_left

  数:sub_root_p   -- 指向节点地址的指针

返回参数:无

功能描述:左旋转

-----------------------------------------------------------------------

*/

void rotate_left(RNode**sub_root_p)

{

     if(*sub_root_p == BNULL ||(*sub_root_p)->right == BNULL)/* 不可能的情况*/

         printf("WARNING: program error detected inrotate_left!\n");

     else{

        RNode* right_tree    =  (*sub_root_p)->right;

          /* 更新旋转后的父节点指针,这点很重要*/

        right_tree->parent       =(*sub_root_p)->parent;

        (*sub_root_p)->parent    = right_tree;

        right_tree->left->parent = *sub_root_p;

         /* 左旋转树*/

        (*sub_root_p)->right =  right_tree->left;

        right_tree->left     =  *sub_root_p;

        *sub_root_p          = right_tree;

    }

}

 

/*---------------------------------------------------------------------

函数名称:rotate_right

  数:sub_root_p   -- 指向节点地址的指针

返回参数:无

功能描述:右旋转

-----------------------------------------------------------------------

*/

void rotate_right(RNode**sub_root_p)

{

     if(*sub_root_p == BNULL ||(*sub_root_p)->left == BNULL)/* 不可能的情况*/

         printf("WARNING: program error detected inrotate_right!\n");

     else{

        RNode* left_tree     =  (*sub_root_p)->left;

         /* 更新旋转后的父节点指针,这点很重要*/

        left_tree->parent        =(*sub_root_p)->parent;

        (*sub_root_p)->parent    = left_tree;

        left_tree->right->parent = *sub_root_p;

         /* 右旋转树*/

        (*sub_root_p)->left  =  left_tree->right;

        left_tree->right     =  *sub_root_p;

        *sub_root_p          = left_tree;

    }

}

 

/*---------------------------------------------------------------------

函数名称:Successor

  数:node   -- 要删除的节点指针

返回参数:BNULL   -- 参数错误

suc  -- 后继节点信息

功能描述:直接后继,但当此node无有节点时,我们返回的是node本身

-----------------------------------------------------------------------

*/

RNode*Successor(RNode* node)

{

     if(node == BNULL)

         return BNULL;

    RNode* suc = BNULL;

     if(node->right ==BNULL) /* 判断node是否具有右子树*/

         return node;

     else

        suc = node->right;

     while(suc->left !=BNULL){

        suc = suc->left;

    };

     return suc;

}   



转自:http://hi.baidu.com/20065562/blog/item/8777467e5292f30229388a0f.html


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值