深入学习二叉树(05)红黑树

红黑树

一、红黑树性质

  1. 每个节点的颜色是红色或者黑色
  2. 根节点是黑色
  3. 每个叶子节点是黑色
  4. 每个红色节点的2个子节点一定是黑色
  5. 任意一节点出发到每个叶子节点的路径都包含相同数量的黑节点 (因此是 黑色完美平衡二叉树)

红黑树不是一个完美平衡二叉树,但从性质 5 可以总结红黑树是黑色完美平衡

二、红黑树节点

 我们把正在处理遍历的节点叫做当前节点如上图的D ,当前节点的上级节点叫父节点,其父亲的另一个子节点叫做兄弟节点,父节点的父节点叫祖父节点。祖父节点的另一个子节点叫叔叔节点

 红黑树能够自平衡的依靠 ,三种操作:左旋、右旋、变色

左旋:以某个节点为支点(旋转节点),其右子节点变为旋转节点的父节点,右子节点的左子节点变为旋转节点的右子节点

右旋:以某个节点作为支点/旋转节点,其左子节点变为旋转节点的父节点,左子节点的右子节点变为旋转节点的左子节点,右子节点保持不变

变色:节点的颜色由红变黑或者由黑变红

 左旋操作

 右旋操作

 旋转操作是局部的,红黑树总是通过旋转和变色来达到自平衡

 扩展:红色节点的父节点一定是黑色的

三、红黑树插入节点

红黑树插入的 八种场景分析,首先对节点进行约定

3.1  红黑树为空

这是一种简单的情景,直接把插入节点作为根节点,但是要注意根节点是黑色的,需要变色

3.2 插入节点的父节点为黑色节点

插入节点是红色的,父节点是黑色的,可以直接插入,无需自平衡

3.3 插入节点的父节点为红节点

该父节点不可能为根节点,所以插入节点总有祖父节点,所以分多种情况

3.4 父节点为红节点,叔叔节点存在并且为红节点

 根据性值推断,祖父节点一定为黑节点,此时情况是 黑红红,最简单的处理如下

  • 将 P 和 S 设置为黑色
  • 将 PP 设置为红色
  • 把 PP 设置为当前插入节点

左节点增加

右节点增加

 如果设置 PP 节点为红色,如果 PP 节点父节点是黑色,则无需处理。如果 PP 节点的父节点是红色,那么红黑树不再平衡,所以把PP 当作插入节点继续当插入节点做自平衡,直到平衡为止。

 红黑树的生长是自低向上的,而普通的二叉树是自顶向下的。

3.5 父节点为红节点,叔叔节点不存在或者为黑节点

因为叔叔节点为黑节点,而父亲节点为红节点

  • 将 P 设为黑色
  • 将 PP 设为红色
  • 对 PP 进行右旋

 当然,可以把 P 设为红色, I 和 PP 设为黑色,也是可以的,但是需要自底向上处理,多做多余的处理,既然能消化就不要麻烦祖辈们

3.6 父节点红,叔叔不存在,插入节点是其父节点的右子节点

  • 对 P  进行左旋
  • 把 P 设置为插入节点
  • 进行上述处理

3.7 叔叔节点不存在或者为黑节点,并且插入节点的父亲节点是祖父节点的右子节点

与上述方向相反

  • 将 P 设为 黑色
  • 将 PP 设为红色】
  • 对 PP 进行左旋

 

 参考代码

#include <stdio.h>
#include <stdlib.h>

const int RED = 0;
const int BLACK = 1;

typedef struct rb_node{
    struct rb_node* lchild, *rchild, *parent;
    int key, colour;
}rb_node;
rb_node* root;

rb_node* get_node(rb_node* parent, int key);
void rb_insert(int key);
rb_node* rb_search(int key);
void rb_delete(int key);
rb_node* clock_wise(rb_node* node);
rb_node* counter_clock_wise(rb_node* node);
void show_rb_tree(rb_node* node);

rb_node* get_node(rb_node* parent, int key){
    rb_node *tmp = (rb_node*)malloc(sizeof(rb_node));
    tmp->key = key;
    tmp->colour = RED;
    tmp->parent = parent;
    tmp->lchild = tmp->rchild = NULL;
    return tmp;
}

rb_node* clock_wise(rb_node* node){
    if(node == NULL || node->lchild == NULL)
    return NULL;

    rb_node *rb_1=node, *rb_2=node->lchild, *rb_3=node->lchild->rchild;
    if(rb_1->parent != NULL){
    if(rb_1->parent->lchild == rb_1)
        rb_1->parent->lchild = rb_2;
    else
        rb_1->parent->rchild = rb_2;
    }else if(rb_1 == root){
    root = rb_2;
    }
    rb_2->parent = rb_1->parent;

    rb_1->parent = rb_2;
    rb_2->rchild = rb_1;

    rb_1->lchild = rb_3;
    if(rb_3 != NULL)rb_3->parent = rb_1;

    return rb_2;    
}

