红黑树概念
总特征:任意节点到叶子节点的最长路径不超过最短路径的两倍
1.每个节点非红即黑
2.根节点为黑色
3.如果一个节点为红色,那么它的子节点必须是黑色(不能有连续的红节点)
4.对于某个节点来说,该节点到所有叶子节点的路径上的黑色节点数量相同
图片来自百度百科
话不多说,直接用C++实现红黑树的结构
整体结构
enum Colour
{
RED,
BLACK
};
template <class K, class V>
struct RBTreeNode
{
pair<K, V> _kv;
RBTreeNode* _left;
RBTreeNode* _right;
RBTreeNode* _parent;
Colour _col;
RBTreeNode(pair<K, V> kv)
:_kv(kv)
, _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _col(RED)
{}
};
template <class K, class V>
class RBTree
{
typedef RBTreeNode<K, V> Node;
public:
bool Insert(const pair<K, V>& kv);
bool IsRBTree();
void Inorder() { _Inorder(_root); }
void Leorder() { _Leorder(_root); }
private:
void RotateL(Node* root);
void RotateR(Node* root);
int _HeightGreater(Node* root);
int _HeightLess(Node* root);
bool _IsRBTree(Node* root, int k, int blackCount);
void _Inorder(Node* root);
void _Leorder(Node* root);
private:
Node* _root = nullptr;
};
插入的三种情况
插入节点颜色都是红色,因为如果插入节点为黑色,一定不符合任意节点到其所有叶子节点的黑色节点数量相同的规则,但插入节点为红色,可以根据红黑树的规则进行一定的调整,使其重新满足红黑树的性质
g是祖父节点,p是父节点,u是叔叔节点,cur可能是当前插入节点,也可能是a或b子树调整后的祖父节点
关于其中涉及到的旋转,在AVL的插入讲解这篇博客中有详细介绍
情况1
第一种情况:
- 如果p与u都是红色,将p与u改为黑色,g改为红色
- 如果g的父节点为黑(g可能是整棵树中的子树),调整结束
- 如果g的父节点为红,需要以g为cur向上继续调整
- 同理,如果p和u的位置调换,但u为红色,也是这样调整(就是上面的四种情况)
最后:
- 如果子树的根节点g为树的根节点,将其改为黑,退出更新
- 如果不是,则判断g的父节点是否为红
- 如果为红,将g作为新的cur,并且根据cur的位置更新出g,u,p的位置,根据情况继续进行更新
- 如果为黑,则退出更新
情况2
第二种情况:
- 如果u不存在,cur就是新插入的节点,以g为根节点进行右旋转(p为g的右子节点则进行左旋转),最后将p和g的颜色反转
- 如果u存在且为黑,那么cur不是新插入的节点,cur之前为黑(因为p为红,cur不可能为红),因为cur的子树调整导致了cur变红。这种情况下,调整方法与第一种是一样的。
为什么第一种情况可以直接将p和u变为黑? - 因为这样做不违反每条路径上的黑节点数量相同的规则,u和p都为红的情况下,将一条路径上的两节点颜色反转,所有路径的黑色节点的数量没有发生变化
- 但在u为黑的情况下,将p和u变黑,因为u本来就是黑的,所以只有某些路径的黑色节点数量增加,违反了第四条这个规则
总结:
- 只有在出现连续两个节点为红色时,才会进行调整。所以cur和parent一定为红
- 三种情况的判断关键在于:uncle节点的颜色
- 若u为红,则反转u,p和g的颜色,对应第一种情况
- 若u为黑,需要进行旋转以维持第四条规则,对应第二和三种情况
情况3
第三种情况:
- u为黑或不存在,p为g的左子节点,cur为p的右子节点
- 思路是往情况2靠,以cur为根节点进行左单旋,成为情况2,以情况2的方式旋转,变色
- 同理,p为g的右子节点,cur为p的左子节点,也是一样的
Insert代码
template <class K, class V>
bool RBTree<K, V>::Insert(const pair<K, V>& kv)
{
// 以搜索二叉树的规则插入
if (_root == nullptr)
{
_root = new Node(kv);
// 根节点为黑色
_root->_col = BLACK;
return true;
}
Node* cur = _root;
Node* parent = nullptr;
// 找合适的插入位置
while (cur)
{
if (kv.first < cur->_kv.first)
{
parent = cur;
cur = cur->_left;
}
else if (kv.first > cur->_kv.first)
{
parent = cur;
cur = cur->_right;
}
else
{
return false;
}
}
cur = new Node(kv);
// 判断该插入parent的哪边
if (kv.first < parent->_kv.first)
{
parent->_left = cur;
}
else
{
parent->_right = cur;
}
cur->_parent = parent;
// 插入结束
// 保持平衡
while (parent && parent->_col == RED) // 出现连续的红节点
{
Node* grandParent = parent->_parent;
assert(grandParent);
if (grandParent->_left == parent) // parent在祖父节点左边
{
Node* uncle = grandParent->_right;
// u为红色,一定要提前判断u是否存在
if (uncle && uncle->_col == RED)
{
uncle->_col = BLACK;
parent->_col = BLACK;
grandParent->_col = RED;
if (grandParent == _root)
{
grandParent->_col = BLACK;
return true;
}
else // grandParent不是根节点,但其父节点为黑色,也插入完成
{
if (grandParent->_parent && grandParent->_parent->_col == BLACK)
{
return true;
}
else // grandParent的父节点为红,出现连续红节点,更新节点,继续调整
{
cur = grandParent;
parent = cur->_parent;
}
}
} // end of if (uncle && uncle->_col == RED)
else // u不存在或者为黑
{
// cur在p的左边
if (cur == parent->_left)
{
RotateR(grandParent);
grandParent->_col = RED;
parent->_col = BLACK;
}
else // cur在p的右边,需要旋转成左边的情况
{
RotateL(parent);
RotateR(grandParent);
cur->_col = BLACK;
grandParent->_col = RED;
}
return true;
}
} // end of - if (grandParent->_left == parent)
else // p在grandParent的右边
{
Node* uncle = grandParent->_left;
assert(grandParent);
// u为红色
if (uncle && uncle->_col == RED)
{
uncle->_col = BLACK;
parent->_col = BLACK;
grandParent->_col = RED;
if (grandParent == _root)
{
_root->_col = BLACK;
return true;
}
else
{
if (grandParent->_parent && grandParent->_parent->_col == BLACK)
{
return true;
}
// 更新继续调整
else
{
cur = grandParent;
parent = cur->_parent;
}
}
} // end of if (uncle && uncle->_col == RED)
else // u不存在或者为黑
{
// cur在p的右边
if (cur == parent->_right)
{
RotateL(grandParent);
grandParent->_col = RED;
parent->_col = BLACK;
}
else // cur在p的右边,需要旋转成左边的情况
{
RotateR(parent);
RotateL(grandParent);
cur->_col = BLACK;
grandParent->_col = RED;
}
return true;
}
} // end of - else
}// end if - while
return true;
}
验证红黑树
先求出一条路径上的黑色节点数量blackCount,然后调用子函数,子函数递归整棵树,用k记录当前路径的黑色节点数量,遇到黑色节点k++,当遇到节点为空的情况,比较k与blackCount是否相等。
另外每次递归要判断
- 根节点是否是黑色
- 如果该节点为红色,且父节点存在,如果父节点也为红,不满足红黑树性质
- 求出节点到叶子节点的最短路径与最长路径,判断最短路径的两倍不能小于最长路径
template <class K, class V>
bool RBTree<K, V>::_IsRBTree(Node* cur, int k, int blackCount)
{
if (cur == nullptr)
{
if (blackCount != k)
{
cout << "路径上的黑色节点数量不相等" << endl;
return false;
}
return true;
}
if (_root->_col != BLACK)
{
cout << "根节点为红色" << endl;
return false;
}
// 求以cur为根节点的最小高度与最大高度
int less = _HeightLess(cur);
int greater = _HeightGreater(cur);
if (less * 2 < greater)
{
cout << "最长路径超过最短路径两倍" << endl;
return false;
}
if (cur->_col == RED && cur->_parent && cur->_parent->_col == RED)
{
cout << "出现连续红色节点" << endl;
return false; // 检查连续的红色节点
}
if (cur->_col == BLACK)
{
k++;
}
// 递归验证左右子树
return _IsRBTree(cur->_left, k, blackCount) && _IsRBTree(cur->_right, k, blackCount);
}
hpp所有代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
#include <utility>
#include <assert.h>
#include <queue>
enum Colour
{
RED,
BLACK
};
template <class K, class V>
struct RBTreeNode
{
pair<K, V> _kv;
RBTreeNode* _left;
RBTreeNode* _right;
RBTreeNode* _parent;
Colour _col;
RBTreeNode(pair<K, V> kv)
:_kv(kv)
, _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _col(RED)
{}
};
template <class K, class V>
class RBTree
{
typedef RBTreeNode<K, V> Node;
public:
bool Insert(const pair<K, V>& kv);
bool IsRBTree();
void Inorder() { _Inorder(_root); }
void Leorder() { _Leorder(_root); }
private:
void RotateL(Node* root);
void RotateR(Node* root);
int _HeightGreater(Node* root);
int _HeightLess(Node* root);
bool _IsRBTree(Node* root, int k, int blackCount);
void _Inorder(Node* root);
void _Leorder(Node* root);
private:
Node* _root = nullptr;
};
template <class K, class V>
bool RBTree<K, V>::Insert(const pair<K, V>& kv)
{
// 以搜索二叉树的规则插入
if (_root == nullptr)
{
_root = new Node(kv);
// 根节点为黑色
_root->_col = BLACK;
return true;
}
Node* cur = _root;
Node* parent = nullptr;
// 找合适的插入位置
while (cur)
{
if (kv.first < cur->_kv.first)
{
parent = cur;
cur = cur->_left;
}
else if (kv.first > cur->_kv.first)
{
parent = cur;
cur = cur->_right;
}
else
{
return false;
}
}
cur = new Node(kv);
// 判断该插入parent的哪边
if (kv.first < parent->_kv.first)
{
parent->_left = cur;
}
else
{
parent->_right = cur;
}
cur->_parent = parent;
// 插入结束
// 保持平衡
while (parent && parent->_col == RED) // 出现连续的红节点
{
Node* grandParent = parent->_parent;
assert(grandParent);
if (grandParent->_left == parent) // parent在祖父节点左边
{
Node* uncle = grandParent->_right;
// u为红色,一定要提前判断u是否存在
if (uncle && uncle->_col == RED)
{
uncle->_col = BLACK;
parent->_col = BLACK;
grandParent->_col = RED;
if (grandParent == _root)
{
grandParent->_col = BLACK;
return true;
}
else // grandParent不是根节点,但其父节点为黑色,也插入完成
{
if (grandParent->_parent && grandParent->_parent->_col == BLACK)
{
return true;
}
else // grandParent的父节点为红,出现连续红节点,更新节点,继续调整
{
cur = grandParent;
parent = cur->_parent;
}
}
} // end of if (uncle && uncle->_col == RED)
else // u不存在或者为黑
{
// cur在p的左边
if (cur == parent->_left)
{
RotateR(grandParent);
grandParent->_col = RED;
parent->_col = BLACK;
}
else // cur在p的右边,需要旋转成左边的情况
{
RotateL(parent);
RotateR(grandParent);
cur->_col = BLACK;
grandParent->_col = RED;
}
return true;
}
} // end of - if (grandParent->_left == parent)
else // p在grandParent的右边
{
Node* uncle = grandParent->_left;
assert(grandParent);
// u为红色
if (uncle && uncle->_col == RED)
{
uncle->_col = BLACK;
parent->_col = BLACK;
grandParent->_col = RED;
if (grandParent == _root)
{
_root->_col = BLACK;
return true;
}
else
{
if (grandParent->_parent->_col == BLACK)
{
return true;
}
// 更新继续调整
else
{
cur = grandParent;
parent = cur->_parent;
}
}
} // end of if (uncle && uncle->_col == RED)
else // u不存在或者为黑
{
// cur在p的右边
if (cur == parent->_right)
{
RotateL(grandParent);
grandParent->_col = RED;
parent->_col = BLACK;
}
else // cur在p的右边,需要旋转成左边的情况
{
RotateR(parent);
RotateL(grandParent);
cur->_col = BLACK;
grandParent->_col = RED;
}
return true;
}
} // end of - else
}// end if - while
return true;
}
template <class K, class V>
void RBTree<K, V>::RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
subR->_left = parent;
parent->_right = subRL;
Node* pparent = parent->_parent;
parent->_parent = subR;
if (subRL)
subRL->_parent = parent;
if (_root == parent)
{
_root = subR;
subR->_parent = nullptr;
}
else // 该子树是树的一部分
{
subR->_parent = pparent;
if (subR->_kv.first < pparent->_kv.first)
{
pparent->_left = subR;
}
else
{
pparent->_right = subR;
}
}
}
template <class K, class V>
void RBTree<K, V>::RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
subL->_right = parent;
parent->_left = subLR;
Node* pparent = parent->_parent;
parent->_parent = subL;
if (subLR)
subLR->_parent = parent;
if (_root == parent)
{
_root = subL;
subL->_parent = nullptr;
}
else
{
subL->_parent = pparent;
if (subL->_kv.first < pparent->_kv.first)
{
pparent->_left = subL;
}
else
{
pparent->_right = subL;
}
}
}
template <class K, class V>
int RBTree<K, V>::_HeightGreater(Node* root)
{
if (root == nullptr)
{
return 0;
}
int leftH = _HeightGreater(root->_left);
int rightH = _HeightGreater(root->_right);
return leftH > rightH ? 1 + leftH : 1 + rightH;
}
template <class K, class V>
int RBTree<K, V>::_HeightLess(Node* root)
{
if (root == nullptr)
{
return 0;
}
int leftH = _HeightLess(root->_left);
int rightH = _HeightLess(root->_right);
return leftH < rightH ? 1 + leftH : 1 + rightH;
}
template <class K, class V>
bool RBTree<K, V>::IsRBTree()
{
int blackCount = 0;
Node* cur = _root;
while (cur)
{
if (cur->_col == BLACK)
{
blackCount++;
}
cur = cur->_left;
}
int k = 0;
return _IsRBTree(_root, k, blackCount);
}
template <class K, class V>
bool RBTree<K, V>::_IsRBTree(Node* cur, int k, int blackCount)
{
if (cur == nullptr)
{
if (blackCount != k)
{
cout << "路径上的黑色节点数量不相等" << endl;
return false;
}
return true;
}
if (_root->_col != BLACK)
{
cout << "根节点为红色" << endl;
return false;
}
// 求以cur为根节点的最小高度与最大高度
int less = _HeightLess(cur);
int greater = _HeightGreater(cur);
if (less * 2 < greater)
{
cout << "最长路径超过最短路径两倍" << endl;
return false;
}
if (cur->_col == RED && cur->_parent && cur->_parent->_col == RED)
{
cout << "出现连续红色节点" << endl;
return false; // 检查连续的红色节点
}
if (cur->_col == BLACK)
{
k++;
}
// 递归验证左右子树
return _IsRBTree(cur->_left, k, blackCount) && _IsRBTree(cur->_right, k, blackCount);
}
template <class K, class V>
void RBTree<K, V>::_Inorder(Node* root)
{
if (root == nullptr)
return;
_Inorder(root->_left);
cout << root->_kv.first << ' ';
_Inorder(root->_right);
}
template <class K, class V>
void RBTree<K, V>::_Leorder(Node* root)
{
queue<Node*> q;
q.push(root);
int count = 1;
while (!q.empty())
{
while (count)
{
Node* top = q.front();
q.pop();
count--;
if (top)
{
q.push(top->_left);
q.push(top->_right);
cout << top->_col << ' ';
}
else
{
cout << "nullptr ";
}
}
count = q.size();
cout << endl;
}
}