数据结构——红黑树

一、红黑树的特性

1.每个节点都是红的或者黑的;

2.根节点是黑色;

3.每个叶子节点都是黑色(度为0的节点为叶子节点);

4.如果一个节点是红色,则他的两个子节点为黑色;

5.对于每个节点,从该节点到其子孙节点的所有路径上包含相同数目的黑色节点。

二、红黑树的使用场景

红黑树主要是通过其<key, value>特性及其中序遍历的特性来针对不同场景进行使用的。以下是红黑树的几个使用场景(先大概总结,待后续把每个点深入学习以后进行分析总结):

1.C++标准库中的STL map容器内部使用了红黑树的数据结构,对红黑树进行了封装实现;

2.nginx定时器timer

3.Linux进程调度cfs

4.Linux内存管理

5.epoll事件管理

三、红黑树的实现

1.红黑树及其节点定义:

#define RED 0
#define BLACK 1

typedef int KET_TYPE;

typedef struct _rb_tree_node
{
    unsigned char color;
    struct _rb_tree_node* left;
    struct _rb_tree_node* right;
    struct _rb_tree_node* parent;
    /* data */

    KET_TYPE key;
    void* value;
}rbtree_node;


typedef struct _rbtree
{
    /* data */
    _rb_tree_node *root;
    _rb_tree_node *nil; //NULL
}rbtree;

2.红黑树节点的左旋:

void left_rotate(rbtree* T, rbtree_node *x)
{
    //参数判断
    if (x == T->nil)
        return;
    
    rbtree_node *y = x->right;

    //x的右节点指向y的左节点,y的左节点如果不为空,则其父节点指向x
    x->right = y->left;
    if (y->left != T->nil)
    {
        y->left->parent = x;
    }

    //x的父节点指向y
    y->parent = x->parent;
    if (x->parent == T->nil)
    {
        T->root = y;
    }
    else if (x->parent->left == x)
    {
        x->parent->left = y;
    }
    else if (x->parent->right == x)
    {
        x->parent->right = y;
    }

    //y的左节点指向x
    y->left = x;
    x->parent = y;

}

3.红黑树节点的右旋:

void right_rotate(rbtree* T, rbtree_node *y)
{
    //参数判断
    if (y == T->nil)
        return;
    
    rbtree_node *x = y->left;

    //y的左节点指向x的右节点,x的右节点如果不为空,则其父节点指向y
    y->left = x->right;
    if (x->right != T->nil)
    {
        x->right->parent = y;
    }

    //y的父节点指向x
    x->parent = y->parent;
    if (y->parent == T->nil)
    {
        T->root = x;
    }
    else if (y->parent->right == y)
    {
        y->parent->right = x;
    }
    else if (y->parent->left == y)
    {
        y->parent->left = x;
    }

    //x的右节点指向y
    x->right = y;
    y->parent = x;
}

4.红黑树节点的插入:

void rbtree_insert(rbtree* T, rbtree_node* z)
{
    rbtree_node* y = T->nil;
    rbtree_node* x = T->root;


    while (x != T->nil)
    {
        y = x;
        if (z->key < x->key)
        {
            x = x->left;
        }
        else if (z->key > x->key)
        {
            x = x->right;
        }
        else 
        {
            //相等的清空根据实际业务,可做处理或不做处理
        }
    }

    //遍历结束后,此时已确定要插入节点的位置
    z->parent = y;
    if (y == T->nil)
    {
        T->root = z;
    }
    else if (z->key > y->key)
    {
        y->left = z;
    }
    else if (z->key < y->key)
    {
        y->right = z;
    }

    //默认新插入节点的颜色为红色
    z->color = RED;
    z->left = T->nil;
    z->right = T->nil;
}

5.红黑树节点的平衡修复:

默认当前T为红黑树,插入的节点默认为红色,分情况讨论:

1.如果当前节点的父节点为祖父节点的左节点:

        ①如果当前叔父节点为红色;

        ②如果当前叔父节点为黑色;

2.如果当前节点的父节点为祖父节点的右节点(待完善):

void rbtree_insert_fixup(rbtree* T, rbtree_node* z)
{
    rbtree_node* y = T->nil;

    while (z->color == RED)
    {
        if (z->parent == z->parent->parent->left)
        {
            y = z->parent->parent->right;
            //如果叔父节点是红色
            if (y->color == RED)
            {
                //父节点变红,祖父节点变黑,叔父节点变红
                z->parent->color = RED;
                z->parent->parent->color = BLACK;
                y->color = RED;
                //祖父节点指向当前节点
                z = z->parent->parent;
            }
            else
            {
                if (z = z->parent->right)
                {
                    z = z->parent;
                    left_rotate(T, z);
                }
                z->parent->color = BLACK;
                z->parent->parent->color = RED;
                right_rotate(T, z->parent->parent);
            }
        }
        else if (z->parent == z->parent->parent->right)
        {
            //待完善
        }
    }
}

6.红黑树节点的删除(待完善):

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值