rb_node* counter_clock_wise(rb_node* node){
    if(node == NULL || node->rchild == NULL)
    return NULL;

    rb_node *rb_1=node, *rb_2=node->rchild, *rb_3=node->rchild->lchild;
    if(rb_1->parent != NULL){
    if(rb_1->parent->lchild == rb_1)
        rb_1->parent->lchild = rb_2;
    else 
        rb_1->parent->rchild = rb_2;
    }
    else if(rb_1 == root){
    root = rb_2;
    }
    rb_2->parent = rb_1->parent;

    rb_1->parent = rb_2;
    rb_2->lchild = rb_1;

    rb_1->rchild = rb_3;
    if(rb_3 != NULL)rb_3->parent = rb_1;

    return rb_2;
}

rb_node* rb_search(int key){
    rb_node *p = root;
    while(p != NULL){
    if(key < p->key)
        p = p->lchild;
    else if(key > p->key)
        p = p->rchild;
    else
        break;
    }
    return p;
}

void rb_insert(int key){
    rb_node *p=root, *q=NULL;

    if(root == NULL){
    root = get_node(NULL, key);
    root->colour = BLACK;
    return;
    }

    while(p != NULL){
    q = p;
    if(key < p->key)
        p = p->lchild;
    else if(key > p->key)
        p = p->rchild;
    else return;
    }

    if(key < q->key)
    q->lchild = get_node(q, key);
    else
    q->rchild = get_node(q, key);

    while(q != NULL && q->colour == RED){
    p = q->parent;//p won't null, or BUG.

    if(p->lchild == q){
        if(q->rchild != NULL && q->rchild->colour == RED)
        counter_clock_wise(q);        
        q = clock_wise(p);
        q->lchild->colour = BLACK;
    }
    else{
        if(q->lchild != NULL && q->lchild->colour == RED)
        clock_wise(q);
        q = counter_clock_wise(p);
        q->rchild->colour = BLACK;
    }

    q = q->parent;
    }
    root->colour = BLACK;
}

void show_rb_tree(rb_node* node){
    if(node == NULL)
    return;
//    printf("(%3d,%3d)\n", node->key, node->colour);
//    if(node->lchild != NULL){
//    printf("[-1]\n");
//    show_rb_tree(node->lchild);
//    }
//    if(node->rchild != NULL){
//    printf("[1]\n");
//    show_rb_tree(node->rchild);
//    }
//    printf("[0]\n");
    show_rb_tree(node->lchild); 
    printf("%3d",node->key);
     show_rb_tree(node->rchild);

}

void rb_delete(int key){
    rb_node *v = rb_search(key), *u, *p, *c, *b;
    int tmp;
    if(v == NULL) return;

    u = v;
    if(v->lchild != NULL && v->rchild != NULL){
    u = v->rchild;
    while(u->lchild != NULL){
        u = u->lchild;
    }
    tmp = u->key;
    u->key = v->key;
    v->key = tmp;
    }

    //u is the node to free.
    if(u->lchild != NULL)
    c = u->lchild;
    else 
    c = u->rchild;

    p = u->parent;
    if(p != NULL){
    //remove u from rb_tree.
    if(p->lchild == u)
        p->lchild = c;
    else
        p->rchild = c;
    }
    else{
    //u is root.
    root = c;
    free((void*)u);
    return;
    }

    //u is not root and u is RED, this will not unbalance.
    if(u->colour == RED){
    free((void*)u);
    return;
    }

    free((void*)u);
    u = c;

    //u is the first node to balance.
    while(u != root){
    if(u != NULL && u->colour == RED){
        //if u is RED, change it to BLACK can finsh.
        u->colour = BLACK;
        return;
    }

    if(u == p->lchild)
        b = p->rchild;
    else 
        b = p->lchild;

    printf("%d\n", b->key);

    //b is borther of u. b can't be null, or the rb_tree is must not balance.
    if(b->colour == BLACK){
        //If b's son is RED, rotate the node.
        if(b->lchild != NULL && b->lchild->colour == RED){
        if(u == p->lchild){
            b = clock_wise(b);
            b->colour = BLACK;
            b->rchild->colour = RED;

            p = counter_clock_wise(p);
            p->colour = p->lchild->colour;
            p->lchild->colour = BLACK;
            p->rchild->colour = BLACK;
        }
        else{
            p = clock_wise(p);
            p->colour = p->rchild->colour;
            p->rchild->colour = BLACK;
            p->lchild->colour = BLACK;
        }

        return;
        }
        else if(b->rchild != NULL && b->rchild->colour == RED){
        if(u == p->rchild){
            b = counter_clock_wise(b);
            b->colour = BLACK;
            b->lchild->colour = RED;

            p = clock_wise(p);
            p->colour = p->rchild->colour;
            p->rchild->colour = BLACK;
            p->lchild->colour = BLACK;
        }
        else{
            p = counter_clock_wise(p);
            p->colour = p->lchild->colour;
            p->lchild->colour = BLACK;
            p->rchild->colour = BLACK;
        }        
        return;
        }
        else{//if b's sons are BLACK, make b RED and move up u.
        b->colour = RED;
        u = p;
        p = u->parent;
        continue;
        }
    }
    else{
        if(u == p->lchild){
        p = counter_clock_wise(p);
        p->colour = BLACK;
        p->lchild->colour = RED;
        p = p->lchild;
        }
        else{
        p = clock_wise(p);
        p->colour = BLACK;
        p->rchild->colour = RED;
        p = p->rchild;
        }
    }
    }
    root->colour = BLACK;
}

