添加链接描述手写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;
}