zoukankan      html  css  js  c++  java
  • 深入学习二叉树(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)
    ", node->key, node->colour);
    //    if(node->lchild != NULL){
    //    printf("[-1]
    ");
    //    show_rb_tree(node->lchild);
    //    }
    //    if(node->rchild != NULL){
    //    printf("[1]
    ");
    //    show_rb_tree(node->rchild);
    //    }
    //    printf("[0]
    ");
        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
    ", 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("
    ");
        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
    ",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

  • 相关阅读:
    Android变化如何破解几场金
    mysql 在创建批处理脚本日志表信息
    近期感悟要多说多想多做
    Spring使用小结2
    structs2使用小结2
    2013第50周五打包
    2013第50周四开发记
    jquery使用总结
    2013第50周三开发记
    eclipse编辑工具小结
  • 原文地址:https://www.cnblogs.com/baizhuang/p/11612819.html
Copyright © 2011-2022 走看看