int main(){
    int i;
    root = NULL;
       
    rb_insert(3);
    rb_insert(2);
    rb_insert(5);
    rb_insert(8);
    rb_insert(4);
    rb_insert(7);
    rb_insert(6);
    rb_insert(9);
//    rb_delete(2);
//    rb_delete(5);
//    rb_delete(8);
    
    show_rb_tree(root);
    printf("\n");
    return 0;
}

自己整理的代码

#include<stdio.h>
#include<stdlib.h>
typedef struct node{
    int key;
    struct node *left,*right,*parent;
    int color;
}TreeNode;

const int BLACK = 1;
const int RED = 0;
TreeNode *root = NULL;

//函数声明 
TreeNode* newNode(TreeNode *parent,int key);

//创建新的节点 
TreeNode* newNode(TreeNode *parent,int key){
    TreeNode *temp = (TreeNode *)malloc(sizeof(TreeNode));
    temp->color = RED;
    temp->left = temp->right = NULL;
    temp->parent = parent;
    temp->key = key;
    return temp;
} 

//子节点在右 
TreeNode* isRight(TreeNode *node){
    if(node == NULL || node->right ==NULL){
        return NULL;
    }
    TreeNode *p1 = node,*p2 = node->right,*p3 = node->right->left;
    if(p1->parent!=NULL){
        if(p1->parent->left = p1){
            p1->parent->left = p2;
        }else{
            p1->parent->right = p2;
        }
    }else if(p1 == root){
        root = p2;
    }
    
    p2->parent = p1->parent;
    p1->parent = p2;
    p2->left = p1;
    p1->right = p3;
    if(p3!=NULL){
        p3->parent = p1;
    }
    return p2;
}

//子节点在左 
TreeNode* isLeft(TreeNode *node){
    if(node == NULL || node->left ==NULL){
        return NULL;
    }
    TreeNode *p1 = node,*p2 = node->left,*p3 = node->left->right;
    if(p1->parent!=NULL){
        if(p1->parent->left == p1){
            p1->parent->left = p2;
        }else{
            p1->parent->right = p2;
        }
    }else if(p1 == root){
        root = p2;
    }
    
    p2->parent = p1->parent;
    p1->parent = p2;
    p2->right = p1;
    p1->left = p3;
    if(p3!=NULL){
        p3->parent = p1;
    }
    return p2;    
} 

void insertNode(int key){
    TreeNode *p = root,*q = NULL;
    if(root == NULL){
        //创建新节点 
        root = newNode(NULL,key);
        root->color = BLACK; 
        return;
    }
    while(p!=NULL){
        q = p;
        if(key<p->key){
            p = p->left;
        }else if(key > p->key){
            p = p->right;
        }else{
            return;
        }
    }
    
    if(key<q->key){
        q->left = newNode(q,key);
    }else{
        q->right = newNode(q,key);
    }
    
    while(q!=NULL && q->color == RED){
        p = q->parent;
        if(p->left == q){
            if(q->right!=NULL&&q->right->color ==RED)
                isRight(q);
            q = isLeft(p);
            q->left->color = BLACK;    
        }else{
            if(q->left!=NULL&&q->left->color == RED)
                isLeft(q);
            q = isRight(p);
            q->right->color = BLACK;
        }
        q = q->parent;
    }    
    root->color = BLACK; 
}


//输出 
void print(TreeNode *root){
    if(root==NULL)
        return;
    print(root->left);
    printf("color:%3d root:%8d parent:%8d  key:%d\n",root->color,root,root->parent,root->key);
    print(root->right);
    
}

int main(void){
    //插入
    root =NULL;
    insertNode(3);
    insertNode(2);
    insertNode(5);
    insertNode(8);
    insertNode(4);
    insertNode(7);
    insertNode(6);
    insertNode(6);
    print(root);
    return 0;
}

 

参考:https://www.jianshu.com/p/e136ec79235c

posted @ 2019-09-30 15:05  byebai95  阅读(426)  评论(0编辑  收藏  举报