在將紅黑樹中某個節點刪除時,分幾個步驟,首先找到該節點的位置,而後刪除該節點,最後調整紅黑樹。node
本文代碼還存在一個問題沒有解決,當連續刪除到第3個節點時會出現問題,如今暫時還沒找出問題,之後有空慢慢研究。數據結構
一、找出要刪除的節點函數
TREE rb_delete_find(TREE r, int d) // find the node that need deleted { NODE *x; x = r; while(x != NULL) { if(x->key == d) break; else if(d < x->key) x = x->left; else x = x->right; } if(x == NULL) { printf("find failed\n", x->key); return NULL; } else { printf("find success, %d\n", x->key); return rb_delete(r, x); } }
在找到要刪除的節點後,根據不一樣的情形將節點刪除。代碼以下:spa
TREE rb_delete(TREE r, NODE *z) { NODE *x, *y = z, *tmp; int y_original_color = y->color; tmp = (TREE)malloc(sizeof(NODE)); tmp->key = -1; tmp->color = 1; tmp->left = NULL; tmp->right = NULL; if(z->left == NULL) { x = z->right; r = rb_delete_node(r, z, z->right); if(x == NULL) { x = tmp; x->p = z->p; z->p->right = x; } } else if(z->right == NULL) { x = z->left; r = rb_delete_node(r, z, z->left); } else //左右孩子都不爲空 { y = tree_minimum(z->right); //y要麼沒有子節點要麼只有右孩子 y_original_color = y->color; x = y->right; if(y->p != z) { r = rb_delete_node(r, y, y->right); y->right = z->right; y->right->p = y; } r = rb_delete_node(r, z, y); y->left = z->left; y->left->p = y; y->color = z->color; if(NULL == x) { x = tmp; x->p = y; y->right = x; } } // printf("root->key: %d \tx->key: %d\n", r->key, x->key); // printf("root->left: %d \troot->right: %d\n", r->left->key, r->right->key); /**在刪除或移動黑色節點時,須要將他的黑色下推給他的孩子節點。若孩子節點爲空, 這時將沒法將黑色下推。若黑色向上推則會致使黑高的不相等。 在此經過建立臨時節點,將其做爲葉子節點。葉子節點的顏色爲黑色,值爲-1. **/ //printf("------------r.key = %d x.key = %d\n",r->key, x->key); //y_original_color保存了移動或刪除的節點的顏色,當移動或刪除的節點爲紅色時,紅黑樹的性質沒有被破壞, //而當移動或刪除的節點爲黑色時,紅黑樹的性質被破壞了,這是就須要對其進行調整。 if(y_original_color == 1) //1:黑色, 0:紅色 { r = rb_delete_fixup(r, x); } return r; }
當刪除或移動的節點爲黑色時,須要對紅黑樹進行調整,以使得其繼續保持紅黑樹的性質。具體的調整過程見上一篇文章。code
調整代碼以下:blog
TREE rb_delete_fixup(TREE r, NODE *z) { NODE *x = z, *w; while(x!=r && x->color==1) { if(x == x->p->left) //x is left child { w = x->p->right; if(w!=NULL && w->color == 0) //case 1: w->color=0 { w->color = 1; x->p->color = 0; r = left_rotate(r, x->p); w = x->p->right; } //提取x和w的一個黑色, 上移到x的父節點。從w提出一個黑色後其變成了紅色,x還剩一個黑色 if((w->left==NULL ||w->left->color==1) && (w->right==NULL || w->right->color==1)) //case 2: w->color=1 && w.left=1 && w.right=1 { w->color = 0; x = x->p; } else { if(w->right==NULL || w->right->color==1) //case 3: w->color=1 && w.left=0 && w.right=1 { w->left->color = 1; w->color = 0; r = right_rotate(r, w); w = x->p->right; } w->color = x->p->color; //case 4: w->color=1 && w.right=0 x->p->color = 1; w->right->color = 1; r = left_rotate(r, x->p); x = r; } } else //x is right child { w = x->p->left; if(w->color == 0) //case 1 { w->color = 1; x->p->color = 0; r = right_rotate(r, x->p); w = x->p->left; } if((w->left==NULL || w->left->color==1) && (w->right==NULL || w->right->color==1)) //case 2 { w->color = 0; x = x->p; } else { if(w->left==NULL || w->left->color==1) //case 3 { w->color = 0; w->right->color = 1; r = left_rotate(r, w); w = x->p->left; } //case 4 w->color = x->p->color; w->left->color = 1; x->p->color = 1; r = right_rotate(r, x->p); x = r; } } } x->color = 1; return r; }
首先是刪除節點函數,其代碼以下:ip
/** ** 刪除節點x,使用y來代替x節點 **/ TREE rb_delete_node(TREE r, NODE *x, NODE *y) { if(x->p == NULL) { r = y; } else if(x == x->p->left) { x->p->left = y; } else x->p->right = y; if(y != NULL) y->p = x->p; return r; }
//查找節點z的後繼節點 NODE *tree_minimum(NODE *z) { NODE *x = z; while(x->left != NULL) x = x->left; return x; }