系列文章目录
文章目录
- 系列文章目录
- 前言
- 1、红黑树的介绍
- 1. 红黑树的概念
- 1.2 红黑树的性质
- 2、红黑树的节点的定义
- 3、红黑树的插入(看叔叔的颜色就行)
- 3.1 情况一:uncle存在且为红
- 3.2 情况二:uncle不存在/存在且为黑(直线)
- 3.3 情况三:uncle不存在/存在且为黑(折线)
- 3.4 总结
- 4、红黑树的平衡检测
- 5、红黑树的整体代码
前言
红黑树是一种二叉搜索树,通过来节点颜色来实现接近平衡。
1、红黑树的介绍
1. 红黑树的概念
红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的。
1.2 红黑树的性质
红黑树本质也是一种二叉搜索树。底层结构需要使用二叉搜索树的地方,基本上都会使用红黑树来实现,而AVL树也因此坐上了冷板凳。
红黑树通过在每个节点上添加一个存储位,用于存储“RED”或“BLACK”。通过节点上红/黑颜色限制,确保最长路径不超过最短路径的两倍,因而它是接近平衡的树形结构。最短路径:全黑;最长路径:一黑一红交替。
-
每个结点不是红色就是黑色。
-
根节点是黑色的。
-
如果一个节点是红色的,则它的两个孩子结点是黑色的。(不能出现连续的红色节点)
-
对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点。(每条路径上都有相同数量的黑色节点)
-
每个叶子结点都是黑色的(此处的叶子结点指的是空结点)。(走到NULL才算一条路径)
最优情况:全黑或每条路径都是一黑一红的满二叉树,高度logN。
最差情况:每颗子树左子树全黑,右子树一黑一红。高度2*logN。
可以发现,最坏情况的时间复杂度和AVL树一样,都是O(logN),但是红黑树这种近似平衡的结构减少了大量旋转,综合性能优于AVL树。
2、红黑树的节点的定义
// 节点的颜色
enum Color { RED, BLACK };
// 红黑树节点的定义
template<class K, class V>
struct RBTreeNode
{
RBTreeNode(const pair<K,V>& kv, Color col = RED)
: _Left(nullptr)
, _Right(nullptr)
, _Parent(nullptr)
, _kv(kv)
, _col(col)
{}
RBTreeNode<K, V>* _Left; // 节点的左孩子
RBTreeNode<K, V>* _Right; // 节点的右孩子
RBTreeNode<K, V>* _Parent; // 节点的双亲(红黑树需要旋转,为了实现简单给出该字段)
pair<K, V> _kv; // 节点的值域
Color _col; // 节点的颜色
};
但是在构造函数中为什么默认是红色呢?为什么不能是黑色呢?
新节点给红色,可能会违反上面说的红黑树性质3;如果新节点给黑色,必定会违反性质4。
3、红黑树的插入(看叔叔的颜色就行)
插入红色节点后,判定红黑树性质是否被破坏
3.1 情况一:uncle存在且为红
可以这么想:cur为红那么就需要将parent变为黑;parent变黑需要控制每条路径上黑节点的数量相同,那么就要把uncle变黑;如果grandfather不是根,需要反转为红,用以控制路径黑节点数量相同。继续向上调整即可。
3.2 情况二:uncle不存在/存在且为黑(直线)
uncle的情况分两种:
- uncle不存在,则cur为插入节点,单旋即可。
- uncle存在且为黑是第一种情况变过来的。
3.3 情况三:uncle不存在/存在且为黑(折线)
uncle的情况分两种。
- uncle不存在,则cur为插入节点,两次单旋即可。
- uncle存在且为黑,先掰直。
3.4 总结
插入新节点时,父节点为红,看叔叔的颜色。
1、叔叔存在且为红,变色,向上调整(可能变为三种情况中的任意一种)。
2、叔叔不存在/存在且为黑,直线。单旋+变色。
3、叔叔不存在/存在且为黑,折线,两次单旋+变色。
4、红黑树的平衡检测
//检测是否符合红黑树
bool IsBalance()
{
if (_root && _root->_col == RED)
{
cout << "根节点颜色是红色" << endl;
return false;
}
//基准值
int benchmark = 0;
Node* cur = _root;
while (cur)
{
if (cur->_col == BLACK)
++benchmark;
cur = cur->_left;
}
//连续红色节点
return _Check(_root, 0, benchmark);
}
//检验是否有连续的红色节点以及黑色节点的数量
bool _Check(Node* root, int blackNum, int benchmark)
{
if (root == nullptr)
{
if (benchmark != blackNum)
{
cout << "某条路径黑色节点的数量不相等" << endl;
return false;
}
return true;
}
if (root->_col == BLACK)
{
++blackNum;
}
if (root->_col == RED
&& root->_parent
&& root->_parent->_col == RED)
{
cout << "存在连续的红色节点" << endl;
return false;
}
return _Check(root->_left, blackNum, benchmark)
&& _Check(root->_right, blackNum, benchmark);
}
-
在_IsBalance中确定号一条路径中黑色节点的数量,作为参数传递给Check函数,Check函数需要在递归至根节点时,统计,每条路径黑色节点数量是否和基准值ref相等。
-
Check函数中还需要判断:子节点为红,父节点也为红(此时不平衡)
5、红黑树的整体代码
#pragma once
#include <iostream>
#include <assert.h>
using namespace std;
// 节点的颜色
enum Color { RED, BLACK };
// 红黑树节点的定义
template<class K, class V>
struct RBTreeNode
{
RBTreeNode(const pair<K,V>& kv, Color col = RED)
: _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _kv(kv)
, _col(col)
{}
RBTreeNode<K, V>* _left; // 节点的左孩子
RBTreeNode<K, V>* _right; // 节点的右孩子
RBTreeNode<K, V>* _parent; // 节点的双亲(红黑树需要旋转,为了实现简单给出该字段)
pair<K, V> _kv; // 节点的值域
Color _col; // 节点的颜色
};
template<class K, class V>
class RBTree
{
typedef RBTreeNode<K, V> Node;
public:
//插入节点
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->_left;
}
else if (cur->_kv.first < kv.first)
{
parent = cur;
cur = cur->_right;
}
else
{
return false;
}
}
cur = new Node(kv);
if (parent->_kv.first > kv.first)
{
parent->_left = cur;
}
else
{
parent->_right = cur;
}
cur->_parent = parent;//链接父节点
while (parent && parent->_col == RED)
{
Node* grandfather = parent->_parent;
if (grandfather->_left == parent)
{
Node* uncle = grandfather->_right;
//情况一:叔叔存在且为红色,变色处理,并继续网上处理
if(uncle && uncle->_col == RED)
{
parent->_col = BLACK;
uncle->_col = BLACK;
grandfather->_col = RED;
//继续向上调整
cur = grandfather;
parent = cur->_parent;
}
else //情况二+三:u不存在/u存在且为黑,旋转+变色
{
if(cur == parent->_left)
{
RotateR(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
else
{
RotateL(parent);
RotateR(grandfather);
cur->_col = BLACK;
//parent->_col = RED;
grandfather->_col = RED;
}
break;
}
}
else // grandfather->_right == parent
{
Node* uncle = grandfather->_left;
if (uncle && uncle->_col == RED)
{
parent->_col = BLACK;
uncle->_col = BLACK;
grandfather->_col = RED;
//继续向上调整
cur = grandfather;
parent = cur->_parent;
}
else //情况二+三:u不存在/u存在且为黑,旋转+变色
{
if (cur == parent->_right)
{
RotateL(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
else
{
RotateR(parent);
RotateL(grandfather);
cur->_col = BLACK;
//parent->_col = RED;
grandfather->_col = RED;
}
break;
}
}
}
_root->_col = BLACK;
return true;
}
//中序遍历
void InOrder()
{
_InOrder(_root);
cout << endl;
}
//检测是否符合红黑树
bool IsBalance()
{
if (_root && _root->_col == RED)
{
cout << "根节点颜色是红色" << endl;
return false;
}
//基准值
int benchmark = 0;
Node* cur = _root;
while (cur)
{
if (cur->_col == BLACK)
++benchmark;
cur = cur->_left;
}
//连续红色节点
return _Check(_root, 0, benchmark);
}
//求高度
int Height()
{
return _Height(_root);
}
//析构函数
~RBTree()
{
_Destroy(_root);
_root = nullptr;
}
private:
//左旋转
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
Node* ppnode = parent->_parent;
subR->_left = parent;
parent->_parent = subR;
if (ppnode == nullptr)
{
_root = subR;
_root->_parent = nullptr;
}
else
{
if (ppnode->_left == parent)
{
ppnode->_left = subR;
}
else
{
ppnode->_right = subR;
}
subR->_parent = ppnode;
}
//parent->_bf = subR->_bf = 0;
}
//右旋转
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)
{
subLR->_parent = parent;
}
Node* ppnode = parent->_parent;
subL->_right = parent;
parent->_parent = subL;
if (parent == _root)
{
_root = subL;
_root->_parent = nullptr;
}
else
{
if (ppnode->_left == parent)
{
ppnode->_left = subL;
}
else
{
ppnode->_right = subL;
}
subL->_parent = ppnode;
}
//parent->_bf = subL->_bf = 0;
}
//左右旋转
void RotateLR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
int bf = subLR->_bf;
RotateL(parent->_left);
RotateR(parent);
/*if (bf == 1)
{
parent->_bf = 0;
subLR->_bf = 0;
subL->_bf = -1;
}
else if (bf == -1)
{
parent->_bf = 1;
subLR->_bf = 0;
subL->_bf = 0;
}
else if (bf == 0)
{
parent->_bf = 0;
subLR->_bf = 0;
subL->_bf = 0;
}
else
{
assert(false);
}*/
}
//右左旋转
void RotateRL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf;
RotateR(parent->_right);
RotateL(parent);
/*if (bf == 1)
{
parent->_bf = -1;
subRL->_bf = 0;
subR->_bf = 0;
}
else if (bf == -1)
{
parent->_bf = 0;
subRL->_bf = 0;
subR->_bf = 1;
}
else if (bf == 0)
{
parent->_bf = 0;
subRL->_bf = 0;
subR->_bf = 0;
}
else
{
assert(false);
}*/
}
//中序遍历
void _InOrder(Node* root)
{
if (root == nullptr)
{
return;
}
_InOrder(root->_left);
cout << root->_kv.first << " ";
_InOrder(root->_right);
}
//检验是否有连续的红色节点以及黑色节点的数量
bool _Check(Node* root, int blackNum, int benchmark)
{
if (root == nullptr)
{
if (benchmark != blackNum)
{
cout << "某条路径黑色节点的数量不相等" << endl;
return false;
}
return true;
}
if (root->_col == BLACK)
{
++blackNum;
}
if (root->_col == RED
&& root->_parent
&& root->_parent->_col == RED)
{
cout << "存在连续的红色节点" << endl;
return false;
}
return _Check(root->_left, blackNum, benchmark)
&& _Check(root->_right, blackNum, benchmark);
}
//树的高度
int _Height(Node* root)
{
if (root == NULL)
return 0;
int leftH = _Height(root->_left);
int rightH = _Height(root->_right);
return leftH > rightH ? leftH + 1 : rightH + 1;
}
//删除树
void _Destroy(Node* root)
{
if (root == nullptr)
{
return;
}
_Destroy(root->_left);
_Destroy(root->_right);
delete root;
}
//查找
Node* Find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (cur->_kv.first < key)
{
cur = cur->_right;
}
else if (cur->_kv.first > key)
{
cur = cur->_left;
}
else
{
return cur;
}
}
return nullptr;
}
private:
Node* _root = nullptr;
};
void Test_RBTree1()
{//测试代码1
//int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
RBTree<int, int> t1;
for (auto e : a)
{
t1.Insert(make_pair(e, e));
//cout << e << ":" << t1.IsBalance() << endl;
}
t1.InOrder();
//cout << t1.IsBalance() << endl;
}
void Test_RBTree2()
{//测试代码2
srand(time(0));
const size_t N = 50000;
RBTree<int, int> t;
for (size_t i = 0; i < N; ++i)
{
size_t x = rand() + i;
t.Insert(make_pair(x, x));
//cout << t.IsBalance() << endl;
}
//t.Inorder();
cout << t.IsBalance() << endl;
cout << t.Height() << endl;
}