手撕红黑树

一. 红黑树的定义

红黑树(Red Black Tree)是一种自平衡二叉查找树,红黑树插入,删除,查找都是O(logn)的时间复杂度。

二. 红黑树的性质

  1. 每个节点或红或黑

  1. 根结点为黑

  1. 每个叶子节点为黑

  1. 若一个节点为红,则它的孩子必须为黑

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

第五条性质尤为重要,第五条性质表明红黑树不同于AVL树。红黑树平衡的是黑高,而AVL树平衡的是子树高度。

三. 红黑树的用途

  1. map, set底层采用红黑树进行存储

  1. 定时器

  1. Linux进程调度(CFS(Completely FairScheduler))

  1. Epoll的实现,内核会在内存中开辟一个空间存放epoll的红黑树,并将每个epollfd加入树中进行管理

四. 红黑树的插入

    • 红黑树节点旋转

红黑树在插入和删除过程中,由于破坏黑高,需要进行调整,而调整的过程中就会涉及到节点旋转的操作。可以说节点旋转是红黑树中非常重要的操作之一。

// 左旋操作
void RBtree::leftRotate(RBtree_node *x)
{
    RBtree_node *y = x->right;

    x->right = y->left;
    if (y->left != nil)
    {
        y->left->parent = x;
    }

    y->parent = x->parent;
    if (x->parent == nil)
    {
        root = y;
    }
    else if (x->parent->left == x)
    {
        x->parent->left = y;
    }
    else
    {
        x->parent->right = y;
    }

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

// 右旋操作
void RBtree::rightRotate(RBtree_node *y)
{
    RBtree_node *x = y->left;

    y->left = x->right;
    if (x->right != nil)
    {
        x->right->parent = y;
    }

    x->parent = y->parent;
    if (y->parent == nil)
    {
        root = x;
    }
    else if (y->parent->left == y)
    {
        y->parent->left = x;
    }
    else
    {
        y->parent->right = x;
    }

    x->right = y;
    y->parent = x;
}
    • 红黑树插入节点

红黑树插入节点类似于二叉搜索树的插入,都是要先在树上寻找到合适的插入位置,再进行节点插入(插入叶子节点),只不过红黑树在插入结束之后要进行节点调整。所以在红黑树中插入节点有以下几个步骤:1. 寻找插入位置

2. 创建新节点

3. 插入,调整

// 节点插入
void RBtree::insert(KEY_TYPE key, VALUE_TYPE value)
{
    RBtree_node *pre = nil;
    RBtree_node *cur = root;

    // 寻找插入位置
    while (cur != nil)
    {
        pre = cur;
        if (key < cur->key)
        {
            cur = cur->left;
        }
        else if (key > cur->key)
        {
            cur = cur->right;
        }
        else
        {
            return;
        }
    }
    
    // 创建新节点
    RBtree_node *node = new RBtree_node(RED);
    node->key = key;
    node->value = value;
    node->left = nil;
    node->right = nil;
    node->parent = pre;

    // 新节点插入红黑树
    if (pre == nil)
    {
        root = node;
    }
    else
    {
        if (key < pre->key)
        {
            pre->left = node;
        }
        else
        {
            pre->right = node;
        }
    }
    
    // 插入调整
    insert_fixup(node);
}
    • 红黑树插入调整

若插入节点时,将插入节点颜色设置为黑色,插入红黑树中必定会将黑高平衡破坏,这样每次插入节点都会带来红黑树的调整。

若插入节点时,将插入节点颜色设置为红色,插入红黑树一定不会破坏黑高,但是会破坏性质4, 此时若插入节点父节点为红色节点,则需要进行调整。现在以插入节点的父节点为祖父节点的左孩子为例:

情况一:叔父节点为红色

此时将父亲节点染为黑色,叔父节点染为黑色,将祖父节点染为红色。之后从祖父节点开始继续向上迭代检查。

情况2:叔父节点为黑色,插入节点为父亲节点右孩子

此时将以插入节点父节点为轴心进行左旋,此时转化为情况3

情况3. 叔父节点为黑色,插入节点为父亲节点左孩子。

此时将父节点染为黑色,将祖父节点染为红色,以祖父节点为轴型进行右旋。

// 插入修复
void RBtree::insert_fixup(RBtree_node *x)
{
    // 迭代检查父节点是否为红色,若为红色继续调整
    while (x->parent->color == RED)
    {
        // 当父节点为祖父节点左孩子
        if (x->parent == x->parent->parent->left)
        {
            // 叔父节点
            RBtree_node *y = x->parent->parent->right;

            // 情况1
            if (y->color == RED)
            {
                x->parent->color = BLACK;
                y->color = BLACK;
                x->parent->parent->color = RED;

                x = x->parent->parent;
            }
            else
            {
                // 情况2
                if (x == x->parent->right)
                {
                    x = x->parent;
                    leftRotate(x);
                }
                // 情况3
                x->parent->color = BLACK;
                x->parent->parent->color = RED;
                rightRotate(x->parent->parent);
            }
        }
        else
        {
            RBtree_node *y = x->parent->parent->left;
            if (y->color == RED)
            {
                x->parent->color = BLACK;
                y->color = BLACK;
                x->parent->parent->color = RED;

                x = x->parent->parent;
            }
            else
            {
                if (x == x->parent->left)
                {
                    x = x->parent;
                    rightRotate(x);
                }
                x->parent->color = BLACK;
                x->parent->parent->color = RED;
                leftRotate(x->parent->parent);
            }
        }
    }
    // 保证根节点一直为黑色
    root->color = BLACK;
}

五.红黑树的删除

    • 寻找一个子树上的最小节点和最大节点

RBtree_node *RBtree::mini_node(RBtree_node *x)
{
    while (x->left != nil)
    {
        x = x->left;
    }
    return x;
}

RBtree_node *RBtree::max_node(RBtree_node *x)
{
    while (x->right != nil)
    {
        x = x->right;
    }
    return x;
}
    • 寻找一个节点的后继节点

当寻找一个节点的后继节点时,存在两种情况:

情况1:该节点存在右子树,此时后继节点为右子树的最小值节点

情况2:该节点不存在右子树,此时后继节点为父节点不断迭代向上搜索,直到当前节点为父节点的左孩子节点,此时父节点为后继节点,例如13节点的后继节点为15

RBtree_node *RBtree::successor(RBtree_node *node)
{
    // 情况1
    if (node->right != nil)
    {
        return mini_node(node->right);
    }
    // 情况2
    else
    {
        RBtree_node *pre = node->parent;
        RBtree_node *cur = node;
        while (pre != nil && cur == pre->right)
        {
            cur = pre;
            pre = pre->parent;
        }
        return pre;
    }
}
    • 红黑树删除节点

红黑树删除时分为如下几种情况:

    • 该删除节点不存在左右子树

若遇到该情况,则直接删除节点

    • 删除节点存在右左子树或右子树

若遇到该情况,将该节点直接删除并且将左子树或右子树代替被删除节点位置。

    • 删除节点存在左子树且存在右子树

若遇到该情况,则寻找插入节点z的直接后继节点y,将y节点替换z节点值,最后删除y节点,y的右孩子连接y的父节点。

// 删除节点
void RBtree::erase(KEY_TYPE key)
{
    // y节点的孩子节点
    RBtree_node *x = nil;
    // 真正删除节点
    RBtree_node *y = nil;
    // 被覆盖节点
    RBtree_node *z = search_node(key);
    if (z == nil)
    {
        return;
    }
    // 情况1, 2
    if (z->left == nil || z->right == nil)
    {
        y = z;
    }
    else
    {
        // 情况3
        y = successor(z);
    }
    
    // x为y的左或右子树
    if (y->left != nil)
    {
        x = y->left;
    }
    if (y->right != nil)
    {
        x = y->right;
    }
    
    // 将x代替y的位置
    x->parent = y->parent;
    if (y->parent == nil)
    {
        root = x;
    }
    else if (y == y->parent->left)
    {
        y->parent->left = x;
    }
    else
    {
        y->parent->right = x;
    }
    
    // 将y值覆盖z值
    if (y != z)
    {
        z->key = y->key;
        z->value = y->value;
    }

    // 若删除节点y为黑色节点,则破坏黑高,进行调整
    if (y->color == BLACK)
    {
        erase_fixup(x);
    }
}
    • 红黑树删除节点调整

接上文,已知条件,y节点为黑色

调整节点为y节点的孩子节点x,若x节点颜色为红色,则直接将x节点染为黑色即可,此时不会破坏黑高。

调整节点为y节点的孩子节点x,若x节点颜色为黑色,此时破坏黑高,需要进行调整。

此时分为四种情况(以x节点为y节点左孩子节点为例)

情况1. 兄弟节点为红色:

解决方法:将兄弟节点染为黑色,将父亲节点染为红色,进行左旋。

情况2:兄弟节点为黑色,且兄弟节点的左孩子右孩子节点都为黑色节点

解决方法:将兄弟节点染为红色

情况3. 兄弟节点为黑色,兄弟节点的左孩子为红色,右孩子为黑色

解决方法:此时将兄弟节点左孩子染为黑色,兄弟节点染为黑色,以兄弟节点为轴心进行右旋,转换为情况4

情况4.兄弟节点右孩子为红色

解决方法:将x父节点右孩子染为父节点颜色,x父节点染为黑色,兄弟节点右孩子染为黑色,以x父节点为轴心进行左旋,左旋结束之后结束循环。

void RBtree::erase_fixup(RBtree_node *x)
{
    while (x != root && x->color == BLACK)
    {
        if (x == x->parent->left)
        {
            RBtree_node *y = x->parent->right;
            // 情况1
            if (y->color == RED)
            {
                y->color = BLACK;
                x->parent->color = RED;
                leftRotate(x->parent);

                y = x->parent->right;
            }
            
            // 情况2
            if (y->left->color == BLACK && y->right->color == BLACK)
            {
                y->color = RED;
                x = x->parent;
            }
            else
            {
                // 情况3
                if (y->right->color == BLACK)
                {
                    y->color = RED;
                    y->left->color = BLACK;
                    rightRotate(y);

                    y = x->parent->right;
                }
                // 情况4
                y->color = x->parent->color;
                x->parent->color = BLACK;
                y->right->color = BLACK;
                leftRotate(x->parent);

                x = root;
            }
        }
        else
        {
            RBtree_node *y = x->parent->left;
            if (y->color == RED)
            {
                y->color = BLACK;
                x->parent->color = RED;
                rightRotate(x->parent);

                y = x->parent->left;
            }

            if (y->left->color == BLACK && y->right->color == BLACK)
            {
                y->color = RED;
                x = x->parent;
            }
            else
            {
                if (y->left->color == BLACK)
                {
                    y->color = RED;
                    y->right->color = BLACK;
                    leftRotate(y);

                    y = x->parent->left;
                }

                y->color = x->parent->color;
                x->parent->color = BLACK;
                y->left->color = BLACK;
                rightRotate(x->parent);

                x = root;
            }
        }
    }
    x->color = BLACK;
}

六. 完整代码

#ifndef RBTREE_H
#define RBTREE_H

typedef enum _COLOR
{
    BLACK = 0,
    RED = 1
} COLOR;

using KEY_TYPE = int;
using VALUE_TYPE = int;

class RBtree_node
{
public:
    KEY_TYPE key;
    VALUE_TYPE value;
    COLOR color;
    class RBtree_node *left;
    class RBtree_node *right;
    class RBtree_node *parent;

    RBtree_node(COLOR c)
        : color(c),
          key(-1),
          value(-1),
          parent(nullptr),
          left(nullptr),
          right(nullptr)
    {
    }
};

class RBtree
{
public:
    RBtree()
    {
        nil = new RBtree_node(BLACK);
        root = nil;
    }

    // 插入
    void insert(KEY_TYPE key, VALUE_TYPE value);

    // 删除
    void erase(KEY_TYPE key);

    // 寻找某个Key值是否存在
    bool find(KEY_TYPE key);

    // 层序遍历打印红黑树
    void print_level();

    // 中序遍历红黑树
    void print_middle();

private:
    // 左旋
    void leftRotate(RBtree_node *x);

    // 右旋
    void rightRotate(RBtree_node *y);

    // 插入修复
    void insert_fixup(RBtree_node *x);

    // 删除修复
    void erase_fixup(RBtree_node *x);

    // 查询某个key节点
    RBtree_node *search_node(KEY_TYPE key);

    // 寻找某个节点后继节点
    RBtree_node *successor(RBtree_node *node);

    // 寻找某颗子树上最小节点
    RBtree_node *mini_node(RBtree_node *x);

    // 寻找某颗子树上最大节点
    RBtree_node *max_node(RBtree_node *x);

private:
    RBtree_node *root;
    RBtree_node *nil;
};

#endif // RBTREE_H
#include "rbtree.h"
#include <iostream>
#include <queue>
#include <stack>

using namespace std;

void RBtree::insert(KEY_TYPE key, VALUE_TYPE value)
{
    RBtree_node *pre = nil;
    RBtree_node *cur = root;
    while (cur != nil)
    {
        pre = cur;
        if (key < cur->key)
        {
            cur = cur->left;
        }
        else if (key > cur->key)
        {
            cur = cur->right;
        }
        else
        {
            return;
        }
    }

    RBtree_node *node = new RBtree_node(RED);
    node->key = key;
    node->value = value;
    node->left = nil;
    node->right = nil;
    node->parent = pre;

    if (pre == nil)
    {
        root = node;
    }
    else
    {
        if (key < pre->key)
        {
            pre->left = node;
        }
        else
        {
            pre->right = node;
        }
    }
    insert_fixup(node);
}

void RBtree::erase(KEY_TYPE key)
{
    RBtree_node *x = nil;
    RBtree_node *y = nil;
    RBtree_node *z = search_node(key);
    if (z == nil)
    {
        return;
    }
    if (z->left == nil || z->right == nil)
    {
        y = z;
    }
    else
    {
        y = successor(z);
    }

    if (y->left != nil)
    {
        x = y->left;
    }
    if (y->right != nil)
    {
        x = y->right;
    }

    x->parent = y->parent;
    if (y->parent == nil)
    {
        root = x;
    }
    else if (y == y->parent->left)
    {
        y->parent->left = x;
    }
    else
    {
        y->parent->right = x;
    }

    if (y != z)
    {
        z->key = y->key;
        z->value = y->value;
    }

    if (y->color == BLACK)
    {
        erase_fixup(x);
    }
}

bool RBtree::find(KEY_TYPE key)
{
    RBtree_node *node = search_node(key);
    if (node != nil)
    {
        return true;
    }
    else
    {
        return false;
    }
}

void RBtree::print_level()
{
    if (root == nil)
    {
        return;
    }
    queue<RBtree_node *> q;
    RBtree_node *cur_end = root;
    RBtree_node *next_end = nullptr;
    q.push(root);
    int level = 1;

    while (!q.empty())
    {
        RBtree_node *node = q.front();
        q.pop();

        if (node != nil)
        {
            cout << "key:" << node->key << " value:" << node->value
                 << " color:" << (node->color == RED ? "RED" : "BLACK")
                 << " level:" << level << endl;
        }
        else
        {
            cout << "nil node"
                 << " level:" << level << endl;
        }

        if (node->left)
        {
            q.push(node->left);
            next_end = node->left;
        }
        if (node->right)
        {
            q.push(node->right);
            next_end = node->right;
        }

        if (node == cur_end)
        {
            if (cur_end != next_end)
            {
                level++;
            }
            cur_end = next_end;
        }
    }
}

void RBtree::print_middle()
{
    stack<RBtree_node *> s;
    RBtree_node *cur = root;
    while (cur != nil || !s.empty())
    {
        if (cur != nil)
        {
            s.push(cur);
            cur = cur->left;
        }
        else
        {
            RBtree_node *node = s.top();
            s.pop();
            cout << "key = " << node->key << "value = " << node->value << endl;
            cur = node->right;
        }
    }
}

void RBtree::leftRotate(RBtree_node *x)
{
    RBtree_node *y = x->right;

    x->right = y->left;
    if (y->left != nil)
    {
        y->left->parent = x;
    }

    y->parent = x->parent;
    if (x->parent == nil)
    {
        root = y;
    }
    else if (x->parent->left == x)
    {
        x->parent->left = y;
    }
    else
    {
        x->parent->right = y;
    }

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

void RBtree::rightRotate(RBtree_node *y)
{
    RBtree_node *x = y->left;

    y->left = x->right;
    if (x->right != nil)
    {
        x->right->parent = y;
    }

    x->parent = y->parent;
    if (y->parent == nil)
    {
        root = x;
    }
    else if (y->parent->left == y)
    {
        y->parent->left = x;
    }
    else
    {
        y->parent->right = x;
    }

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

void RBtree::insert_fixup(RBtree_node *x)
{
    while (x->parent->color == RED)
    {
        if (x->parent == x->parent->parent->left)
        {
            RBtree_node *y = x->parent->parent->right;
            if (y->color == RED)
            {
                x->parent->color = BLACK;
                y->color = BLACK;
                x->parent->parent->color = RED;

                x = x->parent->parent;
            }
            else
            {
                if (x == x->parent->right)
                {
                    x = x->parent;
                    leftRotate(x);
                }
                x->parent->color = BLACK;
                x->parent->parent->color = RED;
                rightRotate(x->parent->parent);
            }
        }
        else
        {
            RBtree_node *y = x->parent->parent->left;
            if (y->color == RED)
            {
                x->parent->color = BLACK;
                y->color = BLACK;
                x->parent->parent->color = RED;

                x = x->parent->parent;
            }
            else
            {
                if (x == x->parent->left)
                {
                    x = x->parent;
                    rightRotate(x);
                }
                x->parent->color = BLACK;
                x->parent->parent->color = RED;
                leftRotate(x->parent->parent);
            }
        }
    }
    root->color = BLACK;
}

void RBtree::erase_fixup(RBtree_node *x)
{
    while (x != root && x->color == BLACK)
    {
        if (x == x->parent->left)
        {
            RBtree_node *y = x->parent->right;
            if (y->color == RED)
            {
                y->color = BLACK;
                x->parent->color = RED;
                leftRotate(x->parent);

                y = x->parent->right;
            }

            if (y->left->color == BLACK && y->right->color == BLACK)
            {
                y->color = RED;
                x = x->parent;
            }
            else
            {
                if (y->right->color == BLACK)
                {
                    y->color = RED;
                    y->left->color = BLACK;
                    rightRotate(y);

                    y = x->parent->right;
                }

                y->color = x->parent->color;
                x->parent->color = BLACK;
                y->right->color = BLACK;
                leftRotate(x->parent);

                x = root;
            }
        }
        else
        {
            RBtree_node *y = x->parent->left;
            if (y->color == RED)
            {
                y->color = BLACK;
                x->parent->color = RED;
                rightRotate(x->parent);

                y = x->parent->left;
            }

            if (y->left->color == BLACK && y->right->color == BLACK)
            {
                y->color = RED;
                x = x->parent;
            }
            else
            {
                if (y->left->color == BLACK)
                {
                    y->color = RED;
                    y->right->color = BLACK;
                    leftRotate(y);

                    y = x->parent->left;
                }

                y->color = x->parent->color;
                x->parent->color = BLACK;
                y->left->color = BLACK;
                rightRotate(x->parent);

                x = root;
            }
        }
    }
    x->color = BLACK;
}

RBtree_node *RBtree::search_node(KEY_TYPE key)
{
    RBtree_node *node = root;
    while (node != nil)
    {
        if (key < node->key)
        {
            node = node->left;
        }
        else if (key > node->key)
        {
            node = node->right;
        }
        else
        {
            return node;
        }
    }
    return nil;
}

RBtree_node *RBtree::successor(RBtree_node *node)
{
    if (node->right != nil)
    {
        return mini_node(node->right);
    }
    else
    {
        RBtree_node *pre = node->parent;
        RBtree_node *cur = node;
        while (pre != nil && cur == pre->right)
        {
            cur = pre;
            pre = pre->parent;
        }
        return pre;
    }
}

RBtree_node *RBtree::mini_node(RBtree_node *x)
{
    while (x->left != nil)
    {
        x = x->left;
    }
    return x;
}

RBtree_node *RBtree::max_node(RBtree_node *x)
{
    while (x->right != nil)
    {
        x = x->right;
    }
    return x;
}

测试代码:

#include "rbtree.h"
#include <iostream>

int main()
{
    RBtree tree;
    for (int i = 0; i < 10; i++)
    {
        tree.insert(i, i);
    }
    tree.print_level();
    std::cout << "after erase" << std::endl;
    tree.erase(3);
    tree.print_level();
    tree.print_middle();
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值