算法导论--红黑树的维持平衡

<pre name="code" class="cpp">c语言代码:基本引用或模仿自http://blog.csdn.net/chenhuajie123/article/details/11951777,还有个人的一点补充
 
//删除节点修复,关键在于双层色(额外黑色)恢复成单层 
static rb_node_t* rb_erase_rebalance(rb_node_t *node, rb_node_t *parent, rb_node_t *root){
	rb_node_t *other, *o_left, *o_right;   //x的兄弟*other,兄弟左孩子*o_left,*o_right  
   
    while ((!node || node->color == BLACK) && node != root)   
    {  
        if (parent->left == node)  
        {  
            other = parent->right;  
            if (other->color == RED)   //Case1:x的兄弟w是红色的,父自然为黑  
            {  
                other->color = BLACK;    
                parent->color = RED;   //上俩行,改变颜色,w->黑、p[x]->红。  
                root = rb_rotate_left(parent, root);  //再对p[x]做一次左旋  
                other = parent->right;  //x的新兄弟new w 是旋转之前w的左孩子。其实就是左旋后的效果。  
            }  
            if ((!other->left || other->left->color == BLACK) &&  
                (!other->right || other->right->color == BLACK))    
                          //Case2:x的兄弟w是黑色,且w的两个孩子也都是黑色的  
  
            {                         //由于w和w的俩个孩子都是黑色的,则在x和w上得去掉一黑色,  
                other->color = RED;   //于是,兄弟w变为红色。  
                node = parent;    //p[x]为新结点x  
                parent = node->parent;  //x<-p[x]  
            }  
            else                       //Case3:x的兄弟w是黑色的,  
            {                          //且,w的左孩子是红色,右孩子为黑色。  
                if (!other->right || other->right->color == BLACK)  
                {  
                    if ((o_left = other->left))   //w和其左孩子left[w],颜色交换。  
                    {  
                        o_left->color = BLACK;    //w的左孩子变为由红转黑
                    }   
                    other->color = RED;           //w由黑->红  
                    root = rb_rotate_right(other, root);  //再对w进行右旋,从而红黑性质恢复。  
                    other = parent->right;        //变化后的,现在父结点的之前的右孩子,作为新的兄弟结点w。  
                }  
                            //情况4:x的兄弟w是黑色的,且w的右孩子是红    
      
                other->color = parent->color;  //把兄弟节点染成当前节点父节点的颜色。  
                parent->color = BLACK;  //把当前节点父节点染成黑色
                //--------------------------------------------------------------------- 
				//1.父节点原本为红色,染为黑,左右子树黑高+1
				//兄弟节点黑转红,兄弟节点右孩子红转黑,左旋,右子树黑高平衡
				//左子树多了原本父节点的黑色,黑高+1,平衡额外黑色
				
				//2.父节点原本为黑色,左旋后
				//左子树多了原本兄弟节点的黑色,平衡额外黑色
				//右子树少了原本父节点的黑色,加上原本兄弟节点的右孩子红转黑,平衡 
				//--------------------------------------------------------------------- 
                if (other->right)      //且w的右孩子是红  
                {  
                    other->right->color = BLACK;  //兄弟节点w右孩子染成黑色,为了让右子树保持黑高  
                }  
                root = rb_rotate_left(parent, root);  //并再做一次左旋  
                node = root;   //并把x置为根。  
                break;  
            }  
        }  
        //镜像代码
        else  
        {  
            other = parent->left;  
            if (other->color == RED)  
            {  
                other->color = BLACK;  
                parent->color = RED;  
                root = rb_rotate_right(parent, root);  
                other = parent->left;  
            }  
            if ((!other->left || other->left->color == BLACK) &&  
                (!other->right || other->right->color == BLACK))  
            {  
                other->color = RED;  
                node = parent;  
                parent = node->parent;  
            }  
            else  
            {  
                if (!other->left || other->left->color == BLACK)  
                {  
                    if ((o_right = other->right))  
                    {  
                        o_right->color = BLACK;  
                    }  
                    other->color = RED;  
                    root = rb_rotate_left(other, root);  
                    other = parent->left;  
                }  
                other->color = parent->color;  
                parent->color = BLACK;  
                if (other->left)  
                {  
                    other->left->color = BLACK;  
                }  
                root = rb_rotate_right(parent, root);  
                node = root;  
                break;  
            }  
        }  
    }  
    //1.维持了每个节点或红或黑,且2.红节点的子节点为黑的性质,3.叶子结点为黑色NIL本来就不变
    if (node)  
    {  
        node->color = BLACK;  //最后将node[上述步骤置为了根结点],改为黑色。因为可能导致root为红,此时root的子节点必然为黑,所以root红转黑后,4.根节点为黑,且5.两端黑高都+1,平衡

    }    
    return root;  //返回root  
} <pre name="code" class="cpp">static rb_node_t* rb_insert_rebalance(rb_node_t *node, rb_node_t *root){
	//插入节点要记得考虑头尾 
	while((node->parent != NULL) && (node->parent->color == RED))//破坏性质:红节点子节点为黑,同时可知爷爷为黑 
	{
		if(node->parent == node->parent->parent->left){
			//Case1:node的叔节点为红 
			if((node->parent->parent->right != NULL) && (node->parent->parent->right->color == RED)){
				node->parent->parent->color = RED;//爷爷黑转红,黑高-1
				//父和叔红转黑,黑高+1 --->平衡 
				node->parent->color = BLACK;//父红转黑 
				node->parent->parent->right->color = BLACK;//叔红转黑; 
				node = node->parent->parent;
			} 
			else{
				//node为右子节点 
				//因为爷爷要黑转红,那么爷爷的子节点要为黑,而此时右子节点为node红 
				if(node == node->parent->right)
				{
					node = node->parent;
					root = rb_rotate_left(node, root);//
					//左旋不改变黑高 
					//使得父为原来的node红,node节点的右子节点自然为黑,满足条件 
				}
				node->parent->color = BLACK;//父红转黑,黑高+1
				node->parent->parent->color = RED;//爷爷黑转红,黑高-1,左子树平衡,但右子树黑高-1 
				root = rb_rotate_right(node->parent->parent, root); //右旋使得左子树父节点为爷爷,右子树黑高+1-->平衡 		
			} 
		}
		else//镜像 
		{
			if((node->parent->parent->left != NULL) && (node->parent->parent->left->color == RED)){
				node->parent->parent->color = RED;
				node->parent->color = BLACK;
				node->parent->parent->left->color = BLACK;
				node = node->parent->parent;
			}else{
				if(node == node->parent->left){
					node = node->parent;
					root = rb_rotate_right(node, root);
				}
				node->parent->color = BLACK;
				node->parent->parent->color = RED;
				root = rb_rotate_left(node->parent->parent, root);
			} 
		}	
	} 
	
	root->color = BLACK;//如果插入的为第一个节点为root,要红转黑
	return root;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值