转载请注明出处:http://blog.csdn.net/mxway/article/details/38080315
下面维基百科上红黑树的5个性质
1. 节点是红色或黑色
2. 根是黑色
3. 所有叶子都是黑色(叶子是NIL节点)
4. 每个红色节点必须有两个黑色的子节点。(从每个叶子到根的所有路径上不能有两个连续的红色节点。)
5. 从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。
根据上面的5个性质,我们可以得出下面的结论:
结论1:在红黑树中若x只有一棵非空子树,则x必为黑色。
证明:假设x为红色,根据性质4可以推出x有两个黑色子节点。与x只有一棵非空子树矛盾。
结论2:在红黑树中若x只有一棵非空子树。则该非空子树的根必为红色,且该非空子树仅且只有一个根节点。
证明:假设y为x的左孩子,节点y的颜色为黑色,且y有子树。由于y是黑色,x的右子权为空,所以从x到其左子树各叶子结点的路径上黑色结点数大于x到其右子树叶到叶节点的路径上黑色节点数,违反性质5,所以节点y为红色。因为y为红色,如果y的子树存在,根据性质4可以得出y的两棵子树必为黑色。从x到经过y到各叶节点的路径上的黑色节点数大于到右子树叶节点路径上的黑色节点数。
同上所述,当y为x的右孩子时也可以证明结论2
下面讨论红黑树的删除问题:
1. 从上面的两个结论可以看出,如果要删除的节点只有一个孩子,那么直接用孩子节点的值代替父节点的值。删除子节点就可以,不需要进入删除调整算法。
2. 若当前要删除的节点两个孩子都不为空,此时我们只需要找到当前节点中序序列的后继节点。用后继节点的值替换当前节点的值。将后继节点作为新的当前节点,此时的当前节点一定只有一个右孩子或左右孩子都为空。
3. 通过步骤2后如果当前节点有后继节点,直接用其后继节点值替换当前节点值,不需要进入删除调整算法。如果当前节点没有后继节点,进入删除调整算法。
算法流程步骤:
1. 判断x的左右子树是否为空。
2. 如果x的左右子都不为空,找到中序序列中x的后继节点y,将x的值用y代替;将y作为新的x节点转到步骤1。否则转步骤3
3. 如果x的左子不空,将x的值用左子的值代替,删除x的左子,算法结束。否则转4
如果x的右子不空,将x的值用右子的值代替。
4. 如果x的右子不空,将x的值用右子的值代替,删除x的右子,算法结束。否则转5
5. 删除x,进入到红黑树删除节点调整程序。
下面通过图来详解红黑树的删除过程
首先利用上篇文章中的代码生成一棵红黑树,插入的顺序为:14,9,41,39,47,20,15,22,7,3,28,24
图1:红黑树
1.删除节点22,由于节点22只有一个孩子24,所以直接把22替换成24。根据上面的结论,不需要进行删除调整算法。
图2:删除节点22
2.删除节点24,24的节点颜色为黑色,且其兄弟39节点也为黑色,39的两个孩子为空,也为黑,所以将39结点染红,父节点28作为新的当前节点。由于28是红色,所以将28染黑,算法结束。
图3:删除节点24后的红黑树
3.删除节点39,因为39为叶节点,颜色为红。直接删除,不需要作任何调整。
图4:删除节点39后的红黑树
4.删除节点28,由于节点28是黑色,其兄弟节点47为黑,兄弟节点的两孩子也为黑。所以节点47染红。父节点41变当前节点
图5:删除节点28第一次调整
现在41为当前节点,由于41的兄弟节点14为黑,14的两个孩子也为黑。所以将14节点染红。父节点20也就是根节点为当前节点
图6:删除节点28第二次调整
此时20为当前节点,由于20是根节点调整算法结束,将28从红黑树中删除。
图7:删除节点28后的红黑树
至此红黑树的属性全部恢复
下面给出删除红黑树节点及调整的c++代码。关于红黑树删除调整算法可以看July的博客,他说的比较详细。这个代码是在上一篇 stl map底层之红黑树插入步骤详解与代码实现基础上增加的新功能
删除节点的c++程序。
template<typename T> void RBTree<T>::DeleteValue(const T &v1) { RBNode<T> *p = NULL; RBNode<T> *nextNode = NULL; Search(v1,p); if(p==NULL) { cout<<"删除的值不存在"<<endl; return; } if(p->left && p->right) { RBNode<T> *tempNode = p->right; while(tempNode) {//中序序列的后继节点 nextNode = tempNode; tempNode = tempNode->left; } p->val = nextNode->val; p = nextNode; } if(p->left) { //直接用后继节点的值替换 RBNode<T> *temp = p->left; p->val = temp->val; p->left = NULL; delete temp; } else if(p->right) { //直接用后继节点的值替换 RBNode<T> *temp = p->right; p->val = temp->val; p->right = NULL; delete temp; } else { //左右子树都不存在,需要进入删除调整算法 DeleteReblance(p); if(p==root) { root = NULL; } else if(p==p->parent->left) {//父节点的指针域需要修改 p->parent->left = NULL; } else if(p==p->parent->right) {//父节点的指针域需要修改 p->parent->right = NULL; } delete p; } }
红黑树删除后调整算法:
template<typename T> void RBTree<T>::DeleteReblance(RBNode<T> *node) { RBNode<T> *parent = NULL; RBNode<T> *other = NULL; while(node->color==_rb_black_node && node->parent) { parent = node->parent; if(node == parent->left) { other = parent->right; if(other->color==_rb_red_node) {//情形1兄弟节点为红 parent->color = _rb_red_node; other->color = _rb_black_node; _rbtree_rotate_left(parent); other = parent->right; } if( (other->left==NULL || other->left->color==_rb_black_node) && (other->right==NULL || other->left->color==_rb_black_node)) {//情形2兄弟为黑,且兄弟的两个孩子也为黑 other->color=_rb_red_node; node = parent; continue; } if( other->right==NULL || other->right->color==_rb_black_node) {//情形3兄弟节点的右孩子为黑,左为红 other->left->color=_rb_black_node;//此时左孩子一定存在且颜色为红,如果不满足就不会进入这个条件 other->color = _rb_red_node; _rbtree_rotate_right(other); other = parent->right; } //情形4兄弟节点的右孩子为红 other->right->color=_rb_black_node; other->color = parent->color; parent->color = _rb_black_node; _rbtree_rotate_left(parent); break; } else { other = parent->left; if(other->color==_rb_red_node) {//情形1兄弟节点为红 parent->color = _rb_red_node; other->color = _rb_black_node; _rbtree_rotate_right(parent); other = parent->left; } if( (other->left==NULL || other->left->color==_rb_black_node) && (other->right==NULL || other->left->color==_rb_black_node)) {//情形2兄弟为黑,且兄弟的两个孩子也为黑 other->color=_rb_red_node; node = parent; continue; } if( other->left==NULL || other->left->color==_rb_black_node) {//情形3兄弟节点的右孩子为黑,左为红 other->right->color=_rb_black_node;//此时左孩子一定存在且颜色为红,如果不满足就不会进入这个条件 other->color = _rb_red_node; _rbtree_rotate_left(other); other = parent->left; } //情形4兄弟节点的右孩子为红 other->left->color=_rb_black_node; other->color = parent->color; parent->color = _rb_black_node; _rbtree_rotate_right(parent); break; } } node->color = _rb_black_node; }