1.红黑树的概念
红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的。
2.红黑树的性质
- 根节点是黑色的
- 如果一个节点是红色的,则它的两个孩子结点是黑色的
- 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点
- 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)
思考:为什么满足上面的性质,红黑树就能保证:其最长路径中节点个数不会超过最短路径节点个数的两倍?
3.红黑树的实现
REBBLACKTree.h
#pragma once
#include <iostream>
using namespace std;
enum Color
{
BLACK,
RED
};
template<class K, class V>
struct RBTreeNode
{
RBTreeNode<K, V>* _left;
RBTreeNode<K, V>* _right;
RBTreeNode<K, V>* _parent;
pair<K, V> _kv;
Color _col;
RBTreeNode(const pair<K,V>& kv)
:_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_kv(kv)
,_col(RED)
{}
};
template<class K,class V>
class RBTree
{
typedef RBTreeNode<K, V> Node;
public:
RBTree()
:_root(nullptr)
{}
void _Destory(Node* root)
{
if (root == nullptr)
{
return;
}
_Destory(root->_left);
_Destory(root->_right);
delete root;
}
~RBTree()
{
_Destory(_root);
_root = nullptr;
}
Node* Find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (cur->_kv.first > key)
{
cur = cur->_left;
}
else if (cur->_kv.first < key)
{
cur = cur->_right;
}
else
{
return cur;
}
}
return nullptr;
}
pair<Node*, bool> Insert(const pair<K,V>& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
_root->_col = BLACK;
return make_pair(_root, 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 make_pair(cur, false);
}
}
Node* newNode = new Node(kv);
newNode->_col = RED;
//为什么我们要将新插入的节点的颜色设置为红色
//如果我们设置为黑色,则该路径黑色节点数量相比于其他路径的黑色节点数量多了一个
//总不可能插入一个节点就对所有路径进行更改
//如果我们插入红色,有可能会出现连续红色节点,我们针对连续红色节点进行下面的处理
if (newNode->_kv.first > parent->_kv.first)
{
parent->_right = newNode;
newNode->_parent = parent;
}
else
{
parent->_left = newNode;
newNode->_parent = parent;
}
cur = newNode;
//当我们插入了新节点之后,可能我们破坏了红黑树的性质
//如果父亲是黑色不用处理,如果是红色需要处理(出现了连续的红色节点)
while (parent && parent->_col == RED)
{
Node* grandfather = parent->_parent;
if (parent == grandfather->_left)
{
Node* uncle = grandfather->_right;
if (uncle && uncle->_col == RED)//叔叔存在且为红
{
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
cur = grandfather;
parent = cur->_parent;
}
else//叔叔存在且为黑 或者 叔叔不存在
{
if (cur == parent->_left)//单旋
{
RotateR(grandfather);
grandfather->_col = RED;
parent->_col = BLACK;
}
else
{
RotateL(parent);
RotateR(grandfather);
grandfather->_col = RED;
cur->_col = BLACK;
}
break;
}
}
else//同上
{
Node* uncle = grandfather->_left;
if (uncle && uncle->_col == RED)//叔叔存在且为红
{
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
cur = grandfather;
parent = cur->_parent;
}
else
{
if (cur == parent->_left)
{
RotateR(parent);
RotateL(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
else
{
RotateL(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
}
_root->_col = BLACK;
return make_pair(newNode, true);
}
void RotateL(Node* parent)//左单旋
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
Node* parentParent = parent->_parent;
parent->_right = subRL;
if (subRL)//subRL为空就不用给subRL找父母了
{
subRL->_parent = parent;
}
parent->_parent = subR;
subR->_left = parent;
if (parent == _root)//如果parent是根节点,把根节点改为subR,_root的父母置为nullptr
{
_root = subR;
_root->_parent = nullptr;
}
else//parent不是根节点
{
//判断parent是parentParent的左还是右
if (parentParent->_left == parent)
{
parentParent->_left = subR;
}
else
{
parentParent->_right = subR;
}
subR->_parent = parentParent;
}
}
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
Node* parentParent = parent->_parent;
parent->_left = subLR;
if (subLR)
{
subLR->_parent = parent;
}
parent->_parent = subL;
subL->_right = parent;
if (parent == _root)
{
_root = subL;
_root->_parent = nullptr;
}
else
{
if (parent == parentParent->_left)
{
parentParent->_left = subL;
}
else
{
parentParent->_right = subL;
}
subL->_parent = parentParent;
}
}
bool _CheckBalance(Node* root, int blackNum, int count)
{
if (root == nullptr)//走到空了说明要开始比较黑色节点数量
{
if (count != blackNum)
{
cout << "黑色节点数量不相等" << endl;
return false;
}
return true;
}
if (root->_col == RED && root->_parent->_col == RED)
{
cout << "存在连续的红色节点" << endl;
return false;
}
if (root->_col == BLACK)
count++;
return _CheckBalance(root->_left, blackNum, count)
&& _CheckBalance(root->_right, blackNum, count);
}
bool CheckBalance()
{
if (_root == nullptr)//空树认为平衡
return true;
if (_root->_col == RED)//根节点颜色为红则不平衡
return false;
//通过每条路径的黑色节点数量是否全部相等来判断,且不能有连续的红色节点
//我们先记录最左路径黑色节点的数量作为参考值
//在依次遍历其他路径,每遍历一条路径,就将其黑色节点数量与参考值比较
//如果遇到不相等的就不平衡
int blackNum = 0;
Node* cur = _root;
while (cur)
{
if (cur->_col == BLACK)
blackNum++;
cur = cur->_left;
}
int count = 0;
return _CheckBalance(_root, blackNum, count);
}
void _InOrder(Node* root)
{
if (root == nullptr)
return;
_InOrder(root->_left);
cout << root->_kv.first << ":" << root->_kv.second << " ";
_InOrder(root->_right);
}
void InOrder()
{
_InOrder(_root);
cout << endl;
}
private:
Node* _root;
};
test.cpp
#include "RedBlackTree.h"
#include <time.h>
void TestRBTree()
{
//int a[] = {16,3,7,11,9,26,18,14,15};
//int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16,14 };
int a[] = { 13,8,17,1,11,15,25,6,22,27 };
RBTree<int,int> t;
for (auto e : a)
{
t.Insert(make_pair(e, e));
}
t.InOrder();
int ret = t.CheckBalance();
cout << ret << endl;
srand(time(0));
int i = 100000000;
while (i--)
{
int e = rand();
t.Insert(make_pair(e, e));
}
cout << t.CheckBalance() << endl;
}
int main()
{
TestRBTree();
return 0;
}