目录
1.红黑树的概念
红黑树是一种近似平衡的二叉树,但在每个节点上增加一个存储位表示节点的颜色,可以是红或黑。通过对任何一条从根到叶子的路径上各个节点着色方式的限制,红黑树确保没有一条路径会比其他路径长出两倍,因而是接近平衡的。
2.红黑树的性质
1.每个节点不是红色就是黑色
2.根节点是黑色的(根黑)
3.如果一个节点是红色的,则它的两个孩子节点是黑色的(即不能有连续两个相同红节点)
4.对于每个节点,从该节点到其所有后代的简单路径上,均包含相同数目的黑色节点,每条路径均以空为结尾
5.每个叶子节点都是黑色的(叶子节点指定是空节点)
确保最长路径不超过最短路径的二倍,即最短路径 < 最长路径 <= 最短路径*2 原理(不考虑叶子节点->空节点):
理论最短路径->全黑,实际最短路径 >= 理论最短路径
理论最长路径->一红一黑交替(红结束),实际最长路径<=理论最长路径
由条件4得知从任意节点到其所有后代叶子节点的简单路径上,均包含相同数目的黑色节点,
则有理论最长路径 == 理论最短路径*2, 所以有实际最长路径 <= 理论最长路径 == 理论最短路径 *2 <= 实际最短路径 *2 ,即实际最长路径 <= 实际最短路径 *2
3.红黑树的操作
3.1 节点定义
三叉链结构,_data指向值域,_color标记节点的颜色
enum Color
{
_red, _black//0--red, 1--black
};
template<class K, class V>
struct RBTreeNode
{
typedef RBTreeNode<K, V> Node;
//init
//color默认给_red
RBTreeNode(const pair<K, V>& data = pair<K, V>(), Color color = _red)
:_left(nullptr), _right(nullptr), _parent(nullptr), _data(data), _color(color)
{}
Node* _left;
Node* _right;
Node* _parent;
pair<K, V> _data;
Color _color;
};
3.2 红黑树实现结构
红黑树的实现中增加一个头结点,因为跟节点必须为黑色,为了与根节点进行区分,将头结点给成黑色,并且让头结点的_parent 域指向红黑树的根节点,_left 域指向红黑树中最小的节点_right 域指向红黑树中最大的节点。
3.3 find操作
根据查找的key值大小,大于key向右查找,小于key向左查找,走到nullptr 表示不存在
Node* find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (key > cur->_data.first)
cur = cur->_right;
else if (key < cur->_data.first)
cur = cur->_left;
else//找到哩
return cur;
}
//cout << "key不存在" << endl;
return nullptr;
}
3.4 insert操作
1.查找插入位置
2.插入节点
3.调整恢复红黑树结构(检测新节点插入后,红黑树的性质是否造成破坏):
新节点的默认颜色是红色,如果如果其双亲节点的颜色是黑色,没有违反红黑树任何性质,则不需要调整;但当新插入节点的双亲节点颜色为红色时,就违反了性质三不能有连在一起的红色节点,此时需要对红黑树分情况来讨论:
(约定:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点)
a.cur为红,p为红,g为黑,u存在且为红
将p,u改为黑,g改为红,然后把g当成cur,继续向上调整
b. cur为红,p为红,g为黑,u不存在/u存在且为黑
p为g的左孩子,cur为p的左孩子,则进行右单旋转;
p为g的右孩子,cur为p的右孩子,则进行左单旋转;
p、g变色--p变黑,g变红
c. cur为红,p为红,g为黑,u不存在/u存在且为黑
p为g的左孩子,cur为p的右孩子,则针对p做左单旋转,再对g做右单旋转(情况b)
p为g的右孩子,cur为p的左孩子,则针对p做右单旋转,再对g做左单旋转(情况b)
bool insert(const pair<K, V>& data)
{
//1.查找插入位置
//2.插入节点
//3.调整RBT
//
//1.查找插入位置
//空树直接插入--根黑
if (_root == nullptr)
{
_root = new Node(data,_black);//根黑
_root->_parent = _head;
_head->_parent = _root;
_head->_left = _head->_right = _root;
return true;
}
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (data.first > cur->_data.first)
{
parent = cur;
cur = cur->_right;
}
else if (data.first < cur->_data.first)
{
parent = cur;
cur = cur->_left;
}
else//key已存在
{
return false;
}
}
//2.插入节点--除根节点外,默认插入节点为红色
cur = new Node(data, _red);
if (parent->_data.first > data.first)
{
parent->_left = cur;
cur->_parent = parent;
}
else
{
parent->_right = cur;
cur->_parent = parent;
}
//3.调整
//3.1插入后无连续红节点--直接插入,无需修改
//3.2插入后有连续红节点--需要调整,调整需要看parent的兄弟节点uncle
while (parent && parent->_color == _red)
{
//parent为红说明一定存在parent的父节点
Node* gfather = parent->_parent;
// g
//p u
if (parent == gfather->_left)
{
Node* uncle = gfather->_right;
//uncle存在且为红
if (uncle && uncle->_color == _red)
{
parent->_color = _black;
uncle->_color = _black;
gfather->_color = _red;
//需要继续更新,上层可能因为gfather变红出现连续红节点
cur = gfather;
parent = gfather->_parent;
}
else//uncle存在且为黑或不存在 -> 旋转+变色
{
if (cur == parent->_left) // LL型
{
// g
// p u
//c
//右旋
RotateR(gfather);
gfather->_color = _red;
parent->_color = _black;
//根为黑,不需要向上更新了
}
else//LR型
{
// g
// p u
// c
//左旋+右旋
RotateL(parent);
RotateR(gfather);
cur->_color = _black;
gfather->_color = _red;
//根为黑,不需要向上更新了
}
break;
}
}
// g
//u p
else//parent在gfather的右边
{
Node* uncle = gfather->_left;
//uncle存在且为红
if (uncle && uncle->_color == _red)
{
parent->_color = uncle->_color = _black;
gfather->_color = _red;
//向上更新
cur = gfather;
parent = cur->_parent;
}
else//叔叔不存在或存在且为黑
{
// g
//u p
// c
//RR型
if (cur == parent->_right)
{
RotateL(gfather);
parent->_color = _black;
gfather->_color = _red;
}
else
{
// g
//u p
// c
//RL型
RotateR(parent);
RotateL(gfather);
cur->_color = _black;
gfather->_color = _red;
}
break;
}
}
}
//4.更新_head的状态
_root->_color = _black;//根可能会变红,需要变为黑色,全部路径黑节点数+1
_head->_parent = _root;
_head->_left = _Min(_root);
_head->_right = _Max(_root);
return true;
}
//左旋
void RotateL(Node* parent)
{
Node* p_r = parent->_right;
Node* p_r_l = p_r->_left;
parent->_right = p_r_l;
if (p_r_l != nullptr)
p_r_l->_parent = parent;
Node* parent_parent = parent->_parent;
p_r->_left = parent;
parent->_parent = p_r;
//p_r变成根
if (parent_parent == _head)
{
_root = p_r;
p_r->_parent = _head;
_head->_parent = _root;
_head->_left = _Min(_root);
_head->_right = _Max(_root);
}
else
{
if (parent == parent_parent->_left)
parent_parent->_left = p_r;
else
parent_parent->_right = p_r;
p_r->_parent = parent_parent;
}
}
//右旋
void RotateR(Node* parent)
{
Node* p_l = parent->_left;
Node* p_l_r = p_l->_right;
parent->_left = p_l_r;
if (p_l_r != nullptr)
p_l_r->_parent = parent;
Node* parent_parent = parent->_parent;
p_l->_right = parent;
parent->_parent = p_l;
//变成根节点
if (parent_parent == _head)
{
_root = p_l;
p_l->_parent = _head;
_head->_parent = _root;
_head->_left = _Min(_root);
_head->_right = _Max(_root);
}
else
{
if (parent == parent_parent->_left)
parent_parent->_left = p_l;
else
parent_parent->_right = p_l;
p_l->_parent = parent_parent;
}
}
3.5 erase操作
参考视频:
https://www.bilibili.com/video/BV16m421u7Tb?vd_source=c744ec928a14e81c8bf974e8d2d7e80f
3.6 红黑树的检验
1. 检验是否满足二叉搜索树(中序遍历是否是有序序列)
2.检测其是否满足红黑树的性质:不能出现连续红节点,计算每条路径黑节点数量是否相同,根是否为黑
//检测是否是红黑树
bool IsRBTree()
{
if (_root == nullptr)
return true;
if (_root->_color == _red)
return false;
//计算任意一条路径的黑节点数量
int refNum = 0;
Node* cur = _root;
while (cur)
{
if (cur->_color == _black)
++refNum;
cur = cur->_left;
}
return _Check(_root, 0, refNum);
}
bool _Check(Node* root, int blackNum, const int refNum)
{
if (root == nullptr)
{
if (refNum != blackNum)
{
cout << "存在黑色节点的数量不相等的路径" << endl;
return false;
}
return true;
}
if (root->_color == _red && root->_parent->_color == _red)
{
cout << root->_data.first << "存在连续红节点" << endl;
return false;
}
if (root->_color == _black)
blackNum++;
return _Check(root->_left, blackNum, refNum) && _Check(root->_right, blackNum, refNum);
}
4. 红黑树与AVL树的比较
红黑树和AVL树都是高效的平衡二叉树,增删改查的时间复杂度都是O(),红黑树不追求绝对平衡,其只需保证最长路径不超过最短路径的2倍,相对而言,降低了插入和旋转的次数,所以在经常进行增删的结构中性能比AVL树更优,而且红黑树实现比较简单,所以实际运用中红黑树更多,例如STL使用红黑树作为底层实现的set和map。
5.模拟实现代码
#pragma once
#include <iostream>
#include <time.h>
#include <assert.h>
#include <string>
#include <vector>
#include <map>
#include <cstdlib>
#include <set>
#include <list>
#include <algorithm>
using namespace std;
namespace myRBTree//KV模型
{
enum Color
{
_red, _black//0--red, 1--black
};
template<class K, class V>
struct RBTreeNode
{
typedef RBTreeNode<K, V> Node;
//init
//color默认给_red
RBTreeNode(const pair<K, V>& data = pair<K, V>(), Color color = _red)
:_left(nullptr), _right(nullptr), _parent(nullptr), _data(data), _color(color)
{}
Node* _left;
Node* _right;
Node* _parent;
pair<K, V> _data;
Color _color;
};
template <class K, class V>
class RBTree
{
typedef RBTreeNode<K, V> Node;
public:
RBTree()
:_root(nullptr)
{
_head = new Node(pair<K, V>{INT_MIN, INT_MAX}, _black);
}
RBTree(const RBTree<K,V>& tree)
{
_head = new Node(pair<K, V>{INT_MIN, INT_MAX}, _black);
_root = _Copy(tree._root, tree._root->_parent);
_root->_parent = _head;
//哨兵头节点链接
_head->_parent = _root;
_head->_left = _Min(_root);
_head->_right = _Max(_root);
}
RBTree<K, V>& operator=(RBTree<K, V> tree)
{
//现代写法
std::swap(_root, tree._root);
std::swap(_head,tree._head);
//局部变量自动销毁
return *this;
}
~RBTree()
{
_destroy(_root);
delete _head;
_root = nullptr;
_head = nullptr;
}
Node* find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (key > cur->_data.first)
cur = cur->_right;
else if (key < cur->_data.first)
cur = cur->_left;
else//找到哩
return cur;
}
//cout << "key不存在" << endl;
return nullptr;
}
bool insert(const pair<K, V>& data)
{
//1.查找插入位置
//2.插入节点
//3.调整RBT
//
//1.查找插入位置
//空树直接插入--根黑
if (_root == nullptr)
{
_root = new Node(data,_black);//根黑
_root->_parent = _head;
_head->_parent = _root;
_head->_left = _head->_right = _root;
return true;
}
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (data.first > cur->_data.first)
{
parent = cur;
cur = cur->_right;
}
else if (data.first < cur->_data.first)
{
parent = cur;
cur = cur->_left;
}
else//key已存在
{
return false;
}
}
//2.插入节点--除根节点外,默认插入节点为红色
cur = new Node(data, _red);
if (parent->_data.first > data.first)
{
parent->_left = cur;
cur->_parent = parent;
}
else
{
parent->_right = cur;
cur->_parent = parent;
}
//3.调整
//3.1插入后无连续红节点--直接插入,无需修改
//3.2插入后有连续红节点--需要调整,调整需要看parent的兄弟节点uncle
while (parent && parent->_color == _red)
{
//parent为红说明一定存在parent的父节点
Node* gfather = parent->_parent;
// g
//p u
if (parent == gfather->_left)
{
Node* uncle = gfather->_right;
//uncle存在且为红
if (uncle && uncle->_color == _red)
{
parent->_color = _black;
uncle->_color = _black;
gfather->_color = _red;
//需要继续更新,上层可能因为gfather变红出现连续红节点
cur = gfather;
parent = gfather->_parent;
}
else//uncle存在且为黑或不存在 -> 旋转+变色
{
if (cur == parent->_left) // LL型
{
// g
// p u
//c
//右旋
RotateR(gfather);
gfather->_color = _red;
parent->_color = _black;
//根为黑,不需要向上更新了
}
else//LR型
{
// g
// p u
// c
//左旋+右旋
RotateL(parent);
RotateR(gfather);
cur->_color = _black;
gfather->_color = _red;
//根为黑,不需要向上更新了
}
break;
}
}
// g
//u p
else//parent在gfather的右边
{
Node* uncle = gfather->_left;
//uncle存在且为红
if (uncle && uncle->_color == _red)
{
parent->_color = uncle->_color = _black;
gfather->_color = _red;
//向上更新
cur = gfather;
parent = cur->_parent;
}
else//叔叔不存在或存在且为黑
{
// g
//u p
// c
//RR型
if (cur == parent->_right)
{
RotateL(gfather);
parent->_color = _black;
gfather->_color = _red;
}
else
{
// g
//u p
// c
//RL型
RotateR(parent);
RotateL(gfather);
cur->_color = _black;
gfather->_color = _red;
}
break;
}
}
}
//4.更新_head的状态
_root->_color = _black;//根可能会变红,需要变为黑色,全部路径黑节点数+1
_head->_parent = _root;
_head->_left = _Min(_root);
_head->_right = _Max(_root);
return true;
}
void InOrder()
{
_InOrder(_root);
}
//检测是否是红黑树
bool IsRBTree()
{
if (_root == nullptr)
return true;
if (_root->_color == _red)
return false;
//计算任意一条路径的黑节点数量
int refNum = 0;
Node* cur = _root;
while (cur)
{
if (cur->_color == _black)
++refNum;
cur = cur->_left;
}
return _Check(_root, 0, refNum);
}
int size()
{
return _size(_root);
}
private:
int _size(Node* root)
{
if (root == nullptr)
return 0;
return _size(root->_left) + _size(root->_right) + 1;
}
bool _Check(Node* root, int blackNum, const int refNum)
{
if (root == nullptr)
{
if (refNum != blackNum)
{
cout << "存在黑色节点的数量不相等的路径" << endl;
return false;
}
return true;
}
if (root->_color == _red && root->_parent->_color == _red)
{
cout << root->_data.first << "存在连续红节点" << endl;
return false;
}
if (root->_color == _black)
blackNum++;
return _Check(root->_left, blackNum, refNum) && _Check(root->_right, blackNum, refNum);
}
void _InOrder(Node* root)
{
if (root == nullptr)
return;
_InOrder(root->_left);
cout << root->_data.first << ':' << root->_data.second << ' ' << root->_color << endl;
//cout << root->_data.first << ':' << root->_data.second << endl;
_InOrder(root->_right);
}
int _Height(Node* root)
{
if (root == nullptr)
return 0;
int heightL = _Height(root->_left);
int heightR = _Height(root->_right);
return max(heightL, heightR) + 1;
}
//左旋
void RotateL(Node* parent)
{
Node* p_r = parent->_right;
Node* p_r_l = p_r->_left;
parent->_right = p_r_l;
if (p_r_l != nullptr)
p_r_l->_parent = parent;
Node* parent_parent = parent->_parent;
p_r->_left = parent;
parent->_parent = p_r;
//p_r变成根
if (parent_parent == _head)
{
_root = p_r;
p_r->_parent = _head;
_head->_parent = _root;
_head->_left = _Min(_root);
_head->_right = _Max(_root);
}
else
{
if (parent == parent_parent->_left)
parent_parent->_left = p_r;
else
parent_parent->_right = p_r;
p_r->_parent = parent_parent;
}
}
//右旋
void RotateR(Node* parent)
{
Node* p_l = parent->_left;
Node* p_l_r = p_l->_right;
parent->_left = p_l_r;
if (p_l_r != nullptr)
p_l_r->_parent = parent;
Node* parent_parent = parent->_parent;
p_l->_right = parent;
parent->_parent = p_l;
//变成根节点
if (parent_parent == _head)
{
_root = p_l;
p_l->_parent = _head;
_head->_parent = _root;
_head->_left = _Min(_root);
_head->_right = _Max(_root);
}
else
{
if (parent == parent_parent->_left)
parent_parent->_left = p_l;
else
parent_parent->_right = p_l;
p_l->_parent = parent_parent;
}
}
void _destroy(Node* _root)
{
if (_root == nullptr)
return;
_destroy(_root->_left);
_destroy(_root->_right);
delete _root;
}
Node* _Copy(Node* root, Node* newRootParent)
{
if (root == nullptr)
return nullptr;
Node* newRoot = new Node(root->_data,root->_color);
newRoot->_left = _Copy(root->_left, newRoot);
newRoot->_right = _Copy(root->_right, newRoot);
newRoot->_parent = newRootParent;
return newRoot;
}
Node* _Min(Node* root)
{
if (root == nullptr)
return nullptr;
while (root->_left != nullptr)
{
root = root->_left;
}
return root;
}
Node* _Max(Node* root)
{
if (root == nullptr)
return nullptr;
while (root->_right != nullptr)
{
root = root->_right;
}
return root;
}
private:
Node* _root;
Node* _head;
};
}