#ifndef RBTREE_H_ #define RBTREE_H_ #include <iostream> #include <string> using namespace std; #define BLACK 0 #define RED 1 struct Node { int key; //节点键值 string ID; int color; //节点颜色 Node *left; //左叶节点 Node *right; //右叶节点 Node *parent; //父节点 }; class RBTree { private: Node *root; //根节点 Node *nil; //哨兵,颜色为BLACK int bHeight; //黑高 int nodeNum; //节点个数 void LeftRotate(Node *x); //左旋转 void RightRotate(Node *x); //右旋转 void InsertFixup(Node *p); //插入节点p时维护红黑树性质 void Transplant(Node *u, Node *v); //用另一棵子树替换一棵子树并成为其双亲的孩子结点 void DeleteFixup(Node *x); //删除结点时维护红黑树性质 public: RBTree(); void Destory(Node *p); //销毁树 Node *Minimum(Node *x); //最小键值结点 Node *Maximum(Node *x); //最大键值结点 Node *Successor(Node *x); //后继 Node *Predecessor(Node *x); //前驱 Node *Search(Node *x,int k); //搜索树 void Insert(Node *z); //插入节点 void Delete(int k); //删除结点,该结点键值为k void Out(Node *p); void Display(); }; /* 功能:左旋转 条件:x的右孩子y不是nil 步骤:x成为y的左孩子,y的左孩子成为x的右孩子,x的左孩子和y的右孩子不变 */ void RBTree::LeftRotate(Node *x) { Node *y=x->right; x->right=y->left; //修改x的右孩子 y->left->parent=x; //修改y的左孩子的父节点 y->parent=x->parent; if(x->parent==nil) root=y; else if(x==x->parent->left) //x为左孩子 x->parent->left=y; else //x为右孩子 x->parent->right=y; y->left=x; x->parent=y; } /* 功能:右旋转 条件:x的左孩子不能为空 步骤:x成为y的右孩子,y的右孩子成为x的左孩子 说明:与左旋转对称 */ void RBTree::RightRotate(Node *x) { Node *y=x->left; x->left=y->right; if (y->right!=nil) y->right->parent=x; y->parent=x->parent; if(x->parent==nil) root=y; else if(x==x->parent->left) x->parent->left=y; else x->parent->right=y; y->right=x; x->parent=y; } /* 功能:插入节点p时维护红黑树性质 说明:p的颜色为红色,所以p的父节点不能为红色 红黑树相关性质:(2)根结点是黑色的(改变) (4)如果一个节点是红色的,那么他的两个子节点都是黑色的(改变) (5)对每个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点(始终成立) */ void RBTree::InsertFixup(Node *p) { while(p->parent->color==RED) //p的父节点也是红色 if(p->parent==p->parent->parent->left) //如果p的父节点是左节点 { Node *y=p->parent->parent->right; //y为p的叔节点 if(y->color==RED) //情况1:叔节点y为红色(与父节点在左或右无关) { p->parent->color=BLACK; y->color=BLACK; p->parent->parent->color=RED; p=p->parent->parent; } else //叔结点y为黑色 { if (p == p->parent->right) //情况2:p的叔结点y是黑色且p是一个右孩子(包括2种情况:父节点在左和右) { p = p->parent; LeftRotate(p); } //Display(); p->parent->color=BLACK; //情况3:p的叔结点y是黑色且p是一个左孩子(方法:改变颜色做右旋) p->parent->parent->color=RED; RightRotate(p->parent->parent); } } else if (p->parent == p->parent->parent->right) //如果p的父节点是右节点 //the same as above,exchange right and left { Node *y=p->parent->parent->left; if(y->color==RED) { p->parent->color=BLACK; y->color=BLACK; p->parent->parent->color=RED; p=p->parent->parent; } else { if (p == p->parent->left) { p = p->parent; RightRotate(p); } p->parent->color=BLACK; p->parent->parent->color=RED; LeftRotate(p->parent->parent); } } root->color = BLACK; } /* 功能:删除节点p时维护红黑树性质 问题:(1)如果y是原来的根结点,,而y的一个红色的孩子成为新的根结点,则违反了性质2 (2)如果x替换y后x和x-parent是红色的,则违反了性质4 (3)在树中移动y将导致先前包含y的任何路径上黑色结点个数少1 */ void RBTree::DeleteFixup(Node *x) { while (x != root && x->color == BLACK) { if (x == x->parent->left) { Node *w = x->parent->right; if (w->color == RED) //情况1:x的兄弟结点是红色的 { x->parent->color = RED; w->color = BLACK; LeftRotate(x->parent); w = x->parent->right; //设置新的w } else { if (w->right->color == BLACK && w->left->color == RED) //情况2:x的兄弟结点w是黑色,而w的两个子节点都是黑色 { w->color = RED; x->parent->color = BLACK; x = x->parent; } else { if (w->right->color == RED) //情况3:x的兄弟w是黑色的,w的右孩子是黑色(w的左孩子是红色)。 { w->color = BLACK; w->left->color = RED; RightRotate(w); w = x->parent->right; } //情况3转换为情况4 //情况4:x的兄弟w是黑色的,且w的右孩子时红色的 w->color = x->parent->color; x->parent->color = BLACK; w->right->color = BLACK; LeftRotate(x->parent); x = root; //为了终止循环 } } }//if else { Node *w = x->parent->left; if (w->color == RED) //情况1:x的兄弟结点是红色的 { x->parent->color = RED; w->color = BLACK; RightRotate(x->parent); w = x->parent->left; //设置新的w } else { if (w->left->color == BLACK && w->right->color == RED) //情况2:x的兄弟结点w是黑色,而w的两个子节点都是黑色 { w->color = RED; //x->parent->color = BLACK; x = x->parent; } else { if (w->left->color == RED) //情况3 { w->color = BLACK; w->right->color = RED; LeftRotate(w); w = x->parent->left; } //情况3转换为情况4 //情况4:x的兄弟w是黑色的,且w的右孩子时红色的 w->color = x->parent->color; x->parent->color = BLACK; w->left->color = BLACK; RightRotate(x->parent); x = root; //为了终止循环 } } }//else }//while x->color = BLACK; //如果X节点原来为红色,那么直接改为黑色 } /* 功能:用另一棵子树替换一棵子树并成为其双亲(父节点)的孩子结点 输入参数:以v为根的子树替换以u为根的子树时,结点u的双亲变为结点v的双亲,并且最后v成为u的双亲的相应孩子 */ void RBTree::Transplant(Node *u, Node *v) { if (u->parent == nil) root = v; else if (u == u->parent->left) u->parent->left = v; else u->parent->right = v; v->parent = u->parent; } /*构造函数*/ RBTree::RBTree() { nil=new Node; nil->color=BLACK; root=nil; bHeight=0; nodeNum=0; } /*销毁树,类似于析构函数,但是要手动调用*/ void RBTree::Destory(Node *p) { if(p==nil) delete p; else { Destory(p->left); Destory(p->right); delete p; } } /* 功能:沿着某一结点,找到最小键值对应的结点 */ Node *RBTree::Minimum(Node *x) { while (x->left != nil) x = x->left; return x; } /* 功能:沿着某一结点,找到最大键值对应的结点 */ Node *RBTree::Maximum(Node *x) { while (x->right != nil) x = x->right; return x; } /* 功能:找到后继结点 说明:按中序遍历的次序查找后继,如果所有关键字都不同,则一个结点的后继是大于x->key的最小关键字的结点。即右子树中向左遍历,左孩子为nil的结点 */ Node *RBTree::Successor(Node *x) { if (x->right != nil) return Minimum(x->right); Node *y = x->parent; while (y != nil&&x == y->right) { x = y; y = y->parent; } return y; } /* 功能:找到前继结点 说明:按中序遍历的次序查找前继,如果所有关键字都不同,则一个结点的后继是大于x-<key的最大关键字的结点。 */ Node *RBTree::Predecessor(Node *x) { if (x->left != nil) return Maximum(x->left); Node *y = x->parent; while (y != nil&&x == y->left) { x = y; y = y->parent; } return y; } /* 功能:根据键值搜索树,返回指向找到结点的指针,找不到返回nil 输入参数:指向树根的指针x和关键字k;x的作用是迭代 */ Node *RBTree::Search(Node *x,int k) { if (x == nil || k == x->key) return x; if (k < x->key) return Search(x->left, k); else return Search(x->right, k); } /* 功能:插入一个节点 入口参数:节点p 说明:插入过程按普通二叉搜索树,调用InsertFixup()函数用来保持红黑树性质 */ void RBTree::Insert(Node *z) { Node *p=new Node; p=z; p->color = RED; if (root == nil) { p->parent = nil; root = p; } else { Node *x = root; Node *y = nil; while (x != nil) { y = x; //最后y总为x的父节点 if (p->key<x->key) x = x->left; else x = x->right; } p->parent = y; //这样,p就是x的兄弟 if (p->key<y->key) y->left = p; else y->right = p; } p->left = nil; p->right = nil; nodeNum++; InsertFixup(p); } /* 功能:删除一个结点,其键值k 入口参数:待删除的结点的键值 说明:删除后用DeleteFixup()来维护红黑树性质 */ void RBTree::Delete(int k) { Node *z = Search(root, k); Node *y = z; Node *x = nil; int oriColor = y->color; //y的最初颜色 if (z->left == nil) { x = z->right; //保存结点x的踪迹,最终移至结点y的原始位置上,指向y的唯一子节点或哨兵 Transplant(z,z->right); } else if (z->right == nil) { x = z->left; Transplant(z,z->left); } else { y = Minimum(z->right); oriColor = y->color; x = y->right; //x为y的右孩子,不是z的 if (y->parent != z) { Transplant(y,y->right); y->right = z->right; y->right->parent = y; } Transplant(z,y); y->left = z->left; y->left->parent = y; //* y->color = z->color; //最后把z的颜色赋给y,所以y的新位置不会出现两红情况 } if (oriColor == BLACK) //如果y是红色,当y被删除或移动时,红黑性质依然保持 DeleteFixup(x); } void RBTree::Out(Node *p) { if(p!=nil) { Out(p->left); cout << p->color << " " << p->ID << " " << p->key << endl; Out(p->right); } } void RBTree::Display() { cout<<"颜色 "<<"ID "<<"key"<<endl; Out(root); } #endif
#include "RBTree.h" int main() { Node node[11]={{10,"A"},{14,"B"},{4,"C"},{12,"D"},{11,"E"},{13,"F"},{7,"G"},{16,"H"},{65,"I"},{43,"J"},{98,"K"}}; Node node2[6] = { { 41 }, { 38 }, { 31 }, { 12 }, { 19 }, { 8 } }; RBTree tree1; for (int i = 0; i < 11; i++) { tree1.Insert(node + i); tree1.Display(); } cout << "插入后:" << endl; tree1.Display(); tree1.Delete(11); cout << "删除后:" << endl; tree1.Display(); tree1.Delete(43); tree1.Display(); }