这里默认大家都知道红黑树的基本概念了,重点讲如何用代码实现(用的是c语言)
打卡机实战应用红黑树:
链接: https://github.com/furyParrot/ClockMachine_RBTree.
1节点定义
typedef struct Node
{
int keyvalue; //键值,一棵树中每个key都是唯一的,用来比较
int Red1Black0; //红黑,0黑 1红
Content * cont; //节点内容
struct Node * lson; //指向左儿子的指针
struct Node * rson; //指向右儿子的指针
struct Node * dad; //指向父节点的指针
} Node;
2增加节点
函数:int AddNode(Node* root, Node* newnode)
root:插入寻找的出发节点
newnode:需要插入的新节点
同向旋转操作并变色
1:左左:先旋转,然后root 以及 root->dad变色
2:右右:先旋转,然后root 以及 root->dad变色
不同向转为同向:
1左右–>变为同向情况并递归
2右左–>变为同向情况并递归
代码:
int AddNode(Node* root, Node* newnode) {
//是首个节点
if (root->keyvalue == 0) {
//将值赋值给根节点。
root->keyvalue = newnode->keyvalue;
ContCpy(root->cont, newnode->cont);
//free(newnode);
}
//不是
else {
if (newnode->keyvalue == root->keyvalue) {
root->cont = newnode->cont;
}
else if (newnode->keyvalue > root->keyvalue) { //要往右边插
if (root->rson != NULL) {//有右儿子的时候
AddNode(root->rson, newnode);
}
else {//没右儿子的时候
if (root->Red1Black0 == 0) { //爸是黑色,直接插入
root->rson = newnode;
newnode->dad = root;
}
else { //爸是红色
int dadRight1Left0 = (root->dad->rson == NULL) ? 0 : ((root->keyvalue == root->dad->rson->keyvalue) ? 1 : 0);
if (((dadRight1Left0 == 1) && (root->dad->lson != NULL) && (root->dad->lson->Red1Black0 == 1)) ||
((dadRight1Left0 == 0) && (root->dad->rson != NULL) && (root->dad->rson->Red1Black0 == 1))) {//叔叔是红色
//爸爸叔叔爷爷同时变色
root->Red1Black0 = 0;
if (dadRight1Left0 == 1) {
if (root->dad->lson != NULL)
root->dad->lson->Red1Black0 = 0;
}
else {
if (root->dad->rson != NULL)
root->dad->rson->Red1Black0 = 0;
}
root->dad->Red1Black0 = 1;
//将newnode插入
root->rson = newnode;
newnode->dad = root;
//爷爷变色,需要将爷爷插入祖父,如果没有祖父,就直接给爷爷变色
if (root->dad->dad == NULL) {
root->dad->Red1Black0 = 0;
}
else {
int ppRight1Left0 = (root->dad->dad->rson == NULL) ? 0 : ((root->dad->keyvalue == root->dad->dad->rson->keyvalue) ? 1 : 0);
if (ppRight1Left0 == 1) {
root->dad->dad->rson = NULL;
//root->dad->dad = NULL;
}
AddNode(root->dad->dad, root->dad);
}
}
else {//叔叔是黑色
if (dadRight1Left0 == 1) {//爸爸是爷爷的右儿子,和我同向:
Node* newpapa = CreatRBTree();
newpapa->keyvalue = root->dad->keyvalue;
ContCpy(newpapa->cont, root->dad->cont);
if (root->dad->lson != NULL) root->dad->lson->dad = newpapa;
newpapa->lson = root->dad->lson;
if (root->lson != NULL) root->lson->dad = newpapa;
newpapa->rson = root->lson;
root->dad->lson = newpapa;
newpapa->dad = root->dad;
root->dad->rson = newnode;
newnode->dad = root->dad;
root->dad->Red1Black0 = 0;
newpapa->Red1Black0 = 1;
root->dad->keyvalue = root->keyvalue;
ContCpy(root->dad->cont, root->cont);
//free(root);
}
else {//爸爸是爷爷的左儿子,和我反向:需要旋转操作
root->rson = newnode->lson;
if (newnode->lson != NULL) newnode->lson->dad = root;
newnode->lson = NULL;
root->dad->lson = newnode;
newnode->dad = root->dad;
root->dad = NULL;
AddNode(newnode, root);
}
}
}
}
}
else { //要往左边插
if (root->lson != NULL) {//有左儿子的时候
AddNode(root->lson, newnode);
}
else {//没左儿子的时候
if (root->Red1Black0 == 0) { //爸是黑色,直接插入
root->lson = newnode;
newnode->dad = root;
}
else { //爸是红色
int dadRight1Left0 = (root->dad->rson == NULL) ? 0 : ((root->keyvalue == root->dad->rson->keyvalue) ? 1 : 0);
if (((dadRight1Left0 == 1) && (root->dad->lson != NULL) && (root->dad->lson->Red1Black0 == 1)) ||
((dadRight1Left0 == 0) && (root->dad->rson != NULL) && (root->dad->rson->Red1Black0 == 1))) { //叔叔是红色
//爸爸叔叔爷爷同时变色
root->Red1Black0 = 0;
if (dadRight1Left0 == 1) {
if (root->dad->lson != NULL)
root->dad->lson->Red1Black0 = 0;
}
else {
if (root->dad->rson != NULL)
root->dad->rson->Red1Black0 = 0;
}
root->dad->Red1Black0 = 1;
//将newnode插入
root->lson = newnode;
newnode->dad = root;
//爷爷变色,需要将爷爷插入祖父,如果没有祖父,就直接给爷爷变色
if (root->dad->dad == NULL) {
root->dad->Red1Black0 = 0;
}
else {
int ppRight1Left0 = (root->dad->dad->rson == NULL) ? 0 : ((root->dad->keyvalue == root->dad->dad->rson->keyvalue) ? 1 : 0);
if (ppRight1Left0 == 1) {
root->dad->dad->rson = NULL;
//root->dad->dad = NULL;
}
AddNode(root->dad->dad, root->dad);
}
}
else {//叔叔是黑色
if (dadRight1Left0 == 0) {//爸爸是爷爷的左儿子,和我同向:
Node* newpapa = CreatRBTree();
newpapa->keyvalue = root->dad->keyvalue;
ContCpy(newpapa->cont, root->dad->cont);
if (root->dad->rson != NULL) root->dad->rson->dad = newpapa;
newpapa->rson = root->dad->rson;
if (root->rson != NULL) root->rson->dad = newpapa;
newpapa->lson = root->rson;
root->dad->rson = newpapa;
newpapa->dad = root->dad;
root->dad->lson = newnode;
newnode->dad = root->dad;
root->dad->Red1Black0 = 0;
newpapa->Red1Black0 = 1;
root->dad->keyvalue = root->keyvalue;
ContCpy(root->dad->cont , root->cont);
//free(root);
}
else {//爸爸是爷爷的右儿子,和我反向:需要旋转操作
root->lson = newnode->rson;
if (newnode->rson != NULL) newnode->rson->dad = root;
newnode->rson = NULL;
root->dad->rson = newnode;
newnode->dad = root->dad;
root->dad = NULL;
AddNode(newnode, root);
}
}
}
}
}
}
return 1;
}
3删除节点
int RemoveNode(Node* node)
删除平衡操作:
void DeleteBalance(Node* n)
链接: https://www.jianshu.com/p/84416644c080.
代码:
void DeleteBalance(Node* n){
//先删除,
Node* p = n->dad;
Node* s = (n->dad==NULL)?NULL:((n->dad->rson->keyvalue==n->keyvalue)?n->dad->lson:n->dad->rson);
int sL1R0 = (s==NULL)?3:( (n->dad->lson->keyvalue==s->keyvalue)?1:0);
Node* sl = (s==NULL)?NULL:(s->lson);
Node* sr = (s==NULL)?NULL:(s->rson);
if(n->Red1Black0==2){
n->Red1Black0 = 0;
}else{
if(n->dad == NULL){
n->keyvalue =0;
n->cont =NULL;
}else{
if(sL1R0==1){
n->dad->rson =NULL;
}else{
n->dad->lson =NULL;
}
//不知道为什么
//free(n);
}
}
//然后开始判断是否需要平衡
if(n->dad==NULL){//n为根节点,无需平衡
return;
}else{
if(s->Red1Black0!=1){//兄黑
if(((s->rson==NULL)|| (s->rson->Red1Black0!=1 ))&&((s->lson==NULL)||(s->lson->Red1Black0!=1))){//兄子节点全黑
if(p->Red1Black0!=1){//父黑
s->Red1Black0=1;
p->Red1Black0=2;
DeleteBalance(p);
}else{//父红
p->Red1Black0 =0;
s->Red1Black0 =1;
//交换ps颜色,平衡结束
}
}else{//兄子节点不全黑
//拐的时候,先弄直
if((sL1R0==1) && (sr!=NULL) && (sr->Red1Black0==1 )){
sr->dad = p;
p->lson = sr;
s->rson = sr->lson;
if(sr->lson!=NULL) sr->lson->dad = s;
s->dad = sr;
sr->lson =s;
s->Red1Black0=1;
sr->Red1Black0 =0;
}else if((sL1R0==0)&&(sl!=NULL)&&(sl->Red1Black0==1)){
sl->dad =p;
p->rson = sl;
s->lson = sl->rson;
if(sl->rson!=NULL)sl->rson->dad =s;
s->dad = sl;
sl->rson = s;
s->Red1Black0 =1;
sl->Red1Black0 =0;
}
//直的时候,直接处理
if(sL1R0 ==1){//s在左边
Node* newP = (Node*)malloc(sizeof(Node));
newP->cont = (Content*)malloc(sizeof(Content));
newP->keyvalue = p->keyvalue;
ContCpy(newP->cont,p->cont);
p->keyvalue = s->keyvalue;
ContCpy(p->cont,s->cont);
newP->lson = sr;
if(sr!=NULL)sr->dad = newP;
newP->rson = p->rson;
if(p->rson!=NULL)p->rson->dad = newP;
sl->dad = p;
p->lson = sl;
newP->dad = p;
p->rson = newP;
sl->Red1Black0 = 0;
}else{
Node* newP = (Node*)malloc(sizeof(Node));
newP->cont = (Content*)malloc(sizeof(Content));
newP->keyvalue = p->keyvalue;
ContCpy(newP->cont,p->cont);
p->keyvalue = s->keyvalue;
ContCpy(p->cont,s->cont);
newP->rson = sl;
if(sl!=NULL)sl->dad = newP;
newP->lson = p->lson;
if(p->lson!=NULL)p->lson->dad = newP;
sr->dad = p;
p->rson = sr;
newP->dad = p;
p->lson = newP;
sr->Red1Black0 = 0;
}
}
}
}
}
4查询节点
普普通通的递归查询
Node* FindNode(Node* root,int keyvalue) {
if(root==NULL){return NULL;}
if((root->keyvalue )== keyvalue){
return root;
}else{
if(keyvalue>(root->keyvalue)){
return FindNode(root->rson,keyvalue);
}else{
return FindNode(root->lson,keyvalue);
}
}
}
5遍历节点
普普通通的中序遍历
6以文件形式保存
函数指针形式,方便更换节点定义
int SaveRBTree(Node* root,char* filename, char* (*NodeToString)(Node* a)) {
SomeNodes a = GetAllNodes(root, 1000);
FILE * p = fopen(filename , "w");
if(p==NULL){printf("file ERROR!\n"); return 0;}
fprintf(p,"%d\n",a.num);
for(int i=0; i < a.num ; i++){
fprintf(p,"%s\n",NodeToString(a.datas[i]));
}
fclose(p);
return a.num;
}
Node* LoadRBTree(char* filename, Node* (*StringToNode)(char* s)) {
Node* root = CreatRBTree();
int num;
FILE* p=fopen(filename,"r");
if(p==NULL){printf("file ERROR!\n"); return NULL;}
fscanf(p,"%d",&num);
char *one_line;
one_line = (char*)malloc( 1000 * sizeof(char));
for(int i=0;i<num+1;i++){
fgets(one_line, 1000, p);
AddNode(root,StringToNode(one_line));
}
printf("file Load Succeed: %d Nodes Loaded!\n",num);
return root;
}