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