C++ 红黑树 (附带调试工具)

来源:互联网 发布:大连知行科技有限公司 编辑:程序博客网 时间:2024/06/05 01:19

这红黑树写得可谓是一路艰辛,本来前天就以为写好了,结果高兴的时候发现写出了BUG,而且看代码,在DOS下实在找不出,害得我用MFC写了一个查看的工具,简直苦逼了,当时心里郁闷得要死

先来说下代码,我插入 删除都用的是递归实现,说实话,感觉递归实现删除并不是特别好,因为在遇到出度大于1的节点时需要找到后继,再删除。那么真正删除的是后继节点,删除后平衡就需要从后继节点上开始。其实红黑树平衡与AVL不同,3次之内绝对解决平衡,所以递归回来效率也稍微有那么点点降低,不过setjmp可以直接跳出递归,我也没去那样测试性能了。还有就是由于del是递归下来的,到匹配的节点便要先判断,若需后继,还得递归,但真正这个地方有点绕,递归必须保证回去的时候不能漏掉节点平衡,我最开始BUG就出在这,漏掉了倒数第二个节点,看图吧



查找插入就不说很简单,还是再说下删除,balance里面就要去判断 父兄侄 这三者的颜色关系,ComputeFactor计算出哪边轻来做平衡,因为在排序树里面是分左右的。删除的代码也不算特别复杂,就通过旋转和改变颜色即可完成,注释里写得非常清晰,特别是删除平衡部分


下面介绍一下工具,使用介绍:

双击鼠标左键,打印当前树

在编辑框里面按esc 清屏

在编辑框里输入data 按enter 删除该节点并打印删除后的树


有些细节我也懒得弄了,为了省时间工具写得有点乱,树的宽度必须接近应用的宽度才会换行。。。如果不能换行自己调整下应用的宽 清屏再输出吧

源码下载:链接: http://pan.baidu.com/s/1pKH9YRL 密码: z3qv

先来上个图吧





linux c++ dos下代码:


