算法————笔试内容--->红黑树(三)

来源:互联网 发布:ug8.0编程中的如何补面 编辑:程序博客网 时间:2024/06/06 00:56

这一篇红黑树将讲解关于红黑树删除的操作,学习本内容的时候小编可是使出了吃屎的尽头~~~~奋斗,好下面开始讲解:

上代码:

节点替换的函数:

void RB_transplant(node *tree_root,node * u,node * v){if(u->parent == NULL){tree_root = u;}else if(u == u->parent->left){u->parent->left = v;}else {u->parent->right = v;}v->parent = u->parent;}
节点删除操作的函数:

void RB_delete(node *tree_root,node *z){node *y;node *x;node *search;y = z;search = z->right;int original_color = y->color;//对z是否有左右子节点分情况讨论if(z->left ==NULL){x = z->right;RB_transplant(tree_root,z,z->right);}else if(z->right ==NULL){x=  z->left;RB_transplant(tree_root,z,z->left);}else{//寻找后继元素while(search!=NULL){y = search;search = search->left;}original_color = y->color;//记录此时的颜色x = y->right;//将y的右子树指针地址保存//此处的处理是针对y的右侧子树来的if(y->parent ==z){x->parent = y;}else{RB_transplant(tree_root,y,y->right);//用y右侧节点代替y的节点y->right = z->right;//将原来z右侧指针指向y的右侧节点y->right->parent = y;//将y的右侧的父指针指向y}RB_transplant(tree_root,z,y);//用y来代替z的位置//处理原来z的左侧子树的节点y->left = z->left;y->left->parent =y;y->color = z->color;}//如果颜色为黑色,则有可能打破了红黑树的平衡,因此要进行红黑树修正的工作if(original_color ==BLACK){RB_delete_fixup(tree_root,x);}}
下面由小编我用图文并茂的方式一一解答每个部分代码的意思:

对于删除操作根据删除节点Z左右子树的存在与否可以分为三种情况:

这个是第一个if中的情况,其操作直接将z的右侧第一个节点来替换z即可。

if(z->left ==NULL){x = z->right;RB_transplant(tree_root,z,z->right);<span style="font-family: Arial, Helvetica, sans-serif;">}</span>

这个是第二个if中的情况,其操作直接将z的左侧第一个节点来替换z即可。

else if(z->right ==NULL){x=  z->left;RB_transplant(tree_root,z,z->left);}


对于第三种情况有点复杂:

                        

图一                                                   

     

                          图二

              

                                   图三 

  

                                                             图四

图一是第三个elsef要处理的情况:首先通过while来寻找Z的后继y,即最小值。然后找到y的右子树节点,交给x指针来管理,如果y的父节点为z直接将x的父指针指向y即可,如果不是则进行下一步处理:见图片二    原来y的位置由y的右子树节点占据,y的右指针指向原来z的有指针指向的位置,最后将这个节点父指针指向y这样 Z的右侧子树已经移交给y,然后用y开始代替z的位置,见图片三和四,进行最后的删除操作。

else{//寻找后继元素while(search!=NULL){y = search;search = search->left;}original_color = y->color;//记录此时的颜色x = y->right;//将y的右子树指针地址保存//此处的处理是针对y的右侧子树来的if(y->parent ==z){x->parent = y;}else{RB_transplant(tree_root,y,y->right);//用y右侧节点代替y的节点y->right = z->right;//将原来z右侧指针指向y的右侧节点y->right->parent = y;//将y的右侧的父指针指向y}RB_transplant(tree_root,z,y);//用y来代替z的位置//处理原来z的左侧子树的节点y->left = z->left;y->left->parent =y;y->color = z->color;}

上述的删除操作解释完成,最后针对颜色为黑色的时候来进行红黑树的修复工作,因为为黑色的时候打破了红黑树的平衡性,因此要进行修复工作:

那么在删除的时候会打破红黑树的哪些性质呢?

1.有可能打破性质二,当要删除的节点为根节点为黑色而其孩子为红色的时候,那么当删除根节点的时候,红色的孩子代替原来的根节点,这个时候就会打破性质二。

2.有可能打破性质四,如果原来y的父节点为红色y节点为黑色,y节点的右节x点为红色,当y移动到要删除的位置,x连接到y原来的父节点上的时候,就会出现连续2个红色节点的情况,这样就打破了性质四。如下图所示


3.有可能打破性质五,同样如上图当y移动到原来z的位置上的时候,会造成一条支路上黑色的节点丢失,破坏了整体红黑树的平衡性。

对于不知道红黑树怎么操作的可以访问这个网站,可以动态的查看红黑树的插入和删除------》》》》》》》》》》》》点击打开链接

算法导论上的讲解:

改正这一问题的办法是将现在占有y原来位置的节点x视为还有一重额外的黑色。也就是说,如果将任意包含节点x的简单路径上黑节点个数加1,则在这种假设下,性质5成立。当将黑色结点y删除或移动时,将其黑色“下推”给节点x。现在问题变为节点x可能既不是红色,又不是黑色,从而违反了性质1.现在的节点x是双重黑色或者红黑色,这就分别给包含x的简单路径上黑节点数贡献了2或1.x的color属性任然是RED(如果x是红黑色的)或者BLACK(如果x是双重黑色的)。换句话说,节点额外的黑色是针对x节点的,而不是反应在他的color属性上的。

下面分情况讨论一下删除节点所遇到的情况:


情况1:x的兄弟节点w是红色的;

代码片段:

//case1//如果兄弟节点为红色的时候if(w->color == RED){w->color = BLACK;//将兄弟节点w染成黑色x->parent->color = RED;//将x的父节点染成红色left_rotate(tree_root,x->parent);//将x的父亲节点左旋转}

因为w必有黑色子节点,所以可以改变w和x->parent的颜色,然后对x->parent做一次左旋转而不违反红黑树的任何性质。现在,x的新兄弟节点是旋转之前w的某个子节点,其颜色为黑色。这样将情况1转换为情况2,3或4处理。


情况2:x的兄弟节点w是黑色的,而且w的两个子节点都是黑色的;

代码片段:

//case2//如果x的兄弟节点的左侧子节点颜色为黑且他的右侧节点也为黑的时候if(w->left->color == BLACK && w->right->color == BLACK){w->color = RED;//那么x的兄弟节点必须为红色,则需要将w染色成红色x = x->parent;//然后上移x指针到其父亲指针处
因为w也是黑色的,所以从x和w上去掉一重黑色,使得x只有一重黑色而w为红色。为了补偿重x和w中去掉的一重黑色,在原来是红色或黑色的x->parent上新增一重额外的黑色。通过将x->parent作为新节点x来重复while循环。注意到,如果通过情况1进入到情况2,则新结点x是红黑色的,因为原来的x->parent是红色的。因此,新节点x的color属性值c为RED,并且在测试循环条件后循环终止。


情况3:x的兄弟节点w是黑色的,w的左孩子是红色的,w的右孩子是黑色的;

//case3//如果x的兄弟节点的右侧子节点颜色为黑色,w的左侧节点为红色}else if(w->right->color ==BLACK){w->left->color = BLACK;w->color = RED;right_rotate(tree_root,w);w = x->parent->right;}
当w为黑色且左子树节点为红色、右孩子为黑色时。可以交换w和其左孩子w->left的颜色,然后对w进行右旋转而不违反红黑树的任何性质。现在x的新兄弟节点w是一个有红色右子树节点的黑色结点,这样就将情况3转换成了情况4.


情况4:x的兄弟节点w是黑色的,w其w的右孩子是红色的;

//case4w->color = x->parent->color;x->parent->color = BLACK;w->right->color = BLACK;left_rotate(tree_root,x->parent);x = tree_root;
通过进行某些颜色修改并对x->parent做一次左旋转,可以去掉x的额外黑色,从而使它变为单重黑色,而且不破坏红黑树的任何性质。将x设置为根后,当while循环测试其循环条件时,循环终止。


红黑树删除操作中修改红黑树操作代码如下:

void RB_delete_fixup(node * tree_root,node *x){node * w;while(x!=tree_root && x->color ==BLACK){//x在父节点的左侧的情况if(x==x->parent->left){//找到x的兄弟节点ww = x->parent->right;//case1//如果兄弟节点为红色的时候if(w->color == RED){w->color = BLACK;//将兄弟节点w染成黑色x->parent->color = RED;//将x的父节点染成红色left_rotate(tree_root,x->parent);//将x的父亲节点左旋转}//case2//如果x的兄弟节点的左侧子节点颜色为黑且他的右侧节点也为黑的时候if(w->left->color == BLACK && w->right->color == BLACK){w->color = RED;//那么x的兄弟节点必须为红色,则需要将w染色成红色x = x->parent;//然后上移x指针到其父亲指针处//case3//如果x的兄弟节点的右侧子节点颜色为黑色,w的左侧节点为红色}else if(w->right->color ==BLACK){w->left->color = BLACK;w->color = RED;right_rotate(tree_root,w);w = x->parent->right;}//case4w->color = x->parent->color;x->parent->color = BLACK;w->right->color = BLACK;left_rotate(tree_root,x->parent);x = tree_root;//一下情况与上述case1~case4对称出现}else if(x==x->parent->right){w = x->parent->left;if(w->color==RED){w->color = BLACK;x->parent->color =RED;right_rotate(tree_root,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;left_rotate(tree_root,w);w = x->parent->left;}w->color = x->parent->color;x->parent->color =BLACK;x->left->color =BLACK;right_rotate(tree_root,x->parent);x=tree_root;}}x->color = BLACK ;}



0 0
原创粉丝点击