文章目录
3.红黑树
3.1概念
红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出两倍,因而是接近平衡的。
3.2 性质
- 每个结点不是红色就是黑色
- 根节点是黑色的
- 如果一个节点是红色的,则它的两个孩子结点是黑色的, 说明树里面不能出现连续的红色节点
- 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点
- 每个叶子结点都是黑色的(此处的叶子结点指的是空结点), 这个性质是为了方便数树有几条路径
问题: 为什么满足上面的性质,红黑树就能保证:其最长路径中节点个数不会超过最短路径节点个数的两倍?
解答: 根据性质3和性质4可知, 如果有一颗红黑树, 那么它的最短路径应是全黑节点, 最长路径应是一红一黑节点交替
于是, 我们可以得到一个结论, 假设每条路径有N个黑色节点, 那么每条路径的节点个数为[N, 2N]. 这样就满足了问题红黑树的特征, 即
最长路径中节点个数不会超过最短路径节点个数的两倍
3.3 RBTree的实现
3.3.1 insert的框架
与前面的avl树类似
#pragma once
enum Color
{
RED,
BLACK
};
template<class K, class V>
struct RBTreeNode
{
RBTreeNode(const pair<K, V>& kv) : _kv(kv), _left(nullptr)
, _right(nullptr), _parent(nullptr), _bf(RED) {}
RBTreeNode<K, V>* _left;
RBTreeNode<K, V>* _right;
RBTreeNode<K, V>* _parent;
pair<K, V> _kv;
Color _color;
};
template<class K, class V>
class RBTree
{
typedef RBTreeNode<K, V> Node;
public:
bool insert(const pair<K, V>& kv)
{
// a. 树为空,则直接新增节点,赋值给root指针
if (_root == nullptr) {
_root = new Node(kv);
// 根节点是黑色的
_root->_color = BLACK;
return true;
}
// b. 树不空,按二叉搜索树性质查找插入位置,插入新节点
Node* cur = _root, * parent = nullptr;
while (cur) {
if (cur->_kv.first < kv.first) {
parent = cur;
cur = cur->_right;
}
else if (cur->_kv.first > kv.first) {
parent = cur;
cur = cur->_left;
}
else return false;
}
// cur为空,找到了一个合适的位置,此时需要链接,注意链接位置
cur = new Node(kv);
// cur->_color = ??
if (kv.first < parent->_kv.first) {
parent->_left = cur;
cur->_parent = parent;
}
else {
parent->_right = cur;
cur->_parent = parent;
}
// new code....
return true;
}
private:
Node* _root = nullptr;
};
3.3.2 insert的处理
新增节点, 选择红色, 因为黑色会影响其他路径
- 新增节点的父亲是黑色的, 不需要处理
- 新增节点的父亲是红色的, 需要处理
(变色)or(变色+旋转)规定cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点
情况1: cur为红,p为红,g为黑, u 存在且为红 \textcolor{red}{u存在且为红} u存在且为红
while (parent && parent->_color == RED) {
Node* grandparent = parent->_parent;
if (parent == grandparent->_left) {
Node* uncle = grandparent->_right;
// uncle存在且为红, 情况1
if (uncle && uncle->_color == RED) {
// g(b)
// p(r) u(r)
// c(r)
// 变色
parent->_color = uncle->_color = BLACK;
grandparent->_color = RED;
// 继续向上处理
cur = grandparent;
parent = cur->_parent;
}
}
}
// 处理后_root可能会变色, 在这里它置为黑色
_root = BLACK;
情况2:cur为红,p为红,g为黑, u 不存在 / u 存在且为黑 \textcolor{red}{u不存在/u存在且为黑} u不存在/u存在且为黑
while (parent && parent->_color == RED) {
Node* grandparent = parent->_parent;
if (parent == grandparent->_left) {
Node* uncle = grandparent->_right;
// uncle存在且为红, 情况1
if (uncle && uncle->_color == RED) {
// g(b)
// p(r) u(r)
// c(r)
// 变色
parent->_color = uncle->_color = BLACK;
grandparent->_color = RED;
// 继续向上处理
cur = grandparent;
parent = cur->_parent;
}
// uncle为黑或者不存在
else {
// cur在parent的左边, 情况2, 单旋
if (cur = parent->_left) {
// g(b)
// p(r) u(b)
// c(r)
RotateR(grandparent);
parent->_color = BLACK;
grandparent->_color = RED;
}
break;
}
}
}
// 处理后_root可能会变色, 在这里它置为黑色
_root = BLACK;
情况3:cur为红,p为红,g为黑, u 不存在 / u 存在且为黑 \textcolor{red}{u不存在/u存在且为黑} u不存在/u存在且为黑, cur的位置与前面不同
while (parent && parent->_color == RED) {
Node* grandparent = parent->_parent;
if (parent == grandparent->_left) {
Node* uncle = grandparent->_right;
// uncle存在且为红, 情况1
if (uncle && uncle->_color == RED) {
// g(b)
// p(r) u(r)
// c(r)
// 变色
parent->_color = uncle->_color = BLACK;
grandparent->_color = RED;
// 继续向上处理
cur = grandparent;
parent = cur->_parent;
}
// uncle为黑或者不存在
else {
// cur在parent的左边, 情况2, 单旋
if (cur = parent->_left) {
// g(b)
// p(r) u(b)
// c(r)
RotateR(grandparent);
parent->_color = BLACK;
grandparent->_color = RED;
}
// cur在parent的右边, 情况3, 双旋
else {
// g(b)
// p(r) u(b)
// c(r)
RotateL(parent);
RotateR(grandparent);
cur->_color = BLACK;
grandparent->_color = RED;
}
break;
}
}
}
// 处理后_root可能会变色, 在这里它置为黑色
_root = BLACK;
完善else条件
while (parent && parent->_color == RED) {
Node* grandparent = parent->_parent;
if (parent == grandparent->_left) {
Node* uncle = grandparent->_right;
// uncle存在且为红, 情况1
if (uncle && uncle->_color == RED) {
// g(b)
// p(r) u(r)
// c(r)
// 变色
parent->_color = uncle->_color = BLACK;
grandparent->_color = RED;
// 继续向上处理
cur = grandparent;
parent = cur->_parent;
}
// uncle为黑或者不存在
else {
// cur在parent的左边, 情况2, 单旋
if (cur = parent->_left) {
// g(b)
// p(r) u(b)
// c(r)
RotateR(grandparent);
parent->_color = BLACK;
grandparent->_color = RED;
}
// cur在parent的右边, 情况3, 双旋
else {
// g(b)
// p(r) u(b)
// c(r)
RotateL(parent);
RotateR(grandparent);
cur->_color = BLACK;
grandparent->_color = RED;
}
break;
}
}
// parent == grandparent->_right
else {
// uncle存在且为红, 情况1
if (uncle && uncle->_color == RED) {
// g(b)
// u(r) p(r)
// c(r)
// 变色
parent->_color = uncle->_color = BLACK;
grandparent->_color = RED;
// 继续向上处理
cur = grandparent;
parent = cur->_parent;
}
// uncle为黑或者不存在
else {
// cur在parent的右边, 情况2, 单旋
if (cur = parent->_right) {
// g(b)
// u(b) p(r)
// c(r)
RotateL(grandparent);
parent->_color = BLACK;
grandparent->_color = RED;
}
// cur在parent的右边, 情况3, 双旋
else {
// g(b)
// u(r) p(b)
// c(r)
RotateR(parent);
RotateL(grandparent);
cur->_color = BLACK;
grandparent->_color = RED;
}
break;
}
}
}
// 处理后_root可能会变色, 在这里它置为黑色
_root = BLACK;
return true;
3.3.3 中序遍历
void InOrder()
{
_InOrder(_root);
cout << endl;
}
void _InOrder(Node* root)
{
if (root == nullptr) return;
_InOrder(root->_left);
cout << root->_kv.first << ' ';
_InOrder(root->_right);
}
3.3.4检查是否平衡和获取树的高度
bool IsBalance()
{
if (_root == nullptr) return true;
// 违反规则2
if (_root->_color == RED) return false;
int refVal = 0; // 参考值, 记录某一条路径上的黑色节点的数量
Node* cur = _root;
while (cur) {
if (cur->_color == BLACK)
refVal++;
cur = cur->_left;
}
int blackNum = 0;
return Check(_root, refVal, blackNum);
}
bool Check(Node* root, const int& refVal, int blackNum)
{
if (root == nullptr) {
// cout << blackNum << endl;
if(blackNum == refVal)
return true;
else {
cout << "有路径黑色节点数量不一致" << endl;
return false;
}
}
if (root->_color == BLACK) blackNum++;
if (root->_color == RED && root->_parent->_color == RED) {
// 违反规则3
cout << "有连续的红色节点" << endl;
return false;
}
return Check(root->_left, refVal, blackNum)
&& Check(root->_right, refVal, blackNum);
}
int GetHeight()
{
return _GetHeight(_root);
}
int _GetHeight(Node* root)
{
if (root == nullptr) return 0;
int left = _GetHeight(root->_left);
int right = _GetHeight(root->_right);
return left > right ? left + 1 : right + 1;
}
3.4完整代码
#pragma once
#include <iostream>
#include <vector>
using namespace std;
enum Color
{
RED,
BLACK
};
template<class K, class V>
struct RBTreeNode
{
RBTreeNode(const pair<K, V>& kv) : _kv(kv), _left(nullptr)
, _right(nullptr), _parent(nullptr), _color(RED) {}
RBTreeNode<K, V>* _left;
RBTreeNode<K, V>* _right;
RBTreeNode<K, V>* _parent;
pair<K, V> _kv;
Color _color;
};
template<class K, class V>
class RBTree
{
typedef RBTreeNode<K, V> Node;
public:
bool insert(const pair<K, V>& kv)
{
// a. 树为空,则直接新增节点,赋值给root指针
if (_root == nullptr) {
_root = new Node(kv);
// 根节点是黑色的
_root->_color = BLACK;
return true;
}
// b. 树不空,按二叉搜索树性质查找插入位置,插入新节点
Node* cur = _root, *parent = nullptr;
while (cur) {
if (cur->_kv.first < kv.first) {
parent = cur;
cur = cur->_right;
}
else if (cur->_kv.first > kv.first) {
parent = cur;
cur = cur->_left;
}
else return false;
}
// cur为空,找到了一个合适的位置,此时需要链接,注意链接位置
cur = new Node(kv);
cur->_color = RED; // 新增节点给红色
if (parent->_kv.first < kv.first) {
parent->_right = cur;
cur->_parent = parent;
}
else {
parent->_left = cur;
cur->_parent = parent;
}
while (parent && parent->_color == RED) {
Node* grandparent = parent->_parent;
if (parent == grandparent->_left) {
Node* uncle = grandparent->_right;
// uncle存在且为红, 情况1
if (uncle && uncle->_color == RED) {
// g(b)
// p(r) u(r)
// c(r)
// 变色
parent->_color = uncle->_color = BLACK;
grandparent->_color = RED;
// 继续向上处理
cur = grandparent;
parent = cur->_parent;
}
// uncle为黑或者不存在
else {
// cur在parent的左边, 情况2, 单旋
if (cur == parent->_left) {
// g(b)
// p(r) u(b)
// c(r)
RotateR(grandparent);
parent->_color = BLACK;
grandparent->_color = RED;
}
// cur在parent的右边, 情况3, 双旋
else {
// g(b)
// p(r) u(b)
// c(r)
RotateL(parent);
RotateR(grandparent);
cur->_color = BLACK;
grandparent->_color = RED;
}
break;
}
}
// parent == grandparent->_right
else {
Node* uncle = grandparent->_left;
// uncle存在且为红, 情况1
if (uncle && uncle->_color == RED) {
// g(b)
// u(r) p(r)
// c(r)
// 变色
parent->_color = uncle->_color = BLACK;
grandparent->_color = RED;
// 继续向上处理
cur = grandparent;
parent = cur->_parent;
}
// uncle为黑或者不存在
else {
// cur在parent的右边, 情况2, 单旋
if (cur == parent->_right) {
// g(b)
// u(b) p(r)
// c(r)
RotateL(grandparent);
parent->_color = BLACK;
grandparent->_color = RED;
}
// cur在parent的左边, 情况3, 双旋
else {
// g(b)
// u(r) p(b)
// c(r)
RotateR(parent);
RotateL(grandparent);
cur->_color = BLACK;
grandparent->_color = RED;
}
break;
}
}
}
// 处理后_root可能会变色, 在这里它置为黑色
_root->_color = BLACK;
return true;
}
void InOrder()
{
_InOrder(_root);
cout << endl;
}
bool IsBalance()
{
if (_root == nullptr) return true;
// 违反规则2
if (_root->_color == RED) return false;
int refVal = 0; // 参考值, 记录某一条路径上的黑色节点的数量
Node* cur = _root;
while (cur) {
if (cur->_color == BLACK)
refVal++;
cur = cur->_left;
}
int blackNum = 0;
return Check(_root, refVal, blackNum);
}
// 获得树的高度
size_t GetHeight()
{
return _GetHeight(_root);
}
// 获得节点数
size_t GetSize()
{
return _GetSize(_root);
}
private:
Node* _root = nullptr;
protected:
// 新节点插入较高右子树的右侧---右右:左单旋
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
// 由于parent不一定是整棵树的根,后面更新subR的parent时需要用到parentParent
Node* parentParent = parent->_parent;
parent->_right = subRL;
// 注意,subRL可能为nullptr
if (subRL)
subRL->_parent = parent;
subR->_left = parent;
parent->_parent = subR;
if (parent == _root) {
_root = subR;
subR->_parent = nullptr;
}
// parent不是整棵树的根
else {
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;
subL->_right = parent;
parent->_parent = subL;
if (parent == _root) {
_root = subL;
subL->_parent = nullptr;
}
else {
if (parent == parentParent->_left)
parentParent->_left = subL;
else
parentParent->_right = subL;
subL->_parent = parentParent;
}
}
void _InOrder(Node* root)
{
if (root == nullptr) return;
_InOrder(root->_left);
cout << root->_kv.first << ' ';
_InOrder(root->_right);
}
bool Check(Node* root, const int& refVal, int blackNum)
{
if (root == nullptr) {
// cout << blackNum << endl;
if(blackNum == refVal)
return true;
else {
cout << "有路径黑色节点数量不一致" << endl;
return false;
}
}
if (root->_color == BLACK) blackNum++;
if (root->_color == RED && root->_parent->_color == RED) {
// 违反规则3
cout << "有连续的红色节点" << endl;
return false;
}
return Check(root->_left, refVal, blackNum)
&& Check(root->_right, refVal, blackNum);
}
size_t _GetHeight(Node* root)
{
if (root == nullptr) return 0;
size_t left = _GetHeight(root->_left);
size_t right = _GetHeight(root->_right);
return left > right ? left + 1 : right + 1;
}
size_t _GetSize(Node* root)
{
if (root == nullptr) return 0;
else return _GetSize(root->_left) + _GetSize(root->_right) + 1;
}
};