红黑树(Red Black Tree)
2017-02-13 16:40
483 查看
1. 概述
一棵二叉树如果满足下面的红黑性质,则为一棵红黑树:1)每个节点或是红的,或是黑的
2)根节点是黑的
3)每个叶节点(NIL)是黑的。
4)如果一个节点是红的,则它的儿子都是黑的
5)对每个节点,从该节点到其子孙节点的所有路径包含相同数目的黑节点
一棵二叉树的形状如下图:
2. 红黑树的高度
1)先证以x为根的子树至少包含(利用红黑树的性质5即可证明)
2)一棵含有n个节点的红黑树的黑高度至少是h / 2,再由1)我们可以得到
,所以
。
因此可以得出红黑树的操作可以在O(lgn)时间内完成。
3.红黑树的基本数据结构
1)红黑树的叶节点typedef struct Node{ Color color; struct Node *left; struct Node *right; struct Node *p; ElemType key; }Node;2)红黑树
typedef struct Tree{ Node *nillNode; Node * root; }*RedBlackTree;
4. 红黑树的两个基本操作----左旋和右旋
1)左旋代码参考
void leftRotate(RedBlackTree t, Node *x) { // Suppose the right node exists(right node not null) Node * y = x->right; //turn y's left subtree into x's right subtree x->right = y->left; if(y->left != t->nillNode) { y->left->p = x; } y->p = x->p; if(x->p == t->nillNode) { // x is the root of the tree t->root = y; } else if (x == x->p->left) { x->p->left = y; } else { x->p->right = y; } // put x on y's leftg y->left = x; // link x->p to y x->p = y; }2)右旋代码参考
void rightRotate(RedBlackTree t, Node *x) { Node *y = x->left; x->left = y->right; if(y->left != t->nillNode) { y->right->p = x; } y->p = x->p; if(x->p == t->nillNode) { t->root = y; } else if (x == x->p->left) { x->p->left = y; } else { x->p->right = y; } y->right = x; x->p = y; }
5. 最小值
和搜索二叉树差不多即一直往左遍历// find the min key with x as the root Node * min(RedBlackTree t, Node * x) { if (x != t->nillNode) { Node *y = x->left; while (y != t->nillNode) { x = y; y = x->left; } } return x; }
6. 最大值
// find the min key with x as the root Node * min(RedBlackTree t, Node * x) { if (x != t->nillNode) { Node *y = x->left; while (y != t->nillNode) { x = y; y = x->left; } } return x; }
7. 后继
Node *successor(RedBlackTree t, Node * x) { if(x->right != t->nillNode) { return min(t, x->right); } Node * y = x->p; while (y != t->nillNode && x == y->left) { x = y; y = y->p; } return y; }
8. 构建一棵红黑树
// create red black tree and initial void createTree(RedBlackTree *t) { // global nil node Node * nillNode = NULL; // create nillNode and initial nillNode = (Node *)malloc(sizeof(Node)); if(nillNode == NULL) { printf("nilNode allocation failed!\n"); exit(1); } nillNode->color = BLACK; nillNode->left = NULL; nillNode->right = NULL; nillNode->p = NULL; //create Red Black Tree and initial (*t) = (RedBlackTree) malloc(sizeof(struct Tree)); if(*t == NULL) { printf("red black allocation failed!\n"); exit(-1); } (*t)->root = nillNode; (*t)->nillNode = nillNode; }
9. 插入
1)首先我们像二叉树那样把节点插入到对应的节点,并设置其为红色节点2)我们对其进行调整,以维持红黑性质
在整个插入过程和调整过程中,只有可能违反红黑性质的2)和4)即根节点是黑色的以及红色节点的儿子节点是黑色节点。(在插入步骤1)中,很容易得出性质2)和4都可能违反),根据如下的调整过程,我们也很容易得出只有性质2)和性质4)可以被违反。
上述过程转化过程:
转化成伪代码:
if (case 1) { } else { if (case 2) { } case 3 }从case1 到case3我们发现并没有违反性质1)3)5),而违反性质1)说明根是红色的,只要将其变成黑色的就OK,所有的性质都可以得到满足,剩下的所有情况就是违反性质4,当遇到case1时z是不断上升的,只要遇到case2 或case3,整个调整过程即将完成。
代码为:
// used for fix up when insert void insertFixUp(RedBlackTree t, Node *z) { Node * y = t->nillNode; while (z->p->color == RED) { if(z->p == z->p->p->left) { // find z's uncle node y = z->p->p->right; // case 1 if (y->color == RED) { z->p->color = BLACK; y->color = BLACK; z = z->p->p; z->color = RED; } else { // y->color == Black // case 2 if(z == z->p->right) { z = z->p; leftRotate(t, z); } // case 3 z->p->color = BLACK; z->p->p->color = RED; rightRotate(t, z->p->p); } } else { // the same as above with "right" and "left" exchanged y = z->p->p->left; //case 1 if (y->color == RED) { z->p->color = BLACK; y->color = BLACK; z = z->p->p; z->color = RED; } else { // case 2 if(z == z->p->left) { z = z->p; rightRotate(t, z); } // case3: z->p->color = BLACK; z->p->p->color = RED; leftRotate(t, z->p->p); } } } t->root->color = BLACK; }
10. 删除
1)按照二叉搜索树进行删除2)如果删除的是黑色节点,则为了维持红黑性质进行相应的调整
其过程代码如下:
void delete(RedBlackTree t, ElemType key) { Node * z = find(t, key); if (z != t->nillNode) { // the node which will be deleted Node *y = t->nillNode; if (z->left == t->nillNode || z->right == t->nillNode) { y = z; } else { y = successor(t, z); } Node *x; if (y->left != t->nillNode) { x = y->left; } else { x = y->right; } x->p = y->p; if (y->p == t->nillNode) { t->root = x; } else { if (y == y->p->left) { y->p->left = x; } else { y->p->right = x; } } if (y != z) { z->key = y->key; } free(y); if (y->color == BLACK) { deleteFixUp(t, x); } } }
我们知道如果删除的是红色的节点的话,则红黑性质依旧是可以满足的,若是删除的是黑色则情况稍有复杂。
可能违反如下性质:
违反性质2):如果删除的节点y原先是根节点,而y的一个红色的儿子节点成了根节点,则违反了性质2)
违反性质4):如果删除节点y的儿子节点x 和 其父亲节点p[y]都是红色的,则违反了性质4)
违反性质5):因为删除的节点是黑色的,必然使得经过该节点的路径黑高度少1,则违反性质5)
综上违反的性质,我们删除节点y的儿子节点x当做一个双重颜色节点,即附加一层黑色(若x原先是黑色的,现在有双重黑色属性,若是原先是黑色的则现在具有红和黑的性质),因此在调整过程中,认为性质5)是维持的。由于我们在调整过程中x节点左右子树是满足红黑树的所有性质的,所以对于违反性质2),我们只要使得让其根节点变成黑色的,则整个红黑树的性质是可以满足的。若对于违反性质4)我们只要使得红色节点x变成黑色的,则整棵树又满足了红黑树的所有性质。剩下内容就是使得双重颜色节点x变成真正意义上的双重颜色节点,即使得性质5)得以维持,调整过程如下。
case1 x的兄弟w是红色的
case2 x的兄弟w是黑色的,且两个孩子是黑色的
case3 x的兄弟w是黑色的,且w的左孩子是黑色的,右孩子是黑色的
case4 x的兄弟w是黑色的,且w的右孩子是红色的
从上述调整我们可以得出其转化图
尤其情况转化,我们可以得出其伪代码:
if (case 1) { } if (case 2) { } else { if (case 3) { } case 4 }其中可能有人认为会在case1和case2中无限循环,而完成不了调整的目的。
因为case1,使得节点x下沉,而case2使得x节点上升,因此不得不会这样想。但我们多想一下,满足上述情况case1只能转化到case2,而case2只能转化到case1,当我们再往下走时,发现x继续上升,因为此时的x的兄弟节点w是黑色的而不是红色的,所以x会继续上升。因此可以想象整个x是不断朝根节点上升的。
调整代码:
void deleteFixUp(RedBlackTree t, Node *x) { while (x != t->root && x->color == BLACK) { // x is x's parent's left child if (x == x->p->left) { Node * w = x->p->right; // case1:turn it into case2 or case3 or case4 if(w->color == RED) { w->color = BLACK; x->p->color = RED; leftRotate(t,x->p); w = x->p->right; } //case 2 if(w->left->color == BLACK && w->right->color == BLACK) { w->color = RED; x = x->p; } else { // case 3 if(w->right->color == BLACK) { w->color = RED; w->left->color = BLACK; rightRotate(t, w); w = x->p->right; } // case 4 w->color = x->p->color; x->p->color = BLACK; w->right->color = BLACK; leftRotate(t,x->p); x = t->root; } } else { Node *w = x->p->left; if (w->color == RED) { w->color = BLACK; x->p->color = RED; rightRotate(t, x->p); w = x->p->left; } if (w->left->color == BLACK && w->right->color == BLACK) { w->color = RED; x = x->p; } else { if(w->left->color == BLACK) { w->color = RED; w->right->color = BLACK; leftRotate(t, w); w = x->p->left; } w->color = x->p->color; x->p->color = BLACK; w->left->color = BLACK; rightRotate(t, x->p); x = t->root; } } } x->color = BLACK; }
至此,所有的分析到此为止,有错误的和疑惑的请多多留言。
完整代码请转此
参考
本文主要是依据 Thomas H.Cormen、Charles E.Leiserson《算法导论》第二版 第十三章 红黑树转载请注明
相关文章推荐
- 红黑树—Red Black Tree
- 红黑树(Red Black Tree) - Flex实现
- 红黑树(Red Black Tree)
- 红黑树与C实现算法 - RedBlackTree.c
- 红黑树(Red BlackTree)的实现
- 红黑树(Red Black Tree)
- 红黑树与C实现算法 - RedBlackTree.c
- C#与数据结构--树论--红黑树(RED BLACK TREE)
- C#与数据结构--树论--红黑树(RED BLACK TREE)
- 编程练习——红黑树(RedBlackTree)
- RedBlackTree(红黑树)--一种自平衡(最优)的二叉搜索树算法
- (原创)红黑树red black tree "insert" "rotate" "search"
- 红黑树(RedBlackTree)实现
- 红黑树(Red Black Tree)
- 红黑树(Red Black Tree)
- 红黑树(Red Black Tree)
- 红黑树(Red Black Tree)
- C++数据结构 之 红黑树_Red Black Tree
- 红黑树(RedBlackTree),平衡树(BalancedTree),SkipList 的实现
- 红黑树(Red Black Tree)