|
2008-11-10补充---这份代码仍然是有问题的, 再次的修正版本在这里:http://www.cppblog.com/converse/archive/2008/11/10/66530.html在之前,我曾经给出过一份红黑树的实现代码,很多人提出异议,说是代码有问题,我曾经做过一些测试,貌似都没有出错,因为这份代码是在我学习红黑树之后很久才贴出来的,所以后来没有再仔细看这份代码。 最近,因为工作上的原因,我需要使用红黑树结构,本以为拿来那份代码稍加改动就可以了,没想到代码调试了很久都还有问题,于是,我决定重新补习红黑树的知识,仔细查看了原有的代码,才发现是有问题的,在这里,给出修正版本的代码,希望这次是没有错误:) 请大家原谅我的疏忽。 我就不在原来的页面修改那份代码了,只是在上面加上说明那份代码是有错误的。
/*----------------------------------------------------------- RB-Tree的插入和删除操作的实现算法 参考资料: 1) <<Introduction to algorithm>> 2) <<STL源码剖析>> 3) sgi-stl中stl_tree.h中的实现算法 4) http://epaperpress.com/sortsearch/index.html 5) http://www.ececs.uc.edu/~franco/C321/html/RedBlack/redblack.html
作者:李创 (http://www.cppblog.com/converse/) 您可以自由的传播,修改这份代码,转载处请注明原作者
红黑树的几个性质: 1) 每个结点只有红和黑两种颜色 2) 根结点是黑色的 3)空节点是黑色的(红黑树中,根节点的parent以及所有叶节点lchild、rchild都不指向NULL,而是指向一个定义好的空节点)。 4) 如果一个结点是红色的,那么它的左右两个子结点的颜色是黑色的 5) 对于每个结点而言,从这个结点到叶子结点的任何路径上的黑色结点 的数目相同 -------------------------------------------------------------*/
#include <stdio.h> #include <stdlib.h> #include <time.h>
typedef int KEY;
enum NODECOLOR { BLACK = 0, RED = 1 };
typedef struct RBTree { struct RBTree *parent; struct RBTree *left, *right; KEY key; NODECOLOR color; }RBTree, *PRBTree;
PRBTree RB_InsertNode(PRBTree root, KEY key); PRBTree RB_InsertNode_Fixup(PRBTree root, PRBTree z);
PRBTree RB_DeleteNode(PRBTree root, KEY key); PRBTree RB_DeleteNode_Fixup(PRBTree root, PRBTree x , PRBTree x_parent);
PRBTree Find_Node(PRBTree root, KEY key); void Left_Rotate(PRBTree A, PRBTree& root); void Right_Rotate(PRBTree A, PRBTree& root); void Mid_Visit(PRBTree T); void Mid_DeleteTree(PRBTree T); void Print_Node(PRBTree node);
/*----------------------------------------------------------- | A B | / \ ==> / \ | a B A y | / \ / \ | b y a b -----------------------------------------------------------*/ void Left_Rotate(PRBTree A, PRBTree& root) { PRBTree B; B = A->right;
A->right = B->left; if (NULL != B->left) B->left->parent = A; B->parent = A->parent;
// 这样三个判断连在一起避免了A->parent = NULL的情况 if (A == root) { root = B; } else if (A == A->parent->left) { A->parent->left = B; } else { A->parent->right = B; } B->left = A; A->parent = B; }
/*----------------------------------------------------------- | A B | / \ / \ | B y ==> a A | / \ / \ |a b b y -----------------------------------------------------------*/ void Right_Rotate(PRBTree A, PRBTree& root) { PRBTree B; B = A->left;
A->left = B->right; if (NULL != B->right) B->right->parent = A;
B->parent = A->parent; // 这样三个判断连在一起避免了A->parent = NULL的情况 if (A == root) { root = B; } else if (A == A->parent->left) { A->parent->left = B; } else { A->parent->right = B; } A->parent = B; B->right = A; }
/*----------------------------------------------------------- | 函数作用:查找key值对应的结点指针 | 输入参数:根节点root,待查找关键值key | 返回参数:如果找到返回结点指针,否则返回NULL -------------------------------------------------------------*/ PRBTree Find_Node(PRBTree root, KEY key) { PRBTree x;
// 找到key所在的node x = root; do { if (key == x->key) break; if (key < x->key) { if (NULL != x->left) x = x->left; else break; } else { if (NULL != x->right) x = x->right; else break; } } while (NULL != x);
return x; }
/*----------------------------------------------------------- | 函数作用:在树中插入key值 | 输入参数:根节点root,待插入结点的关键值key | 返回参数:根节点root -------------------------------------------------------------*/ PRBTree RB_InsertNode(PRBTree root, KEY key) { PRBTree x, y;
PRBTree z; if (NULL == (z = (PRBTree)malloc(sizeof(RBTree)))) { printf("Memory alloc error\n"); return NULL; } z->key = key;
// 得到z的父节点, 如果KEY已经存在就直接返回 x = root, y = NULL; while (NULL != x) { y = x; if (key < x->key) { if (NULL != x->left) { x = x->left; } else { break; } } else if (key > x->key) { if (NULL != x->right) { x = x->right; } else { break; } } else { return root; } }
if (NULL == y || y->key > key) { if (NULL == y) root = z; else y->left = z; } else { y->right = z; }
// 设置z的左右子树为空并且颜色是red,注意新插入的节点颜色都是red z->parent = y; z->left = z->right = NULL; z->color = RED;
// 对红黑树进行修正 return RB_InsertNode_Fixup(root, z); }
/*----------------------------------------------------------- | 函数作用:对插入key值之后的树进行修正 | 输入参数:根节点root,插入的结点z | 返回参数:根节点root -------------------------------------------------------------*/ PRBTree RB_InsertNode_Fixup(PRBTree root, PRBTree z) { PRBTree y; while (root != z && RED == z->parent->color) // 当z不是根同时父节点的颜色是red { if (z->parent == z->parent->parent->left) // 父节点是祖父节点的左子树 { y = z->parent->parent->right; // y为z的伯父节点 if (NULL != y && RED == y->color) // 伯父节点存在且颜色是red { z->parent->color = BLACK; // 更改z的父节点颜色是B y->color = BLACK; // 更改z的伯父节点颜色是B z->parent->parent->color = RED; // 更改z的祖父节点颜色是B z = z->parent->parent; // 更新z为它的祖父节点 } else // 无伯父节点或者伯父节点颜色是b { if (z == z->parent->right) // 如果新节点是父节点的右子树 { z = z->parent; Left_Rotate(z, root); } z->parent->color = BLACK; // 改变父节点颜色是B z->parent->parent->color = RED; // 改变祖父节点颜色是R Right_Rotate(z->parent->parent, root); } } else // 父节点为祖父节点的右子树 { y = z->parent->parent->left; // y为z的伯父节点 if (NULL != y && RED == y->color) // 如果y的颜色是red { z->parent->color = BLACK; // 更改父节点的颜色为B y->color = BLACK; // 更改伯父节点的颜色是B z->parent->parent->color = RED; // 更改祖父节点颜色是R z = z->parent->parent; // 更改z指向祖父节点 } else // y不存在或者颜色是B { if (z == z->parent->left) // 如果是父节点的左子树 { z = z->parent; Right_Rotate(z, root); } z->parent->color = BLACK; // 改变父节点的颜色是B z->parent->parent->color = RED; // 改变祖父节点的颜色是RED Left_Rotate(z->parent->parent, root); } } } // while(RED == z->parent->color)
// 根节点的颜色始终都是B root->color = BLACK;
return root; }
/*----------------------------------------------------------- | 函数作用:在树中删除key值 | 输入参数:根节点root,待插入结点的关键值key | 返回参数:根节点root -------------------------------------------------------------*/ PRBTree RB_DeleteNode(PRBTree root, KEY key) { PRBTree x, y, z, x_parent;
// 首先查找需要删除的节点 z = Find_Node(root, key); if (NULL == z) return root;
y = z, x = NULL, x_parent = NULL;
// y是x按照中序遍历树的后继 if (NULL == y->left) { x = y->right; } else { if (NULL == y->right) { x = y->left; } else { y = y->right; while (NULL != y->left) y = y->left; x = y->right; } }
if (y != z) { z->left->parent = y; y->left = z->left; if (y != z->right) { x_parent = y->parent; if (NULL != x) x->parent = y->parent; y->parent->left = x; y->right = z->right; z->right->parent = y; } else { x_parent = y; } if (root == z) { root = y; } else if (z == z->parent->left) { z->parent->left = y; } else { z->parent->right = y; } y->parent = z->parent; NODECOLOR color = y->color; y->color = z->color; z->color = color; y = z; } else { x_parent = y->parent; if (NULL != x) x->parent = y->parent; if (root == z) { root = y; } else if (z == z->parent->left) { z->parent->left = x; } else { z->parent->right = x; }
}
if (BLACK == y->color) { root = RB_DeleteNode_Fixup(root, x, x_parent); } free(y);
return root; }
/*----------------------------------------------------------- | 函数作用:对删除key值之后的树进行修正 | 输入参数:根节点root,删除的结点的子结点x | 返回参数:根节点root -------------------------------------------------------------*/ PRBTree RB_DeleteNode_Fixup(PRBTree root, PRBTree x, PRBTree x_parent) { PRBTree w;
while (x != root && (NULL == x || BLACK == x->color)) { if (x == x_parent->left) // 如果x是左子树 { w = x_parent->right; // w是x的兄弟结点 if (RED == w->color) // 如果w的颜色是红色 { w->color = BLACK; x_parent->color = RED; Left_Rotate(x_parent, root); w = x_parent->right; } if ((NULL == w->left || BLACK == w->left->color) && (NULL == w->right || BLACK == w->right->color)) { w->color = RED; x = x_parent; x_parent = x_parent->parent; } else { if (NULL == w->right || BLACK == w->right->color) { if (NULL != w->left) w->left->color = BLACK;
w->color = RED; Right_Rotate(w, root); w = x_parent->right; }
w->color = x_parent->color; x_parent->color = BLACK; if (NULL != w->right) w->right->color = BLACK; Left_Rotate(x->parent, root); break; } } else { w = x_parent->left; // w是x的兄弟结点
if (RED == w->color) // 如果w的颜色是红色 { w->color = BLACK; x_parent->color = RED; Right_Rotate(x_parent, root); w = x_parent->left; } if ((NULL == w->left || BLACK == w->left->color) && (NULL == w->right || BLACK == w->right->color)) { w->color = RED; x = x_parent; x_parent = x_parent->parent; } else { if (NULL == w->left || BLACK == w->left->color) { if (NULL != w->right) w->right->color = BLACK;
w->color = RED; Left_Rotate(w, root); w = x_parent->left; }
w->color = x_parent->color; x_parent->color = BLACK; if (NULL != w->left) w->left->color = BLACK; Right_Rotate(x->parent, root); break; } } }
x->color = BLACK;
return root; }
void Print_Node(PRBTree node) { char* color[] = {"BLACK", "RED"}; printf("Key = %d,\tcolor = %s", node->key, color[node->color]); if (NULL != node->parent) printf(",\tparent = %d", node->parent->key); if (NULL != node->left) printf(",\tleft = %d", node->left->key); if (NULL != node->right) printf(",\tright = %d", node->right->key); printf("\n"); }
// 中序遍历树, 加了一个判断, 如果输出的数据不满足序列关系就报错退出 void Mid_Visit(PRBTree T) { if (NULL != T) { if (NULL != T->left) { if (T->left->key > T->key) { printf("wrong!\n"); exit(-1); } Mid_Visit(T->left); } Print_Node(T); if (NULL != T->right) { if (T->right->key < T->key) { printf("wrong\n"); exit(-1); } Mid_Visit(T->right); } } }
// 中序删除树的各个节点 void Mid_DeleteTree(PRBTree T) { if (NULL != T) { if (NULL != T->left) Mid_DeleteTree(T->left); PRBTree temp = T->right; free(T); T = NULL; if (NULL != temp) Mid_DeleteTree(temp); } }
void Create_New_Array(int array[], int length) { for (int i = 0; i < length; i++) { array[i] = rand() % 256; } }
int main(int argc, char *argv[]) { srand(time(NULL)); PRBTree root = NULL; int i; for (i = 0; i < 100000; i++) { root = RB_InsertNode(root, rand() % 10000); }
Mid_Visit(root);
// 删除整颗树 Mid_DeleteTree(root);
return 0; }
|