1.红黑树的概念
红黑树是一种二叉搜索树,并且每个结点上增加了一个存储表示结点的颜色,可以是Red或Black。通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径的长度长出两倍,因而是近似平衡的。
2.红黑树的性质(重要)
- 每个结点的颜色不是红色就是黑色
- 根结点的颜色是黑的
- 如果一个结点是红的,则它的两个孩子结点是黑的(意思是不可能存在连续的红结点)
- 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点
- 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)
满足以上性质,红黑树就能保证:其最长路径的结点个数不会超过最短路径结点个数的两倍。
为什么呢?因为最短路径是全黑,最长路径是红黑相间,即:
3.红黑树的插入操作
插入新结点的默认颜色给成红色,因为插入之前所有根至外部结点的路径上黑色结点数目都相同,所以如果插入的结点是黑色肯定错误(黑色结点数目就不同了),而插入红结点可能会也可能不会违反“没有连续两个结点是红色”的条件,所以插入的结点为红色。如果违反了条件就再调整。
思路:
1)按照二叉搜索树的规则插入新结点
2)检测新结点插入后,红黑树的性质是否遭到破坏
因为新结点的默认颜色是红色,因此:如果其双亲结点的颜色是黑色,没有违反红黑树的性质,不需要调整;但当新插入结点的双亲结点是红色时,就违反了性质三不能有连在一起的红色结点,此时需要对红黑树分情况讨论:parent在祖父的左侧和parent在祖父的右侧。
相关代码如下:
#pragma once
#include<iostream>
using std::cout;
using std::endl;
enum Color
{
RED,
BLACK
};
template<class T>
struct RBTreeNode
{
RBTreeNode(const T& data = T(), Color color = RED)
: _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _data(data)
, _color(color)
{}
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
T _data;
Color _color;
};
template<class T>
class RBTree
{
typedef RBTreeNode<T> Node;
public:
RBTree()
:_root(nullptr)
{}
~RBTree()
{
Destroy(_root);
}
bool Insert(const T& data)
{
//第一步:按照二叉搜索树的方式插入新结点
if (nullptr == _root)
{
_root = new Node(data);
_root->_color = BLACK;
return true;
}
else
{
//按照二叉搜索树的特性,在红黑树中找到要插入的位置
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (data < cur->_data)
{
parent = cur;
cur = cur->_left;
}
else if (data > cur->_data)
{
parent = cur;
cur = cur->_right;
}
else
return false;
}
//插入新结点
cur = new Node(data);
cur->_color = RED;
if (data < parent->_data)
{
parent->_left = cur;
cur->_parent = parent;
}
else
{
parent->_right = cur;
cur->_parent = parent;
}
//第二步:检测新结点插入后,红黑树的性质是否遭到破坏,若满足性质直接退出,否则对红黑树进行旋转着色处理
while (parent && RED == parent->_color)
{
//此时grandfather一定存在,因为parent存在,且颜色不是黑色,则parent一定不是根
Node* grandfather = parent->_parent;
//parent在左侧的情况
if (parent == grandfather->_left)
{
Node* uncle = grandfather->_right;
if (uncle && RED == uncle->_color)
{
//叔叔结点存在且为红色
parent->_color = uncle->_color = BLACK;
grandfather->_color = RED;
cur = grandfather;
parent = cur->_parent;
}
else
{
//叔叔结点不存在,或叔叔结点存在且为黑色
if (cur == parent->_right)
{
RotateL(parent);
}
grandfather->_color = RED;
parent->_color = BLACK;
RotateR(grandfather);
break;
}
}
//parent在右侧的情况
else
{
Node* uncle = grandfather->_left;
if (uncle && RED == uncle->_color)
{
parent->_color = uncle->_color = BLACK;
grandfather->_color = RED;
cur = grandfather;
parent = cur->_parent;
}
else
{
if (cur == parent->_left)
{
RotateR(parent);
}
RotateL(grandfather);
grandfather->_color = RED;
parent->_color = BLACK;
break;
}
}
}
_root->_color = BLACK;
return true;
}
}
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if (subRL)
{
subRL->_parent = parent;
}
subR->_left = parent;
Node* pparent = parent->_parent;
parent->_parent = subR;
if (parent == _root)
{
_root = subR;
}
else
{
if (pparent->_left == parent)
{
pparent->_left = subR;
}
else
{
pparent->_right = subR;
}
}
subR->_parent = pparent;
}
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)
{
subLR->_parent = parent;
}
Node* pparent = parent->_parent;
subL->_right = parent;
parent->_parent = subL;
if (parent == _root)
{
_root = subL;
}
else
{
if (pparent->_left == parent)
{
pparent->_left = subL;
}
else
{
pparent->_right = subL;
}
}
subL->_parent = pparent;
}
void Inorder()
{
_Inorder(_root);
cout << endl;
}
bool IsRBtree()
{
//空树也是红黑树
if (nullptr == _root)
return true;
//检测根节点是否满足红黑树的性质
if (BLACK != _root->_color)
{
cout << "违反红黑树性质:根节点必须为黑色" << endl;
return false;
}
//获取任意一条路径中黑色结点的个数
size_t blackCount = 0;
Node* cur = _root;
while (cur)
{
if (BLACK == cur->_color)
blackCount++;
cur = cur->_left;
}
size_t k = 0;//k用来记录路径中黑色结点的个数
return _IsRBTree(_root, k, blackCount);
}
private:
void _Inorder(Node* root)
{
if (root)
{
_Inorder(root->_left);
cout << root->_data << " ";
_Inorder(root->_right);
}
}
void Destroy(Node* root)
{
if (root)
{
Destroy(root->_left);
Destroy(root->_right);
root = nullptr;
}
}
bool _IsRBTree(Node* root, size_t k, const size_t blackCount)
{
if (nullptr == root)
return true;
//统计黑色结点的个数
if (BLACK == root->_color)
k++;
//检测当前结点与其双亲结点是否都为红色
Node* parent = root->_parent;
if (parent && RED == parent->_color && RED == root->_color)
{
cout << "违反红黑树性质:没有连在一起的红色结点" << endl;
return false;
}
//检测当前路径中黑色结点的个数是否与其他路径中的黑色结点相等
if (nullptr == root->_left && nullptr == root->_right)
{
if (k != blackCount)
{
cout << "违反红黑树性质:每条路径中黑色结点的个数必须相等" << endl;
return false;
}
}
return _IsRBTree(root->_left, k, blackCount) && _IsRBTree(root->_right,k,blackCount);
}
private:
Node* _root;
};
void TestRBTree()
{
RBTree<int> rt1;
rt1.Insert(2);
rt1.Insert(8);
rt1.Insert(11);
rt1.Insert(13);
rt1.Insert(17);
rt1.Inorder();
rt1.IsRBTree();
}