#include<iostream>  #include<ctime>  #include<stack>  #include<cstdlib>#include <sstream>using namespace std;  enum Color{RED,BLACK};struct Node{      Node* left;Node* right;Color c;int data;};Node* nil;//顺时针旋转  右旋void cwSpin(Node* node,Node*& parent){parent->left=node->right;node->right=parent;parent=node;node->left->c=BLACK;node->right->c=BLACK;node->c=RED;}//逆时针旋转 左旋void ccwSpin(Node* node,Node*& parent){parent->right=node->left;node->left=parent;parent=node;node->left->c=BLACK;node->right->c=BLACK;node->c=RED;}void insert(Node*& node,Node*& parent,int data){if(node==nil){Node* new_node=new Node;new_node->c=RED;new_node->left=nil;new_node->right=nil;new_node->data=data;node=new_node;return;}else if(data<node->data){insert(node->left,node,data);}else{insert(node->right,node,data);}if(node->c==BLACK){if(node->right!=nil&&node->right->c==RED&&node->left!=nil&&node->left->c==RED){node->left->c=BLACK;node->right->c=BLACK;node->c=RED;}}else{if(parent==nil){return;}//node在父节点的左边if(parent->left==node){if(node->left!=nil&&node->left->c==RED){cwSpin(node,parent);}else if(node->right!=nil&&node->right->c==RED){Node* temp=node->right;node->right=node->right->left;temp->left=node;node=temp;cwSpin(node,parent);}}else{if(node->right!=nil&&node->right->c==RED){ccwSpin(node,parent);}else if(node->left!=nil&&node->left->c==RED){Node* temp=node->left;node->left=node->left->right;temp->right=node;node=temp;ccwSpin(node,parent);}}}}int deep=0;int count=0;void InOrderTranversal(Node* root,int level=1){if(root==nil){return;}InOrderTranversal(root->left,level+1);cout<<root->data<<':'<<level<<':'<<(Color)root->c<<endl;count++;if(level>deep){deep=level;}InOrderTranversal(root->right,level+1);}void release(Node* root){            if(root==nil){          return;      }            release(root->left);      release(root->right);            delete root;            }  //顺时针旋转  右旋void cwSpin2(Node* node,Node*& parent){parent->left=node->right;node->right=parent;parent=node;}//逆时针旋转 左旋void ccwSpin2(Node* node,Node*& parent){parent->right=node->left;node->left=parent;parent=node;}void ComputeFactor(int& fac,Node* node,Node* parent){if(parent==nil){return;}if(parent->left==node){fac=-1;}else if(parent->right==node){fac=1;}else{throw;}cout<<"fac计算:"<<fac<<endl;}void SetColor(Node* node,Color c){if(node!=nil){node->c=c;}}void balance(Node*& node, Node* parent, int& fac) {//左轻 需平衡if (fac == -1) {//红兄 父侄必黑 等效转化为(根重量不变,将红节点位置转换到轻的一边) 黑兄红父if (node->right->c == RED) {SetColor(node, RED);SetColor(node->right, BLACK);ccwSpin2(node->right, node);cout << "左轻红兄" << endl;balance(node->left, node, fac);}//黑兄 父侄可红可黑else {bool redNephew = false;//红父 if (node->c == RED) {//黑侄 将父置黑,兄置红(重的一侧-1,根+1),至此树恢复平衡if (node->right->left->c == BLACK&&node->right->right->c == BLACK) {SetColor(node, BLACK);SetColor(node->right, RED);fac = 0;cout << "左轻黑兄 红父黑侄" << endl;}//红侄 else {redNephew = true;}}//黑父else {//黑侄 将兄置红(重的一侧-1),还需继续平衡if (node->right->left->c == BLACK&&node->right->right->c == BLACK) {SetColor(node->right, RED);ComputeFactor(fac, node, parent);cout << "左轻黑兄 黑父黑侄" << endl;}//红侄 else {redNephew = true;}}//若为红侄子 只能通过旋转 且需2次旋转 用父节点增加左边重量,用侄子代替父节点,父红则红,父黑则黑if (redNephew) {Color c = node->c;//记录父节点颜色  //左红侄 右旋侄兄后 左旋侄父,父置黑,侄随父色,至此树恢复平衡if (node->right->left->c == RED) {SetColor(node, BLACK);SetColor(node->right->left, c);cwSpin2(node->right->left, node->right);ccwSpin2(node->right, node);fac = 0;cout << "左轻黑兄 左红侄" << endl;}//右红侄 左旋父兄 父侄置黑,兄随父色,至此树恢复平衡else if (node->right->right->c == RED) {SetColor(node, BLACK);SetColor(node->right->right, BLACK);SetColor(node->right, c);ccwSpin2(node->right, node);fac = 0;cout << "左轻黑兄 右红侄" << endl;}}}}//右轻 需平衡else if (fac == 1) {//红兄 父侄必黑 等效转化(根重量不变,将红节点位置转换到轻的一边)为 黑兄红父if (node->left->c == RED) {SetColor(node, RED);SetColor(node->left, BLACK);cwSpin2(node->left, node);cout << "右轻红兄" << endl;balance(node->right, node, fac);}//黑兄 父侄可红可黑else {bool redNephew = false;//红父 if (node->c == RED) {//黑侄 将父置黑,兄置红(重的一侧-1,根+1),至此树恢复平衡if (node->left->left->c == BLACK&&node->left->right->c == BLACK) {SetColor(node, BLACK);SetColor(node->left, RED);fac = 0;cout << "右轻黑兄 红父黑侄" << endl;}//红侄 else {redNephew = true;}}//黑父else {//黑侄 将兄置红(重的一侧-1),还需向上继续平衡if (node->left->left->c == BLACK&&node->left->right->c == BLACK) {SetColor(node->left, RED);ComputeFactor(fac, node, parent);cout << "右轻黑兄 黑父黑侄" << endl;}//红侄 else {redNephew = true;}}//若为红侄子 只能通过旋转 且需2次旋转 用父节点增加左边重量,用侄子代替父节点,父红则红,父黑则黑if (redNephew) {Color c = node->c;//记录父节点颜色  //右红侄 左旋侄兄后 右旋侄父,父置黑,侄随父色,至此树恢复平衡if (node->left->right->c == RED) {SetColor(node, BLACK);SetColor(node->left->right, c);ccwSpin2(node->left->right, node->left);cwSpin2(node->left, node);fac = 0;cout << "右轻黑兄 右红侄" << endl;}//左红侄 右旋父兄 父侄置黑,兄随父色,至此树恢复平衡else if (node->left->left->c == RED) {SetColor(node, BLACK);SetColor(node->left->left, BLACK);SetColor(node->left, c);cwSpin2(node->left, node);fac = 0;cout << "右轻黑兄 左红侄" << endl;}}}}}void Next(Node*& root, Node*& node, Node*& parent,Node* parent_parent, int& fac) {if (node->left == nil) {if (node->c == BLACK) {ComputeFactor(fac, node, parent);}root->data = node->data;if (node->right != nil) {Node* temp = node;node = node->right;if(node->c==RED){fac = 0;}SetColor(node, BLACK);delete temp;cout << "左到底空" << endl;}else {delete node;node = nil;cout << "左到底双空" << endl;}balance(parent, parent_parent, fac);return;}Next(root, node->left, node,parent, fac);balance(parent, parent_parent, fac);}//后继删除inline void del(Node*& root, Node*& parent, int data, int& fac) {if (root->data == data) {if (root->left == nil&&root->right == nil) {//删除了黑节点,树平衡被破坏if (root->c == BLACK) {ComputeFactor(fac, root, parent);}delete root;root = nil;cout << "左右空" << endl;}else if (root->right == nil) {if (root->c == BLACK) {ComputeFactor(fac, root, parent);}Node* temp = root;root = root->left;delete temp;cout << "右空" << endl;}else if (root->left == nil) {if (root->c == BLACK) {ComputeFactor(fac, root, parent);}Node* temp = root;root = root->right;delete temp;cout << "左空" << endl;}//出度大于1,需要转换为叶节点删除else {Next(root, root->right, root,parent, fac);}return;}else if (data<root->data) {del(root->left, root, data, fac);}else {del(root->right, root, data, fac);}balance(root, parent, fac);}void find(Node* root,int data,stringstream& ss){if(root==nil){cout<<"not find!"<<endl;return;}if(root->data==data){cout<<"i find it! path:"<<ss.str()<<endl;}else if(data<root->data){ss<<'0';find(root->left,data,ss);}else{ss<<'1';find(root->right,data,ss);}}int main(int argc,char* argv[]){srand(time(NULL));nil=new Node;nil->c=BLACK;Node* root=new Node;root->c=BLACK;root->left=nil;root->right=nil;root->data=0;Node* parent=nil;nil->left=parent;nil->right=parent;int num=100;if(argc>1){num=atoi(argv[1]);}clock_t t1=clock();for(int i=0;i<num;i++){          insert(root,parent,rand()%100);  root->c=BLACK;    }clock_t t2=clock();cout<<(double)(t2-t1)<<endl;InOrderTranversal(root);cout<<"树的深度为:"<<deep<<endl;cout<<"当前数目为:"<<count<<endl;while(true){int index;cout<<"please select function index(1.del 2.find):"<<endl;cin>>index;if(index==1){cout<<"please cin key data"<<endl;cin>>num;count=0;deep=0;int fac=0;del(root,parent,num,fac);InOrderTranversal(root);cout<<"树的深度为:"<<deep<<endl;cout<<"当前数目为:"<<count<<endl;}else if(index==2){cout<<"please cin key data"<<endl;cin>>num;stringstream ss;find(root,num,ss);}}release(root);delete nil;}





原创粉丝点击