数据结构与算法:1. 随处可见的红黑树

1. 红黑树是什么

  1. 红黑树是一种特定类型的二叉树,用来组织数据的一种结构
  2. 红黑树是一种平衡二叉查找树的变体,左右子树高差有可能大于1,并不是严格意义上的平衡二叉树(AVL)
  3. 在对红黑树查找时,可以采用普通二叉排序树上的查找算法,在查找过程中不需要颜色信息

2. 红黑树用在哪里

  1. hashmap
  2. cfs
  3. epoll
  4. 定时器
  5. nginx

主要用法:

  1. 通过key去查找value
  2. 二叉排序树,是有一个有序的,当作顺序执行

因为key-value是一个强查找的过程,kv结构有下面这几种

  1. rbtree
  2. hash
  3. b/b+tree
  4. 跳表

3. 红黑树性质

  1. 每个结点是红的或者黑的
  2. 根结点是黑的
  3. 每个叶子结点是黑的
  4. 如果一个结点是红的,则它的两个儿子都是黑的
  5. 对每个结点,从该结点到其子孙结点到所有路径上的包含相同数目的黑结点(决定了高度相同)
#define RBTREE_ENTRY(name, type)    \
    struct name {
      
                         \
        struct type *right; \
        struct type *left;  \
        struct type *parent;\
        unsigned char color;        \
    }

typedef struct _rbtree_node{
    
    

    KEY_TYPE key;
    void *value;
#if 1
    struct _rbtree_node *right;
    struct _rbtree_node *left;
    struct _rbtree_node *parent;
    unsigned char color;
#else

    RBTREE_ENTRY(, rb_node) node; // 把红黑树的性质封装一下, 会更灵活

#endif
} rbtree_node;

typedef struct _rbtree {
    
    

    struct _rbtree_node *root;
    struct _rbtree_node *nil;

} rbtree;

4. 旋转

  1. 红黑树性质被破坏的时候,才进行调整
  2. 红黑树最多的旋转次数就是层高
  3. 旋转是为了不影响其他结点,更好的去变色
// 左旋:要一个树, 和一个待旋转的结点
// 1. x指向y的左子树
// 2. y的左子树指向x
// 3. x的parent指向y
// 改变方向, 总共需要改动6个指针
void rbtree_left_rotate(rbtree *T, rbtree_node *x){
    
    
    rbtree_node *y = x->right;
    // 1. x指向y的左子树
    x->right = y->left;
    // 如果不是叶子结点, 才进行修改
    if(y->left != T->nil){
    
    
        y->left->parent = x;
    }
    // 2. y的左子树指向x
    y->parent = x->parent;
    // 需要判断一下x是不是根结点
    if(x->parent == T->nil){
    
    
        T->root = y;
    }else if(x == x->parent->left){
    
    
        x->parent->left = y;
    }else{
    
    
        x->parent->right = y;
    }

    // 3. x的parent指向y
    y->left = x;
    x->parent = y;
}

void rbtree_right_rotate(rbtree *T, rbtree_node *y){
    
    
     rbtree_node *x = y->left;
    // 1. 
    y->left = x->right;
    // 如果不是叶子结点, 才进行修改
    if(x->right != T->nil){
    
    
        x->right->parent = y;
    }
    // 2. 
    x->parent = y->parent;
    // 需要判断一下y是不是根结点
    if(y->parent == T->nil){
    
    
        T->root = x;
    }else if(y == y->parent->right){
    
    
        y->parent->right = x;
    }else{
    
    
        y->parent->left = x;
    }

    x->right = y;
    y->parent = x;
}

5. 颜色

红黑树在插入任何一个结点之前,他已经是一个红黑树

  1. 上红色,这个黑色的高度没有修改
    1. 如果父节点是红色,就需要调整
    2. 如果叔父结点是红色的
    3. 如果叔父结点是黑色的,而且当前结点是左孩子
      1. 这个时候需要右旋,因为左边比较重
      2. 父节点改成黑色,祖父结点改成红色,然后旋转
void rbtree_insert_fixup(rbtree *T, rbtree_node *z){
    
    
    // z->color == RED
    while(z->parent->color == RED){
    
    
        // 不清楚父节点是左子树还是右子树
        if(z->parent == z->parent->parent->left){
    
    
            rbtree_node *y = z->parent->parent->right;
            if(y->color == RED){
    
    
                z->parent->color = BLACK;
                y->color = BLACK;
                z->parent->parent->color = RED;
                z = z->parent->parent; // z在每一次循环回溯的时候,都是红色的
            }else{
    
     // y->color == BLACK
                if(z == z->parent->right){
    
    
                    z = z->parent;
                    rbtree_left_rotate(T, z);
                }
                z->parent->color = BLACK;
                z->parent->parent->color = RED;
                rbtree_right_rotate(T, z->parent->parent);
            }
        }
    }
}

void rbtree_insert(rbtree *T, rbtree_node *z){
    
    
    rbtree_node *x = T->root;
    rbtree_node *y = T->nil;
    while(x != T->nil){
    
    
        y = x;
        if(z->key < x->key){
    
    
            x = x->left;
        }else if(z->key > x->key){
    
    
            x = x->right;
        }else{
    
     // Exist
            return;
        }
    }
    // 如果这个红黑树一个结点都没有
    if(y == T->nil){
    
    
        T->root = z;
    }else{
    
    
        // z 插到 y 的左子树还是右子树 ?
        if(y->key > z->key){
    
    
            y->left = z;
        }else{
    
    
            y->right = z;
        }
    }
    z->parent = y;
    z->left = T->nil;
    z->right = T->nil;
    z->color = RED;
}

推荐一个零声学院免费公开课程,个人觉得老师讲得不错,分享给大家:

Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,立即学习

猜你喜欢

转载自blog.csdn.net/weixin_44839362/article/details/128995382