目录
一、什么是红黑树
1.红黑树是在AVL树的基础上进行改进的一种树,也是一颗二叉搜素树,它并不要求像AVL树一样,严格要求平衡因子的绝对值不大于1,它只要求最长路径不超过最短路径的2倍即可,正如它的名字一样,它不再使用平衡因子,而是用颜色来标记每一个节点,分别是红色和黑色。
2、红黑树的根节点必须是黑色节点
3、红黑树不能有两个连续的红节点,但可以有连续的黑色节点。
4、红黑树的叶子节点必须是黑色,这里的叶子节点说的是NIL。
5、红黑树每条路径的黑色节点数目相等
这里的NIL通常我们认为就是存放nullptr的地方。
二、红黑树的基本框架
基本的成员,这里颜色我们可以使用一个枚举来实现。
enum Colour
{
RED,
BLACK
};
template<class K, class V>
struct RBTreeNode
{
RBTreeNode<K, V>* _left;
RBTreeNode<K, V>* _right;
RBTreeNode<K, V>* _parent;
pair<K, V> _kv;
Colour _col;
RBTreeNode(const pair<K, V>& kv)
:_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_kv(kv)
,_col(RED)
{}
};
template<class K, class V>
struct RBTree
{
typedef RBTreeNode<K, V> Node;
public:
private:
Node* _root = nullptr;
三、红黑树的插入
我们先默认插入的节点的颜色为红色。
首先先像普通的二叉搜索树一样,通过左右比较来找到我们要插入的位置,比要插入的值大,就往左边走,比要插入的值小,就往右边走,和要插入的值一样,就break出来,最后来到空位置,将值插入进去。
bool insert(const pair<K, V>& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
_root->_cor = BLACK;
return true;
}
Node* cur = _root;
Node* parent = nullptr;
//寻找插入的位置
while (cur)
{
if (cur->_kv.first > kv.first)
{
parent = cur;
cur = cur->_left;
}
else if (cur->_kv.first < kv.first)
{
parent = cur;
cur = cur->_right;
}
else
{
return false;
}
}
//插入新节点
cur = new Node(kv);
cur->_parent = parent;
cur->_cor = RED;
//链接cur
if (parent->_kv.first > kv.first)
{
parent->_left = cur;
}
else
{
parent->_right = cur;
}
}
然后再调整我们的颜色就可以了。
这里分为几种情况
首先我们先理解几个定义出来的变量,
cur为我们当前的节点,
parent为我们当前节点的父节点
grandfather为parent节点的父节点
uncle为parent节点的叔叔节点,也就是grandfather节点的左或者右孩子
1.如果parent节点的颜色为黑色,我们就结束
因为我们默认插入的节点为红色,parent节点为黑色,那么就符合红黑树的性质,没有与性质发生冲突。
2.如果parent节点存在且为红,uncle节点不存在
解决方法:旋转+变色
如果cur == parent->left, parent在grandfather的左边,那么就将grandfather右旋,然后把cur的颜色和grandfather的颜色调成红色,parent的颜色为黑色,然后结束。
如果cur == parent->right,parent == grandfather->grandfather的左边,那么就先左旋parent,再右旋grandfather。
3.parent为红,uncle存在且为红
解决方法:将parent和uncle变为黑,grandfather变为红,然后继续向上处理
然后就继续变成的刚才的情况,继续处理,这里要注意,当处理到根节点时,如果根节点刚好是处理完变成红的,要手动处理成黑色
4.parent为红,uncle为黑
这种情况通常发生在我们继续向上处理的过程中出现的一种情况
解决方法:和uncle为黑的解决方法一样,旋转+变色
这里旋转要注意路径是直线还是折线,要是折线就要用双旋
这是总体调整颜色的代码
while (parent && parent->_col == RED)
{
Node* grandfather = parent->_parent;
if (parent == grandfather->_left)
{
Node* uncle = grandfather->_right;
// u存在且为红
if (uncle && uncle->_col == RED)
{
// 变色
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
// 继续向上处理
cur = grandfather;
parent = cur->_parent;
}
else // u不存在 或 存在且为黑
{
if (cur == parent->_left)
{
// g
// p
// c
RotateR(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
else
{
// g
// p
// c
RotateL(parent);
RotateR(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
else // parent == grandfather->_right
{
Node* uncle = grandfather->_left;
// u存在且为红
if (uncle && uncle->_col == RED)
{
// 变色
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
// 继续向上处理
cur = grandfather;
parent = cur->_parent;
}
else
{
if (cur == parent->_right)
{
// g
// p
// c
RotateL(grandfather);
grandfather->_col = RED;
parent->_col = BLACK;
}
else
{
// g
// p
// c
RotateR(parent);
RotateL(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
}
这是总体插入的代码
bool Insert(const pair<K, V>& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
_root->_col = BLACK;
return true;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (cur->_kv.first < kv.first)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_kv.first > kv.first)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
cur = new Node(kv);
cur->_col = RED;
if (parent->_kv.first < kv.first)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
cur->_parent = parent;
while (parent && parent->_col == RED)
{
Node* grandfather = parent->_parent;
if (parent == grandfather->_left)
{
Node* uncle = grandfather->_right;
// u存在且为红
if (uncle && uncle->_col == RED)
{
// 变色
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
// 继续向上处理
cur = grandfather;
parent = cur->_parent;
}
else // u不存在 或 存在且为黑
{
if (cur == parent->_left)
{
// g
// p
// c
RotateR(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
else
{
// g
// p
// c
RotateL(parent);
RotateR(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
else // parent == grandfather->_right
{
Node* uncle = grandfather->_left;
// u存在且为红
if (uncle && uncle->_col == RED)
{
// 变色
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
// 继续向上处理
cur = grandfather;
parent = cur->_parent;
}
else
{
if (cur == parent->_right)
{
// g
// p
// c
RotateL(grandfather);
grandfather->_col = RED;
parent->_col = BLACK;
}
else
{
// g
// p
// c
RotateR(parent);
RotateL(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
}
_root->_col = BLACK;
return true;
}
void RotateL(Node* parent)
{
++_rotateCount;
Node* cur = parent->_right;
Node* curleft = cur->_left;
parent->_right = curleft;
if (curleft)
{
curleft->_parent = parent;
}
cur->_left = parent;
Node* ppnode = parent->_parent;
parent->_parent = cur;
if (parent == _root)
{
_root = cur;
cur->_parent = nullptr;
}
else
{
if (ppnode->_left == parent)
{
ppnode->_left = cur;
}
else
{
ppnode->_right = cur;
}
cur->_parent = ppnode;
}
}
void RotateR(Node* parent)
{
++_rotateCount;
Node* cur = parent->_left;
Node* curright = cur->_right;
parent->_left = curright;
if (curright)
curright->_parent = parent;
Node* ppnode = parent->_parent;
cur->_right = parent;
parent->_parent = cur;
if (ppnode == nullptr)
{
_root = cur;
cur->_parent = nullptr;
}
else
{
if (ppnode->_left == parent)
{
ppnode->_left = cur;
}
else
{
ppnode->_right = cur;
}
cur->_parent = ppnode;
}
}