目录
红黑树的概念
红黑树本质上是一棵二叉搜索树,只不过在此基础上增加了一些条件规定与限制
1.结点是红色或黑色。
2.根结点是黑色。
3.每个叶子结点都是黑色的空结点(NIL结点)。
4 每个红色结点的两个子结点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色结点)
5.从任一结点到其每个叶子的所有路径都包含相同数目的黑色结点。
空树也是红黑树
红黑树的插入
这个也是红黑树的精髓,其他的地方代码一看就懂了
我们假设有三种情况
情况1
叔叔节点存在且为红
如图,星星可以表示空,也可以表示子树
cur为新的红色的节点
在这种情况下,cur和p两个必须有一个要变成红色,如果把cur变成黑色,你会发现不符合上面的规定5,而且这种情况想改都没有办法改,所以我们需要把p变成黑色,虽然也不符合规定5,但是我们可以继续把u节点变成黑色,这样对于这颗子树就符合红黑树的规定了
但是如果g上面还有双亲,对于g的双亲,又不满足规定5了,所以我们需要对g进行修改,将g改为红色,这样就好了,有人可能会问了,那万一g的双亲也是红色的,怎么办,不急,我们不是说了么,星星可以代表子树,那可能到时候就又是情况1了,不是也无妨,我们看情况2
情况2
叔叔节点不存在||存在且为黑
类似于这种,在这种情况下,我们可以得到一个结论,cur一定不是叶子节点,为什么呢,因为如果cur是叶子结点,那在它插入之前,你可以看一下,这棵树已经不是红黑树了,所以cur不是页子节点,而是调整上来的,就比如说情况1把g节点变成红色了,这个cur可能就是情况1的g
说这个有什么用呢?这表明,cur的子树里面一定有黑色节点,因为它是调整上来的嘛,它原本就是黑色节点,后来调整成为了红色,那它的下面就一定得有黑色的节点,那可得,p的右子树里面也一定有黑色节点,不然cur是黑色的时候就不满足规定5了
现在cur和p必须要有一个变成黑色,肯定不能是cur,因为它是调整上来的,一变又回去了,所以只能是p变成黑色,但是对应g,又不满足规定5了,所以我们得继续调整,我们需要把g变为黑色,然后进行右单旋,旋转之后就满足了,如果不知道什么是右单旋可以看我的AVL树的博客,里面介绍了右单旋
(56条消息) AVL树插入操作与验证操作的简单实现_芜湖开冲~的博客-CSDN博客
之后就符合红黑树的性质了
有的同学可能说,你这不符合规定5啊,我们前面已经讨论过了,cur底下的两棵子树必定有黑色节点,而且g的左子树,也就是原本p的右子树,里面也一定有黑色节点
情况3
叔叔节点不存在||存在且为黑
只不过这一次cur是在内侧
这种情况和情况2很像,直接说结论吧,把parent变成黑色,g变成红色,然后对p左单旋变成情况2
红黑树节点的代码实现
//红黑树的节点
template <class T>
struct RBTreeNode {
//构造函数,默认颜色是红色,因为如果默认是黑色的,那必须每一次增加一个新的节点,都必须调整一次
//而新增红色的节点有时候可以不用调
RBTreeNode(const T& value = T(), const Colour& colour = RED)
:_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_col(colour)
,_val(value)
{}
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
Colour _col;
T _val;
};
红黑树迭代器的代码实现
//红黑树的迭代器结构,本质也是对节点的封装
template <class T>
struct RBTreeIterator {
typedef RBTreeNode<T> Node;
typedef RBTreeIterator<T> Self;
RBTreeIterator(Node* pNode)
:_pNode(pNode)
{}
//让迭代器拥有类似于指针的功能
//解引用
T& operator*() {
return _pNode->_val;
}
//->运算符,这里把它当做一个一元的后缀运算符,返回的是一个指针,表示的是指针里面值的地址
//感觉好像是退裤子放屁,其实不是,因为迭代器的值可能是一个结构体里面的某一个值,取的是那一个值的地址
T* operator->() {
return &(operator*());
}
//前置++与后置++
Self& operator++() {
Increament();
return *this;
}
//迭代器本身指向的是新的元素,而返回的是上一个元素
Self operator++(int) {
Self temp(*this);
Increament();
return temp;
}
//前置--与后置--
Self& operator--() {
DeIncreament();
return *this;
}
Self operator--(int) {
Self temp(*this);
DeIncreament();
return temp;
}
//迭代器比较
bool operator!=(const Self& s) {
return _pNode != s._pNode;
}
bool operator==(const Self& s) {
return _pNode == s._pNode;
}
//迭代器向后移动
//对于红黑树来说,就是找比它大的节点中最小的那个
void Increament() {
if (_pNode->_right) {
_pNode = _pNode->_right;
while (_pNode->_left) {
_pNode = _pNode->_left;
}
}
else {
Node* parent = _pNode->_parent;
while (parent->_right == _pNode) {
_pNode = parent;
parent = parent->_parent;
}
if (_pNode->_right != parent) {
_pNode = parent;
}
}
}
//迭代器向前移动
void DeIncreament() {
if (_pNode->_parent->_parent == _pNode && _pNode->_col == RED) {
_pNode = _pNode->_right;
return;
}
if (_pNode->_left) {
_pNode = _pNode->_left;
while (_pNode->_right) {
_pNode = _pNode->_right;
}
}
else {
Node* parent = _pNode->_parent;
while (parent->_left == _pNode) {
_pNode = parent;
parent = parent->_parent;
}
_pNode = parent;
}
}
Node* _pNode;
};
红黑树本体代码的实现
//红黑树,约定:不考虑key重复的情况
template <class T, class KeyOfValue> //这里的KeyOfValue不用管,是用于map,set封装的时候使用的
class RBTree {
typedef RBTreeNode<T> Node;
public:
typedef RBTreeIterator<T> iterator;
public:
RBTree()
: _size(0)
{
_pHead = new Node;
_pHead->_left = _pHead;
_pHead->_right = _pHead;
_pHead->_parent = nullptr;
}
~RBTree() {
_Destroy(_pHead->_parent);
delete _pHead;
_pHead = nullptr;
_size = 0;
}
//插入值为data的节点,iterator表示这个节点的迭代器,bool表示是否插入成功
pair<iterator, bool> Insert(const T& data) {
//找到要插入的位置
KeyOfValue kov;
//空树
Node* newnode = nullptr;
if (_size == 0) {
newnode = new Node(data, BLACK);
newnode->_parent = _pHead;
_pHead->_parent = newnode;
}
//非空,用二叉搜索树的方式插入节点
else {
Node* cur = _pHead->_parent;
Node* parent = _pHead;
//找位置
while (cur) {
parent = cur;
if (kov(data) < kov(cur->_val)) {
cur = cur->_left;
}
else if (kov(data) > kov(cur->_val)) {
cur = cur->_right;
}
else {
return make_pair(iterator(_pHead), false);
}
}
cur = new Node(data);
if (kov(data) < kov(parent->_val)) {
parent->_left = cur;
}
else {
parent->_right = cur;
}
cur->_parent = parent;
newnode = cur;
while (parent != _pHead && parent->_col == RED) {
//parent是红色的,所以不是根节点,也不可能原本是根节点,被改成红节点
//因为此时还没有对parent进行操作呢,也不可能是_pHead,所以一定有双亲
Node* grandFather = parent->_parent;
//分两大类,parent在grandFather左和右
//在左
if (parent == grandFather->_left) {
Node* uncle = grandFather->_right;
if (uncle && RED == uncle->_col) {
// 叔叔节点存在且为红
parent->_col = BLACK;
uncle->_col = BLACK;
grandFather->_col = RED;
cur = grandFather;
parent = cur->_parent;
}
else {
// 叔叔节点为空 || 叔叔节点存在且为黑
// cur在内侧
if (cur == parent->_right)
{
// 先对parent进行左单旋,然后将parent和cur交换---->变成cur在外侧
RotateL(parent);
swap(parent, cur);
}
// cur在外侧
// 将祖父和双亲节点的颜色交换,然后再对祖父树进行右单旋
grandFather->_col = RED;
parent->_col = BLACK;
RotateR(grandFather);
}
}
//在右
else {
Node* uncle = grandFather->_left;
if (uncle && RED == uncle->_col)
{
// 叔叔节点存在且为红
parent->_col = BLACK;
uncle->_col = BLACK;
grandFather->_col = RED;
cur = grandFather;
parent = cur->_parent;
}
else
{
// 叔叔节点不存在 || 叔叔节点存在并且颜色是黑色
if (cur == parent->_left)
{
//cur在内侧
RotateR(parent);
swap(cur, parent);
}
//cur在外侧
parent->_col = BLACK;
grandFather->_col = RED;
RotateL(grandFather);
}
}
}
}
// 需要更新_pHead的left和right指针域
_pHead->_left = _LeftMost();
_pHead->_right = _RightMost();
_pHead->_parent->_col = BLACK;
++_size;
return make_pair(iterator(newnode), true);
}
//迭代器,之所以第一个字母大写,一方面是内部整齐,另一方面是一般不直接用红黑树,而是封装使用
//所以不必考虑外部使用的情况
iterator Begin() {
return iterator(_LeftMost());
}
iterator End() {
return iterator(_pHead);
}
// 判空
bool Empty()const {
return _size == 0;
}
//红黑树中有效节点的个数
size_t Size()const {
return _size;
}
void Clear() {
_Destroy(GetRoot());
_size = 0;
}
// 查找
iterator Find(const T& data) {
Node* cur = GetRoot();
if (cur == nullptr) {
return iterator(_pHead);
}
KeyOfValue kov;
while (cur != nullptr) {
if (kov(data) < kov(cur->_val)) {
cur = cur->_left;
}
else if (kov(data) > kov(cur->_val)) {
cur = cur->_right;
}
else {
return iterator(cur);
}
}
return iterator(_pHead);
}
//交换
void Swap(RBTree<T, KeyOfValue>& t) {
std::swap(_pHead, t._pHead);
}
private:
//寻找最小节点
Node* _LeftMost() {
Node* cur = GetRoot();
//判断一下,不然底下不好写
if (nullptr == cur) {
return _pHead;
}
while (cur->_left) {
cur = cur->_left;
}
return cur;
}
//寻找最大节点
Node* _RightMost() {
Node* cur = GetRoot();
if (nullptr == cur) {
return _pHead;
}
while (cur->_right) {
cur = cur->_right;
}
return cur;
}
//销毁树
void _Destroy(Node*& pRoot) {
if (pRoot) {
_Destroy(pRoot->_left);
_Destroy(pRoot->_right);
delete pRoot;
pRoot = nullptr;
}
}
//左单旋
void RotateL(Node* parent) {
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
// 右单支
if (subRL) {
subRL->_parent = parent;
}
subR->_left = parent;
// 更新parent和subR的双亲
Node* pparent = parent->_parent;
parent->_parent = subR;
subR->_parent = pparent;
// 还需要处理pparent的孩子
if (pparent == _pHead) {
_pHead->_parent = subR;
}
else {
if (parent == pparent->_left) {
pparent->_left = subR;
}
else {
pparent->_right = subR;
}
}
}
void RotateR(Node* parent) {
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
// 左单支
if (subLR) {
subLR->_parent = parent;
}
subL->_right = parent;
// 更新parent和subL的双薪
Node* pparent = parent->_parent;
parent->_parent = subL;
subL->_parent = pparent;
if (pparent == _pHead) {
_pHead->_parent = subL;
}
else {
if (parent == pparent->_left) {
pparent->_left = subL;
}
else {
pparent->_right = subL;
}
}
}
Node* GetRoot() {
return _pHead->_parent;
}
private:
Node* _pHead;
size_t _size;
};
实现里面的细节我已经放到注释里面了,如果还有什么不懂的,欢迎评论区留言