红黑树实现简单map

3 篇文章 0 订阅

添加链接描述手写C++版本的红黑树, 实现map操作(还未完成0.0)

#include <iostream>
#include <cassert>
using namespace std;

enum class Color
{
    RED,
    BLACK
};

enum class ChildFlag
{
    NotDefine,
    LEFT,
    RIGHT
};

template <class Key_type, class Value_type>
class rb_node
{
public:
    rb_node() : lchild(nullptr), rchild(nullptr), parent(nullptr), color(Color::RED) {}
    rb_node(Key_type a, Value_type b) : lchild(nullptr), rchild(nullptr), parent(nullptr), color(Color::RED), m_key(a), m_value(b) {}
    rb_node(const rb_node &tmp) = delete; // 不支持拷贝构造
    rb_node(rb_node &&tmp);
    rb_node<Key_type, Value_type> *lchild;
    rb_node<Key_type, Value_type> *rchild;
    rb_node<Key_type, Value_type> *parent;
    int color;

    Key_type m_key;
    Value_type m_value;

public:
    bool left_rotary();
    bool right_rotary();
    rb_node<Key_type, Value_type> *getUncle();
    rb_node<Key_type, Value_type> *getGradePa();
};

template <class Key_type, class Value_type>
class rb_tree
{
public:
    rb_tree() : root(nullptr), lead(nullptr) {}
    rb_tree(const rb_tree &tmp) = delete; // 不支持拷贝构造
    rb_tree(rb_tree &&tmp);
    rb_node<Key_type, Value_type> *root;
    rb_node<Key_type, Value_type> *leaf; // 同一的黑色叶子节点
    int num;                             // 节点总数

public:
    void insert(Key_type, Value_type);
    void erase(Key_type); // 待完成
    void init();
    void clear();
    void size();
};

template <class Key_type, class Value_type>
bool rb_node<Key_type, Value_type>::left_rotary()
{
    rb_node<Key_type, Value_type> *pa = this->m_parent;
    if (pa->lchild == this)
    {
        // pa下面的顶点换了
        pa->lchild = this->rchild;
        this->rchild->parent = pa;

        // 我的右孩子指向当前顶点的左孩子
        this->rchild = pa->lchild->lchild;
        pa->lchild->lchild->parent = this;

        // pa下面顶点的左孩子换成了我
        pa->lchild->lchild = this;
        this->parent = pa->lchild;
    }
    else
    {
        // pa下面的顶点换了
        pa->rchild = this->rchild;
        this->rchild->parent = pa;

        // 我的右孩子指向当前顶点的左孩子
        this->rchild = pa->rchild->lchild;
        pa->rchild->lchild->parent = this;

        // pa下面顶点的左孩子换成了我
        pa->rchild->lchild = this;
        this->parent = pa->rchild;
    }
}

template <class Key_type, class Value_type>
bool rb_node<Key_type, Value_type>::right_rotary()
{
    rb_node<Key_type, Value_type> *pa = this->m_parent;
    if (pa->lchild == this)
    {
        // pa下面的顶点换了
        pa->lchild = this->rchild;
        this->rchild->parent = pa;

        // 我的左孩子指向当前顶点的右孩子
        this->lchild = pa->lchild->rchild;
        pa->lchild->rchild->parent = this;

        // pa下面顶点的左孩子换成了我
        pa->lchild->rchild = this;
        this->parent = pa->rchild;
    }
    else
    {
        // pa下面的顶点换了
        pa->rchild = this->rchild;
        this->rchild->parent = pa;

        // 我的左孩子指向当前顶点的右孩子
        this->lchild = pa->rchild->rchild;
        pa->rchild->rchild->parent = this;

        // pa下面顶点的左孩子换成了我
        pa->rchild->rchild = this;
        this->parent = pa->rchild;
    }
}

template <class Key_type, class Value_type>
rb_node<Key_type, Value_type> *rb_node<Key_type, Value_type>::getGradePa()
{
    return this->parent->parent;
}

template <class Key_type, class Value_type>
rb_node<Key_type, Value_type> *rb_node<Key_type, Value_type>::getUncle()
{
    rb_node<Key_type, Value_type> *pa = this->getGradePa();
    if (pa->lchild == this->parent)
    {
        return pa->rchild;
    }
    else
    {
        return pa->lchild;
    }
}

