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

这红黑树写得可谓是一路艰辛,本来前天就以为写好了,结果高兴的时候发现写出了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;
}





评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值