红黑树—Red Black Tree

红黑树是具有以下五条性质的二叉查找树:

  1. 每个结点要么是红的要么是黑的。  
  2. 根结点是黑的。  
  3. 每个叶结点(叶结点即指树尾端NIL指针或NULL结点)都是黑的。  
  4. 如果一个结点是红的,那么它的两个儿子都是黑的。  
  5.  对于任意结点而言,其到叶结点树尾端NIL指针的每条路径都包含相同数目的黑结点。 

正是由于红黑树的以上五个性质,使得其高度最多是2log(N+1),从而保证红黑树的查找、插入、删除的时间复杂度最坏为O(log n)。具体关于红黑树的基本介绍,以及插入操作,和删除操作的算法的具体分析可参考博文教你透彻了解黑树其结构之法、算法之道系列文章整体不错,可以多多参考学习)。 在插入、删除过程中最关键的就是时刻保证RBT的五个性质。


以下主要给出RBT的插入算法的具体实现,删除操作目前还没彻底弄清楚,后续再补充。其中的左旋转,右旋转,以及双旋转操作与平衡二叉树中的操作一样,

具体见:平衡二叉树(AVLTree)

插入操作:首先按查找二叉树的方法找到正确的插入位置,并将新节点X设为红色。则主要分为以下4中情况:

1、其父节点P为黑色,则直接插入,完成。

2、其父节点P为红色(则祖父节点GP一定为黑色),X为P(GP的左节点,为右节点时,对称情况)的左子节点(为右节点时,对称情况),其叔父节点S(即      GP的       右节点)为黑色,则执行一次左单旋转即可。 (对称情况执行一次右单旋转)。

3、其父节点P为红色(则祖父节点GP一定为黑色),X为P(GP的左节点,为右节点时,对称情况)的右子节点(为左节点时,对称情况),其叔父节点S(即      GP的       右节点)为黑色,则执行一次双旋转即可。 (对称情况类似执行一次双旋转)。

4、其父节点P为红色(则祖父节点GP一定为黑色),其叔父节点S为红色。 这种情况相对较为复杂。基本思路是,在插入新节点的自顶向下遍历过程中,将遇到的所有         双红儿子节点(其父节点一定为黑)的情况进行颜色翻转,即将父节点设为红,两儿子改为黑,从而将第4种情况转化为2或3的情况。


具体代码如下:

<span style="font-size:18px;">typedef enum ColorType {Red,Black} ColorType;
typedef int ElementType;
typedef struct RedBlackNode* RedBlackTree;
typedef struct RedBlackTree Position;


//节点
struct RedBlackNode
{
 ElementType Element;//节点value值
 RedBlackTree Left;//节点左指针
 RedBlackTree Right;//节点右指针
 ColorType Color;//节点颜色
 
};

/*旋转处理函数
根据需要进行单旋转(双旋转由两次单旋转完成)
参数:
Item:新节点value值
Parent:插入新节点后的曾祖父节点
返回值:
旋转后的新树根(新节点的祖父节点)指针
*/
static Position Rotate(ElementType Item,Position Parent)
{
 if(Item<Parent->Element)
	return  Parent->Left=Item<Parent->Left->Element?
		SingleRotateWithLeft(Parent->Left)://“一”形
		SingleRotateWithRight(Parent->Left);//“之”形
 else
	return Parent->Right=Item>Parent->Right->Element?
		SingleRotateWithRight(Parent->Right)://“一”形
		SingleRotateWithLeft(Parent->Right);//“之”形
}

static Position X,P,GP,GGP;


/*树形调整函数*/
static void HandleRrorient(ElementType Item,RedBlackTree T)
{
 //在自顶向下遍历时遇到双子节点均为红时,执行颜色翻转
 X->Color=Red;
 X->Left->Color=Black;
 X->Right->Color=Black;
 
  if(P->Color==Red)//当父节点需要执行旋转操作
  {
    GP->Color=Red;
	if(Item<P->Element != P->Element<GP->Element)//为”之“形,需要执行双旋转
		P=Rotate(Item,GP);//对X和P执行一次单旋转(双旋转的第一次单旋转)
	X=Rotate(Item,GGP);//为”一“形,旋转后X为新子树的树根
	X->Color=Black;//确保树根为黑色
  }

}

RedBlackTree Insert(ElementType Item ,RedBlackTree T)
{
 X=P=GP=GGP=T;
 /*Position NullNode=malloc(sizeof(struct RedBlackNode));
 NullNode->Left=Right=NULL;
 NullNode->Color=Red;
 */
 NullNode->Element=Item;
 while(X->Element!=Item && 	X!=NullNode)//自定向下遍历,并处理双红儿子节点,以及带来的旋转操作
 {
  GGP=GP;GP=P;P=X;
  if(X<X->Element)
	X=X->Left;
  else
	X=X->Right;
	if(X->Left->Color==Red && X->Right->Color==Red)//双红儿子节点
		 HandleRrorient(Item,T);
 }

 if(X!=NullNode)//原来一存在该值的节点
	return NullNode;
	
 X=malloc(sizeof(struct RedBlackNode));
 if(X=NULL)
   printf("Out of space \n");
 X->Element=Item;
 X->Left=X->Right=NullNode;
 
 //将新节点插入到树叶
 if(Item<P->Element)
	P->Left=X;
 else 
   P->Right=X;
 //最后插入节点后可能使得不满足红黑树的性质,因此需要最后一次调整(因为已不存在其叔父节点为红的情况,因此只需要进行一次单或者双旋转即可)
  HandleRrorient(Item,T);
  
  return T;
}
</span>





















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值