template <class Key_type, class Value_type>
void rb_tree<Key_type, Value_type>::insert(Key_type key, Value_type value)
{
    // 由于每次插入之前都是一颗完整的红黑树
    // 我们每次都插入到最下面, 然后置为红色(这里不置为黑色是因为会影响到黑高, 让红黑树的性质维持更难处理)

    // 首先当红黑树是空树的时候, 插入节点, 置为黑色
    rb_node<Key_type, Value_type> *cur_node = new rb_node<Key_type, Value_type>(key, value);
    if (this->num == 0)
    {
        this->root = cur_node;
        cur_node->color = Color::BLACK;
        cur_node->lchild = this->leaf;
        cur_node->rchild = this->leaf;
    }
    else
    {
        int flag = ChildFlag::NotDefine;
        rb_node<Key_type, Value_type> *work = this->root;
        rb_node<Key_type, Value_type> *work_pa = work;
        while (work != this->leaf)
        {
            if (work->m_key < cur_node->m_key)
            {
                work_pa = work;
                work = work->rchild;
                flag = ChildFlag::RIGHT;
            }
            else if (work->m_key > cur_node->m_key)
            {
                work_pa = work;
                work = work->lchild;
                flag = ChildFlag::LEFT;
            }
            else
            {
                // 相等的时候 我们就替换value吧
                // 这里如果value重载了移动拷贝, 我们就用上去吧,毕竟写C++不就是想速度快点么(0..0)
                // 这里有点风险, 用move的话  万一有傻逼(绝对不是我自己, Value_type的移动拷贝没有把被移动对象给置空,就GG了)
                work->m_value = move(cur_node->m_value);
                delete cur_node;
            }
        }
        work = work_pa;
        // 找到可以插入的地方了
        if (flag == ChildFlag::LEFT)
        {
            work = work->parent;
            work->lchild = cur_node;
            cur_node->parent = work;
            cur_node->lchild = this->leaf;
            cur_node->rchild = this->leaf;
        }
        else if (flag == ChildFlag::RIGHT)
        {
            work = work->parent;
            work->rchild = cur_node;
            cur_node->parent = work;
            cur_node->lchild = this->leaf;
            cur_node->rchild = this->leaf;
        }
        else
        {
            assert(0);
        }
        // 插入后解决红黑树性质不满足的情况
        // work指针现在成为当前节点的父指针, 当父亲节点也是红色的时候, 此时需要进行调整
        // 这里要递归处理, work指针不停的向上移动
        while (work->color == Color::RED)
        {
            if (work == this->root)
            {
                work->color = Color::BLACK;
            }

            rb_node<Key_type, Value_type> *uncle = cur_node->getUncle();
            rb_node<Key_type, Value_type> *gradePa = cur_node->getGradePa();
            if (uncle->color == Color::RED)
            {
                // 因为爸爸节点是红色的, 所以他一定有祖父节点
                // 最简单的情况
                // 此时爸爸和叔叔都是红色, 就让爸爸和叔叔变成黑色, 将祖父节点变成红色
                work->color = Color::BLACK;
                uncle->color = Color::BLACK;
                // 这里其实可以直接右值引用拿到getGradePa返回值等等, 但是我想全篇都用指针进行操作, 避免auto和&
                work = gradePa;
                continue;
            }
            else
            {
                // 情况1  父亲是祖父的左孩子
                if (work == work->parent->lchild)
                {
                    // 情况1.1 我是父亲左孩子
                    if (cur_node == cur_node->parent->lchild)
                    {
                        // 这个情况就直接以父亲节点进行右旋摆正位置
                        // 然后让父亲变成黑色,祖父变红(相当于把红色往上面挪了一格, 这里正好叔叔节点是黑色的, 我们可以在父节点进行右旋,
                        // 父亲黑色节点就上去了, 而变成红色的祖父就到了右边, 同时减少了操作次数并且让树两边的节点数尽量保持平衡了)
                        work->color = Color::BLACK;
                        gradePa->color = Color::RED;
                        work->right_rotary();
                        break;
                    }
                    // 情况1.2 我是父亲右孩子
                    else
                    {
                        // 以我左旋 这时候情况就变成了1.1的情况了
                        // 然后以父节点右旋
                        cur_node->left_rotary();
                        cur_node->color = Color::BLACK;
                        work->color = Color::RED;
                        cur_node->right_rotary();
                        break;
                    }
                }
                // 情况2  父亲是祖父的右孩子
                else
                {
                    // 情况2.1 我是父亲左孩子
                    if (cur_node == cur_node->parent->lchild)
                    {
                        cur_node->right_rotary();
                        cur_node->color = Color::BLACK;
                        work->color = Color::RED;
                        cur_node->left_rotary();
                        break;
                    }
                    // 情况2.2 我是父亲右孩子
                    else
                    {
                        work->color = Color::BLACK;
                        gradePa->color = Color::RED;
                        work->left_rotary();
                        break;
                    }
                }
            }
        }
    }
}

template <class Key_type, class Value_type>
void rb_tree<Key_type, Value_type>::erase(Key_type key)
{
}

template <class Key_type, class Value_type>
void rb_tree<Key_type, Value_type>::init()
{
    this->leaf = new rb_node<Key_type, Value_type>();
    this->leaf->color = Color::BLACK;
}

template <class Key_type, class Value_type>
void rb_tree<Key_type, Value_type>::clear()
{
}

template <class Key_type, class Value_type>
void rb_tree<Key_type, Value_type>::size()
{
    return this->num;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值