红黑树相关算法实现(算法导论13章)
2012-10-22 14:39
501 查看
/* * copyright@nciaebupt 转载请保留此标记 * 所有代码已经在linux g++ 下编译通过,直接拷贝运行即可 如有问题欢迎指正 * 红黑树(red-black tree)是许多“平衡的”查找树中的一种。 * 红黑树的性质: * 1、每个结点或是红的,或是黑的。 * 2、根结点是黑的。 * 3、每个叶结点(NIL)是黑的。 * 4、如果一个结点是红的,则它的两个儿子都是黑的。 * 5、对每个结点,从该结点到其子孙的所有路径上包含相同数目的黑结点。 * 红黑树的结点比普通的二叉查找树的结点多了一个颜色属性。 */ #include <iostream> #include <vector> using namespace std; //将RED,BLACK颜色值定义成枚举类型 enum RBCOLOR {RED,BLACK}; //定义红黑树节点的数据结构 struct RBTreeNode { int key; RBCOLOR color; RBTreeNode * left; RBTreeNode * right; RBTreeNode * parent; }; //定义红黑树的数据结构 struct RBTree { RBTreeNode * root; //RBTreeNode * NIL = new RBTreeNode; RBTreeNode * NIL; }; void RBTreeInsertFixup(RBTree * T,RBTreeNode * z); void RBTreeDeleteFixup(RBTree * T,RBTreeNode * x); //实现红黑树的左旋操作 void RBLeftRotate(RBTree * T,RBTreeNode * x) { RBTreeNode * y = x->right; x->right = y->left; if(y->left != T->NIL) y->left->parent = x; y->parent = x->parent; if(x->parent == T->NIL) T->root = y; else if(x->parent->left ==x) x->parent->left = y; else x->parent->right =y; y->left = x; x->parent = y; } //实现红黑树的右旋操作 void RBRightRotate(RBTree * T,RBTreeNode * x) { RBTreeNode * y = x->left; if(x->left == T->NIL) return; x->left = y->right; if(y->right != T->NIL) { y->right->parent = x; } y->parent = x->parent; if(x->parent == T->NIL) T->root = y; else { if(x->parent->left == x) x->parent->left = y; else x->parent->right = y; } y->right = x; x->parent = y; } //红黑树插入 void RBTreeInsert(RBTree * T,RBTreeNode * z) { RBTreeNode * y = T->NIL; RBTreeNode * x = T->root; while(x != T->NIL) { y = x; if(z->key <= x->key) x = x->left; else x = x->right; } z->parent = y; if(y == T->NIL) T->root = z; else { if(z->key <= y->key) { y->left = z; } else { y->right = z; } } RBTreeInsertFixup(T,z); } //红黑树插入对节点重新着色 void RBTreeInsertFixup(RBTree * T,RBTreeNode * z) { RBTreeNode * y; if(z->parent == T->NIL)//z是根节点 { z->color = BLACK; return; } if(z->parent->color == BLACK)//这种情况下是平衡的 { return; } //一直循环,直到z的父节点的颜色为黑色 while(z->parent->color == RED) { if(z->parent == z->parent->parent->left)//当z的父节点是z祖父节点的左孩子时 { y = z->parent->parent->right;//y是z的叔叔 //case1:z的叔叔y 的颜色为红色 if(y->color == RED) { z->parent->color = BLACK; y->color = BLACK; z->parent->parent->color = RED; z = z->parent->parent; } else { if(z == z->parent->right)//case2:z的叔叔y 的颜色为黑色并且z是它父节点的右孩子 { z = z->parent; RBLeftRotate(T,z); } //case3:z的叔叔y 的颜色为黑色并且z是它父节点的左孩子 z->parent->color =BLACK; z->parent->parent->color = RED; RBRightRotate(T,z->parent->parent); } }//当z的父节点是z祖父节点的右孩子时 else //如果z的父节点是其祖父节点的右孩子 { y = z->parent->parent->left;//y是z的叔叔节点 if(y->color == RED)//case1:z的叔叔节点为红色,则z的父节点BLACK,祖父节点RED,叔叔节点BLACK均变色 { z->parent->color = BLACK; y->color = BLACK; z->parent->parent->color = RED; z = z->parent->parent; } else { if(z == z->parent->left)//case2:z的叔叔y的颜色为黑色并且z是它父节点的左孩子 { z = z->parent; RBRightRotate(T,z); } //case3:z的叔叔y的颜色为黑色并且z是它父节点的右孩子 z->parent->color = BLACK; z->parent->parent->color = RED; RBLeftRotate(T,z->parent->parent); } } } T->root->color = BLACK; } //红黑树的最小值 RBTreeNode * RBTreeMin(RBTree * T,RBTreeNode * x) { while(x->left != T->NIL)//最小元素就是树的最左结点 { x = x->left; } return x; } //红黑树中某个节点的后继 RBTreeNode * Successor(RBTree * T,RBTreeNode * x) { if(x->right != T->NIL)//如果x有右子树,那么x的后继就是其右子树中的最小元素 { return RBTreeMin(T,x->right); } else//如果x没有右子树,那么x的后继就是离它最近的、并且把它当做左子树部分的祖先 { RBTreeNode * y = x->parent; while(y != T->NIL && x != y->left) { x = y; y = y->parent; } return y; } } //红黑树中删除节点 RBTreeNode * RBTreeDelete(RBTree * T,RBTreeNode * z) { RBTreeNode * y; //y是要删除的那个节点 RBTreeNode * x; //x是要删除的节点y的子节点 //首先确定要删除的节点y(y可能就是z也可能是z的后继) if(z->left == T->NIL || z->right == T->NIL)//这个条件包含两种情况:如果z的左右子树都 //为空那么直接删除z,要删除的节点就是z;如果z的左右子树有一个为空,那么就用不为空的 //那个子节点代替z,要删除的节点也是z { y = z; } else//如果z的左右子树都不为空,那么要删除的节点就是z的后继 { y = Successor(T,z); } //确定y的子节点x(x可能为空) if(y->left != T->NIL) x = y->left; else x = y->right; //y只有一个孩子的情况,用孩子节点x代替y(此时若y != z则x->parent 也指向 y->parent) if(x != T->NIL) x->parent = y->parent; //y没有孩子或者只有一个孩子时,y的父节点与x建立链接(此时若y != z则y->parent->left/right也指向 x) if(y->parent == T->NIL) T->root = x; else { if(y->parent->left == y) y->parent->left = x; else y->parent->right = x; } //y有两个孩子时,交换y与z的key if(y != z) { z->key = y->key; } if(y->color == BLACK) RBTreeDeleteFixup(T,y); return y; } //红黑树删除操作对节点重新着色 void RBTreeDeleteFixup(RBTree * T,RBTreeNode * x) { RBTreeNode * brother; while(x != T->root && x->color == BLACK) { //the x is its parent's left child if(x == x->parent->left) { brother = x->parent->right;//get x's brother //case1:当前节点是黑色,且兄弟节点为红色(此时父节点和兄弟节点的子节点分为黑) if(brother->color == RED) { brother->color = BLACK; x->parent->color = RED; RBLeftRotate(T,x->parent); brother = x->parent->right; } //当前节点是黑色,且兄弟节点为黑色 if(brother->left->color == BLACK && brother->right->color == BLACK)//case2:当前节点是黑色,且兄弟是黑色,且兄弟节点的两个子节点全为黑色 { brother->color = RED; x = x->parent; } else if(brother->left->color == RED && brother->right->color == BLACK)//case3:当前节点是黑色,且兄弟是黑色,且兄弟节点的左子节点为红右子结点为黑色 { brother->color = RED; brother->left->color = BLACK; RBRightRotate(T,brother); brother = x->parent->right; } //case4:当前节点是黑色,且兄弟是黑色,且brother的右孩子为红色 brother->color = x->parent->color; x->parent->color = BLACK; brother->right->color = BLACK; RBLeftRotate(T,x->parent); x = T->root; } else //if(x == x->parent->right)//x是其父节点的右孩子 { brother = x->parent->left;//得到x的兄弟节点brother if(!brother || brother == T->NIL) return; if(brother->color == RED)//case1:当前节点是黑色,且兄弟节点为红色(此时父节点和兄弟节点的子节点分为黑) { brother->color = BLACK; x->parent->color = RED; RBRightRotate(T,x->parent); brother = x->parent->left; } //当前节点是黑色,且兄弟节点为黑色 if(brother->right->color == BLACK && brother->left->color == BLACK)//case2:当前节点是黑色,且兄弟是黑色,且兄弟节点的两个子节点全为黑色 { brother->color = RED; x = x->parent; } else if(brother->right->color == BLACK)//case3:当前节点是黑色,且兄弟是黑色,且兄弟节点的左子节点为红右子结点为黑色 { brother->left->color = BLACK; brother->color = RED; RBLeftRotate(T,brother); brother = x->parent->left; } //case4:当前节点是黑色,且兄弟是黑色,且brother的右孩子为红色 brother->color = x->parent->color; x->parent->color = BLACK; brother->right->color = BLACK; if(x->parent->left != NULL) RBRightRotate(T,x->parent); x = T->root; } } x->color = BLACK; } //红黑树查找值为key的某个节点 RBTreeNode * RBTreeSearch(RBTree * T,int key) { RBTreeNode * x = T->root; while(x != T->NIL && x->key != key) { if(key < x->key) x = x->left; else x = x->right; } return x; } //中序遍历红黑树 void InorderRBTreeWalk(RBTree * T,RBTreeNode * x) { if(x != T->NIL) { InorderRBTreeWalk(T,x->left); cout<<x->key<<endl; InorderRBTreeWalk(T,x->right); } } int main(int argc, char **argv) { //15,5,3,12,10,13,6,7,16,20,18,23 RBTree * T = new RBTree; T->NIL = new RBTreeNode; T->NIL->color = BLACK; T->NIL->key = 10000; T->NIL->left = NULL; T->NIL->parent = NULL; T->NIL->right = NULL; T->root = T->NIL; vector<int> vi; vi.push_back(12); vi.push_back(15); vi.push_back(5); vi.push_back(3); vi.push_back(10); vi.push_back(13); vi.push_back(6); vi.push_back(7); vi.push_back(16); vi.push_back(20); vi.push_back(18); vi.push_back(23); //建立红黑树 for(vector<int>::iterator it = vi.begin(); it != vi.end();++it) { RBTreeNode * p = new RBTreeNode; p->color = RED; p->key = *it; p->left = T->NIL; p->parent = T->NIL; p->right = T->NIL; cout<<"Insert key : "<<p->key<<endl; RBTreeInsert(T,p); } cout<<"---------------------------------"<<endl; //中序遍历红黑树 InorderRBTreeWalk(T,T->root); /* cout<<"---------------------------------"<<endl; //查找红黑树中key为16的节点 RBTreeNode * x = RBTreeSearch(T,16); //当key为20的节点不为空时删除它 if(x != T->NIL) { cout<<"The key to be deleted is :"<<x->key<<endl; RBTreeDelete(T,x); } //中序遍历红黑树 InorderRBTreeWalk(T,T->root); */ cout<<"---------------------------------------"<<endl; for(vector<int>::iterator it = vi.begin(); it != vi.end();++it) { RBTreeNode * x = RBTreeSearch(T,*it); if(x != T->NIL) { cout<<"The key to be deleted is :"<<x->key<<endl; RBTreeDelete(T,x); } InorderRBTreeWalk(T,T->root); cout<<"---------------------------------------"<<endl; } return 0; }
相关文章推荐
- 算法导论13章之红黑树
- [算法导论]红黑树实现(插入和删除) @ Python
- 用c语言实现红黑树(依据算法导论上的方法)
- 二叉查找树相关算法实现(算法导论12章)
- 完整的C++实现算法导论十三章红黑树以及十四章中的顺序统计树
- 根据算法导论实现的红黑树
- 实现算法导论第三版中红黑树插入算法
- 【算法导论-34】红黑树、顺序统计树的Java实现
- 算法导论——红黑树插入算法C++实现
- Java实现算法导论中凸包问题Jarvis步进法
- 二叉树-你必须要懂!(二叉树相关算法实现-iOS)
- Java实现算法导论中求解模线性方程解(基于最大公约数欧几里得扩展算法)
- 红黑树(算法导论)
- 算法导论之红黑树的学习
- 算法导论 红黑树 学习 旋转(二)
- 【算法导论33】跳跃表(Skip list)原理与java实现
- 【算法】红黑树的讲解及插入删除算法实现原理
- 经典算法:红黑树的C语言实现 ( 插入 、删除 )
- 红黑树的删除(算法导论)
- 用于测试“红黑树算法实现的正确性”的工具示意图