红黑树这一块的知识有点难懂,,难懂的地方就是左旋,右旋,插入调整,和删除调整,对我来说最难懂的还是删除部分,一直只得形不得意,,看着算法导论眼睛疼。。。这里有一位大佬讲的还行-》https://www.cnblogs.com/skywang12345/p/3245399.html
下面是我实现的代码,不够完善,因为我没有重复使用树根,先这样吧,回头复习时把他完善。。下面代码可以运行的哦,注意引用符号,之前有个地方就是因为我加了个引用就一直栈溢出。。。删除操作部分我注释了的那种方法也是可以的,不过我觉得麻烦。。从网上看到了一种简洁的写法就修改了下
代码:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
//红黑树学习,主要难点,左旋,右旋,插入,删除
//红黑树主要是为了保证二叉搜索树的平衡,避免出现一条简单路径的深度高,一条简单路径深度低的情况
//红黑树的效率高,保证在最坏的情况下的时间复杂度的为O(lgn)
//红黑树的五条性质:
//1.每个节点或是红色的,或是黑色的
//2.根节点是黑色的
//3.每个叶节点(NIL)是黑色的
//4.如果一个节点是红色的,则它的两个子结点都是黑色的
//5.对每个结点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色结点
//*************************数据结构定义阶段*************************
typedef enum{RED,BLACK} Color;
typedef struct BST{
int key; //关键字
Color color;//节点颜色
struct BST *p,*left,*right; //双亲,左孩子,右孩子
BST(){color = BLACK; p = left = right = NULL;} //无参构造
}BSTNode;
typedef struct BST_Root{ //树根
BSTNode *root;
BSTNode *nil; //红黑树是以一个标记结尾的
BST_Root(){ //
nil = new BSTNode();
nil->color = BLACK;
nil->p = nil->left = nil->right = NULL;
root = nil;
}
}BSTRoot;
BSTRoot BT; //这里我直接把树根先建好,后面方便使用nil
//*************************数据结构定义阶段*************************
//*************************查找*************************
//和一般的二叉搜索树一样的操作,只是结尾标志不再是NULL,而是统一的nil
BSTNode* tree_search(BSTNode *&T,int k){ //递归查找
if(T != BT.nil && T->key != k){
if(k < T->key)
return tree_search(T->left,k);
else
return tree_search(T->right,k);
}
return T;
}
BSTNode* interative_tree_search(BSTNode *&T,int k){ //非递归查找
BSTNode *t = T;
while(t != BT.nil && t->key != k){
if(k < t->key)
t = t->left;
else
t = t->right;
}
return t;
}
//*************************查找*************************
//************************最大关键字查询,最小关键字查询,前驱和后继查询************************
BSTNode* tree_minmum(BSTNode *&T){ //最小关键字查询
BSTNode *t = T;
while(t!=BT.nil && t->left != BT.nil){
t = t->left;
}
return t;
}
BSTNode* tree_maxmum(BSTNode *&T){ //最大关键字查询
BSTNode *t = T;
while(t!=BT.nil && t->right != BT.nil){
t = t->right;
}
return t;
}
BSTNode* tree_successor(BSTNode *&T){ //后继查询,后继就是大于T.x的最小关键字节点
BSTNode *t = T,*y = BT.nil;
if(T == BT.nil) return T;
if(T->right != BT.nil) //如果右子树不为空直接求右子树的最小节点
return tree_minmum(T->right);
y = t->p;
while(y != BT.nil && y->right == t){
t = y;
y = y->p;
}
return y;
}
BSTNode* tree_predecessor(BSTNode *&T){ //前驱查询,前驱就是小于T.x的最大关键字节点
BSTNode *t = T,*y = BT.nil;
if(T == BT.nil) return T;
if(T->left != BT.nil) //如果左子树不为空直接求左子树的最大节点
return tree_maxmum(T->left);
y = t->p;
while(y != BT.nil && y->left == t){ //这里就是没有左子树的情况,往上找,看看上面还有没有小于t.x的节点
t = y;
y = y->p;
}
return y;
}
//************************最大关键字查询,最小关键字查询,前驱和后继查询************************
//************************左旋和右旋************************
void left_rotate(BSTNode *&T,BSTNode * x){
BSTNode *y = x->right; //x的右孩子取出来
x->right = y->left; //把y的左孩子给x当右孩子
if(y->left != BT.nil){ //y的左孩子不是nil就让它认x为爸爸
y->left->p = x;
}
y->p = x->p; //y认x的爸爸为爸爸
if(x->p == BT.nil) //如果x原来是根节点,那么更新根节点
BT.root = y;
else if(x == x->p->left) //看x原来是它爸爸的左孩子还是右孩子,因为从现在开始x不是它原来爸爸的儿子了,y才是
x->p->left = y;
else
x->p->right = y;
y->left = x;
x->p = y;
}
void right_rotate(BSTNode *&T,BSTNode *x){ //右旋,同上面是对称的
BSTNode *y = x->left;
x->left = y->right;
if(y->right != BT.nil)
y->right->p = x;
y->p = x->p;
if(x->p == BT.nil)
BT.root = y;
else if(x == x->p->left)
x->p->left = y;
else
x->p->right = y;
y->right = x;
x->p = y;
}
//************************左旋和右旋************************
//************************插入************************
void RB_Insert_Fixup(BSTNode *&T,BSTNode *&z){
//有三种情况,1.父节点是黑色的;2.z是根;3.父节点是红色的;三种情况只有3需要调整,1,2种不用
while(z->p->color == RED){
//看看父节点是祖父结点的左孩子还是右孩子
if(z->p == z->p->p->left){
//取得叔叔结点
BSTNode *y = z->p->p->right;
if(y->color == RED){
//如果叔叔结点也是红色的,那么叔叔结点和父节点都修改成黑色,祖父结点修改成红色,再把当前结点改成祖父结点
//这样修改就满足了第四条性质
z->p->color = BLACK;
y->color = BLACK;
z->p->p->color = RED;
z = z->p->p;
}else if(z == z->p->right){
//如果叔叔结点是黑色的,并且当前结点是父节点的右孩子,那么把当前结点修改成父节点,再对当前结点左旋
z = z->p;
left_rotate(T,z);
}else if(z == z->p->left){
//如果叔叔结点时黑色的,并且当前结点是父节点的左孩子,那么把父节点修改成黑色,祖父结点修改成红色,并对祖父结点右旋
z->p->color = BLACK;
z->p->p->color = RED;
right_rotate(T,z->p->p);
}
}else { //下面操作与上面对称
BSTNode *y = z->p->p->left;
if(y->color == RED){
y->color = BLACK;
z->p->color = BLACK;
z->p->p->color = RED;
z = z->p->p;
}else if(z == z->p->left){
z = z->p;
right_rotate(T,z);
}else if(z == z->p->right){
z->p->color = BLACK;
z->p->p->color = RED;
left_rotate(T,z->p->p);
}
}
}
BT.root->color = BLACK; //最后把根结点设置成黑色,此时整棵树以满足所有红黑树性质
}
void tree_insert(BSTNode *&T, int k){ //插入操作基本一样,就最后多了两步
BSTNode *t = T,*y = T;
BSTNode *z = new BSTNode();
z->key = k;
z->p = z->left = z->right = BT.nil;
z->color = RED; //这里要把颜色设置为红色
while(t!=BT.nil){
y = t;
if(k < t->key)
t = t->left;
else
t = t->right;
}
z->p = y;
if(y == BT.nil)
BT.root = z;
else if(k < y->key)
y->left = z;
else
y->right = z;
RB_Insert_Fixup(T,z); //调整颜色,保持红黑性质
}
//************************插入************************
//************************删除************************
void tree_transplant(BSTNode *&T,BSTNode *&u,BSTNode *&v){
if(u->p == BT.nil)
BT.root = v;
else if(u == u->p->left)
u->p->left = v;
else
u->p->right = v;
v->p = u->p;
}
void RB_Delete_Fixup(BSTNode *&T,BSTNode *x){
while(x != T && x->color == BLACK){
if(x == x->p->left){
BSTNode *w = x->p->right;
if(w->color == RED){
w->color = BLACK;
x->p->color = RED;
left_rotate(T,x->p);
w = x->p->right; //w是x的兄弟结点,所以这里要修改
}else if(w->left->color == BLACK && w->right->color == BLACK){
w->color = RED;
x = x->p;
}else if(w->left->color == RED && w->right->color == BLACK){
w->left->color = BLACK;
w->color = RED;
right_rotate(T,w);
w = x->p->right;
}
if(w->right->color == RED){
w->color = x->p->color;
x->p->color = BLACK;
w->right->color = BLACK;
left_rotate(T,x->p);
x = T;
}
}else{
BSTNode *w = x->p->left;
if(w->color == RED){
w->color = BLACK;
x->p->color = RED;
right_rotate(T,x->p);
w = x->p->left;
}else if(w->left->color == BLACK && w->right->color == BLACK){
w->color = RED;
x = x->p;
}else if(w->left->color == BLACK && w->right->color == RED){
w->right->color = BLACK;
w->color = RED;
w = x->p->left;
}
if(w->right->color == BLACK){
w->color = x->p->color;
x->p->color = BLACK;
w->left->color = BLACK;
right_rotate(T,x->p);
x = T;
}
}
}
x->color = BLACK;
}
void tree_delete(BSTNode *&T,int k){ //删除
BSTNode *z = tree_search(T,k);
if(z == BT.nil) return;
BSTNode *y = z,*x = NULL;
// Color y_color = y->color;
//如果两个孩子,就找到右子树中最小的结点,将之代替,然后直接删除该结点即可
if(z->left != BT.nil && z->right != BT.nil){
y = tree_minmum(z->right);
z->key = y->key;//这里只对值进行复制,并不复制颜色,以免破坏红黑树的性质
z = y;
}
if(z->left == BT.nil){
x = z->right;
tree_transplant(T,z,z->right);
}
else if(z->right == BT.nil){
x = z->left;
tree_transplant(T,z,z->left);
}
if(z->color == BLACK)
RB_Delete_Fixup(T,x);
delete z;
// else{
// y = tree_minmum(z->right); //后继
// y_color = y->color;
// x = y->right;
// if(y->p == z)
// x->p = z;
// else {
// tree_transplant(T,y,y->right);
// y->right = z->right;
// y->right->p = y;
// }
// tree_transplant(T,z,y);
// y->left = z->left;
// y->left->p = y;
// y->color = z->color;
// }
// if(y_color == BLACK)
// RB_Delete_Fixup(T,x);
}
//************************删除************************
void inorder_input(BSTNode *&T){ //中序遍历输出
if(T!=BT.nil){
inorder_input(T->left);
printf("%d ",T->key);
inorder_input(T->right);
}
}
int main(){
int a[9] = {11,2,14,1,7,15,5,8,4};
for(int i = 0;i<9;i++)
tree_insert(BT.root,a[i]);
printf("inorder input primitive sequence: ");
inorder_input(BT.root);
putchar('\n');
printf("after digit 7 be deleted: ");
tree_delete(BT.root, 7);
tree_delete(BT.root,14);
inorder_input(BT.root);
putchar('\n');
system("pause");
return 0;
}