一、平衡二叉搜索树
对于map/multimap/set/multiset 这几个容器的共同点是:其底层都是按照二叉搜索树
来实现的。但是二叉搜索树有其自身的缺陷,假如往树中插入的元素有序或者接近有序,二叉树搜索树就会退化成单支树,时间复杂度会退化成O(N),因此map/set等关联式容器的底层结构是对二叉树进行了平衡,即采用二叉平衡搜索树来实现的。
二、AVLTree
二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下。因此,两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年发明了一种解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。
一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:
■1、它的左右子树是空树。
■2、右子树减去左子树的高度(简称平衡因子) 的绝对值不超过1(-1/0/1)。
如果一棵二叉搜索树是高度平衡的,它就是AVL树。如果它有n个结点,其高度可保持在 ,搜索时间复杂度O(log2N)。
1、AVL树节点的定义
template<class K,class V>
struct AVLTreeNode{
AVLTreeNode<K,V>* parent; //该节点的父节点
AVLTreeNode<K,V>* left; //该节点的左孩子
AVLTreeNode<K,V>* right; //该节点的右孩子
std::pair<K,V> kv;
int bf; //该节点的平衡因子
AVLTreeNode(const std::pair<K,V>& _kv)
:parent(nullptr),left(nullptr),right(nullptr),kv(_kv),bf(0)
{}
};
2、AVLTree的插入
AVLTree就是在二叉搜索树的基础上引入了平衡因子,因此AVLTree也可以看成是二叉搜索树。那么AVLTree的插入过程可以分两步:
■1、按照二叉搜索树的方式插入新节点。
■2、调整节点的平衡因子。
C++代码:
template<class K, class V>
struct AVLTree {
typedef AVLTreeNode<K, V> Node;
public:
pair<Node*,bool> insert(const pair<K, V>& kv){
if(root==nullptr){ //当root节点不存在时,创建节点
root=new Node(kv);
return make_pair(root,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 make_pair(cur,false); //节点已经存在,插入失败
}
}
cur=new Node(kv);
if(_parent->kv.first > kv.first){
_parent->left=cur;
cur->parent=_parent;
}else{
_parent->right=cur;
cur->parent=_parent;
}
Node* newNode=cur;//保存插入节点,因为调节平衡因子时要改变cur指针
//向上调节平衡因子
while(_parent){
//更新父亲节点的平衡因子
if(_parent->left==cur){
_parent->bf--;
}else{
_parent->bf++;
}
if(_parent->bf==0){//更新结束,达到平衡
break;
}else if(abs(_parent->bf)==1){ // 继续向上调整
cur=_parent;
_parent=_parent->parent;
}else if(abs(_parent->bf)==2){ //旋转
if(_parent->bf==2){
if(cur->bf==1){
RotateL(_parent);
}else{
RotateRL(_parent);
}
}else{
if(cur->bf==-1){
RotateR(_parent);
}else{
RotateLR(_parent);
}
}
break;
}else{
assert(false);
}
}
return make_pair(newNode,true);
}
private:
Node *root=nullptr;
}
3、AVLTree的旋转
如果在一棵原本平衡的AVLTree中插入一个新节点,可能造成不平横,此时必须调整树的结构,使之平衡化。根据节点插入位置的不同,AVLTree的旋转分为4种:
3.1、新节点插入较高左子树的左侧—左左:右单旋
下图在插入之前,AVLTree是平衡的,新节点插入到30的左子树(注意是:不是左孩子)中,30左子树增加了一层,导致以60为根的二叉树不平衡,要让60平衡,只能将60左子树的高度减少一层,右子树增加一层,即将左子树往上提,这样60转下来,因为60比30大,只能将其放在30的右子树,而如果30有右子树,右子树根的值一定大于30,小于60,只能将其放在60的左子树,旋转完成后,更新节点的平衡因子即可。
C++代码:
void RotateR(Node* _parent){
Node* subL=_parent->left;
Node* subLR=subL->right;
_parent->left=subLR;
if(subLR) //当subLR存在时
subLR->parent=_parent;
subL->right=_parent;
_parent->parent=subL;
Node* parentParent=_parent->parent;
if(_parent==root){ //如果父节点根节点,则更新根节点
root=subL;
root->parent=nullptr;
}else{
if(parentParent->left==_parent){ //如果父亲节点为祖父节点的左子树
parentParent->left=subL;
}else{ //如果父亲节点为祖父节点的右子树
parentParent->right=subL;
}
subL->parent=parentParent; //将子树和原来的祖父节点连接起来
}
subL->bf=_parent->bf=0; //更新平衡因子
}
3.2、新节点插入较高右子树的右侧—右右:左单旋
左单旋的情况和右单旋是类似的,所以这里就不具体分析了:
C++代码
void RotateL(Node* _parent){
Node* subR=_parent->right;
Node* subRL=subR->left;
_parent->right=subRL;
if(subRL)
subRL->parent=_parent;
subR->left=_parent;
_parent->parent=subR;
Node* parentParent=_parent->parent;
if(_parent==root){
root=subR;
subR->parent=nullptr;
}else{
if(parentParent->left==_parent){
parentParent->left=subR;
}else{
parentParent->right=subR;
}
subR->parent=parentParent;
}
_parent->bf=subR->bf=0;
}
3.3、新节点插入较高左子树的右侧—左右:先左单旋再右单旋
当新节点插入较高左子树的右侧时,则需要进行双旋转,如下图,我们可以进行复用上面的左旋和右旋转,我们需要旋转后保持搜索的特点,所以我们需要先进行左旋转,再进行右旋转。我们在旋转之后只需要调整节点的平衡因子即可:
C++代码:
void RotateLR(Node* _parent){
Node* subL=_parent->left; //先保存节点,为后面更新平衡因子做准备
Node* subLR=subL->right;
int bf=subLR->bf; //判断是上面三种情况的哪一种
RotateL(subL);
RotateR(_parent);
if(bf==1){
subLR->bf=_parent->bf=0;
subL->bf=-1;
}else if(bf==-1){
subLR=subL->bf=0;
_parent->bf=1;
}else{
subL->bf=subLR->bf=_parent->bf=0;
}
}
3.4、新节点插入较高右子树的左侧—右左:先右单旋再左单旋
右左双旋的情况和左右双旋是类似的,所以这里就不具体分析了一下是旋转的图:
C++代码:
void RotateRL(Node* _parent){
Node* subR=_parent->right;
Node* subRL-subR->left;
int bf=subRL->bf;
RotateR(subR);
RotateL(_parent);
if(bf==1){
_parent->bf=-1;
subR->bf=subRL->bf=0;
}else if(bf==-1){
_parent->bf=subRL->bf=0;
subR->bf=1;
}else{
subR->bf=subRL->bf=_parent->bf=0;
}
}
3.5、插入节点的整体代码
std::pair<Node*, bool> insert(const std::pair<K, V>& kv) {
if (root == nullptr) {
root = new Node(kv);
return make_pair(root, 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 make_pair(cur, false);
}
}
cur = new Node(kv);
if (_parent->kv.first > kv.first) {
_parent->left = cur;
cur->parent = _parent;
}
else {
_parent->right = cur;
cur->parent = _parent;
}
Node* newNode = cur;
while (_parent) {
if (cur == _parent->right) {
_parent->bf++;
}
else {
_parent->bf--;
}
if (_parent->bf==0) {
break;
}
else if (abs(_parent->bf) == 1) { //继续向上更新
cur = _parent;
_parent = _parent->parent;
}
else if (abs(_parent->bf) == 2) {
//旋转
if (_parent->bf == -2) {
if (cur->bf == -1) {
RotateR(_parent);
}
else {
RotateLR(_parent);
}
}
else {
if (cur->bf ==1) {
RotateL(_parent);
}
else {
RotateRL(_parent);
}
}
break;
}
else {
assert(false);
}
}
return make_pair(newNode,true);
}
void RotateR(Node* _parent) {
Node* subL = _parent->left;
Node* subLR = subL->right;
_parent->left = subLR;
if (subLR) //subLR不为空节点
subLR->parent = _parent;
Node* parentParent = _parent->parent;
subL->right = _parent;
_parent->parent = subL;
if (_parent == root) { //走到根节点,根节点的父亲节点为空
root = subL;
}
else {
if (parentParent->left == _parent) {
parentParent->left = subL;
}
else {
parentParent->right = subL;
}
}
subL->parent = parentParent;
subL->bf = _parent->bf = 0;
}
void RotateL(Node* _parent) {
Node* subR = _parent->right;
Node* subRL = subR->left;
_parent->right = subRL;
if (subRL)
subRL->parent = _parent;
Node* parentParent = _parent->parent;
subR->left = _parent;
_parent->parent = subR;
if (_parent == root) {
root = subR;
}
else {
if (parentParent->left == _parent) {
parentParent->left = subR;
}
else {
parentParent->right = subR;
}
}
subR->parent = parentParent;
subR->bf = _parent->bf = 0;
}
void RotateLR(Node* _parent) {
Node* subL = _parent->left;
Node* subLR = subL->right;
int bf = subLR->bf;
RotateL(subL);
RotateR(_parent);
if (bf == 1) {
subL->bf = -1;
subLR->bf = 0;
_parent->bf = 0;
}
else if (bf == -1) {
subL->bf = 0;
subLR->bf = 0;
_parent->bf = 1;
}
else if(bf == 0){
subL->bf = subLR->bf = _parent->bf = 0;
}
else {
assert(false);
}
}
void RotateRL(Node* _parent) {
Node* subR = _parent->right;
Node* subRL = subR->left;
int bf = subRL->bf;
RotateR(subR);
RotateL(_parent);
if (bf == 1) {
subR->bf = 0;
_parent->bf = -1;
subRL->bf = 0;
}
else if (bf == -1) {
subR->bf = 1;
_parent->bf = 0;
subRL->bf = 0;
}
else if(bf==0){
subR->bf = subRL->bf = _parent->bf = 0;
}
else {
assert(false);
}
}
4、AVLTree的验证
AVL树是在二叉搜索树的基础上加入了平衡性的限制,因此要验证AVL树,可以分两步:
■ 1、验证是二叉搜索树:中序遍历是有序。
void _InOrder(Node* root) {
if (!root)
return;
_InOrder(root->left);
cout << root->kv.first << ' ' << root->bf << endl;
_InOrder(root->right);
}
void InOrder() {
_InOrder(root);
}
■ 2、验证其为平衡树:每个节点子树的左右高度差绝对值不超过1。
利用后序遍历:验证每个节点子树的左右高度差绝对值不超过1。
bool isBalance() {
return _isBalance(root)!=-1;
}
int _isBalance(Node* root) {
if (!root) return 0;
int left = _isBalance(root->left);
if (left == -1) return -1;
int right = _isBalance(root->right);
if (right == -1) return -1;
if (abs(right - left) > 1) return -1;
return max(left, right) + 1;
}
5、AVLTree的性能
AVLTree是一棵绝对平衡的二叉搜索树,其要求每个节点的左右子树高度差的绝对值不超过1,这样可以保证查询时的高效速度,即(log2N)。但是如果要对AVLTree做一些结果的修改操作,性能非常低下。比如:插入时要维护其绝对平衡,旋转次数太多,更差的是在删除的时候有可能一直要让旋转持续到根的位置。因此:如果需要一种
查询高效且有序
的数据结构,而且数据的个数为静态的(即不会改变),可以考虑AVL树,但一个结构经常修改,就不太适合。
6、AVLTree的拷贝构造、析构函数、拷贝赋值运算符重载、[]重载
template<class K, class V>
struct AVLTree {
typedef AVLTreeNode<K, V> Node;
public:
AVLTree() = default;
AVLTree(const AVLTree<K, V>& t) {
deleteNode(root);
root=copyNode(t.root);
}
Node* copyNode(Node* const sNode) {
if (!sNode) return nullptr;
Node* root = new Node(sNode->kv);
root->bf = sNode->bf;
root->left = copyNode(sNode->left);
if (root->left) root->left->parent = root;
root->right = copyNode(sNode->right);
if (root->right) root->right->parent = root;
return root;
}
V& operator[](const K& key) {
return ((*(insert(make_pair(key, V())).first)).kv).second;
}
AVLTree<K, V>& operator=(AVLTree<K, V> t) {
swap(root,t.root);
return *this;
}
//使用后序遍历析构节点
~AVLTree() {
deleteNode(root);
}
void deleteNode(Node* root) {
if (!root) return;
deleteNode(root->left);
deleteNode(root->right);
delete root;
}
};
三、红黑树
3.1红黑树的概念
红黑树是一种二叉搜索树
,但在每个节点上增加一个存储位表示节点的颜色,可以是Red或Black
。通过对任何一条从根到叶子的路径上各个节点着色方式的限制,红黑树确保没有一条路径会比其他路径长出两倍
,因而是接近平衡的。
3.2红黑树的性质
■1、每个节点不是红色就是黑色。
■2、根节点是黑色。
■3、没有连续的两个节点都是红节点。
■4、对于每个节点,从该节点到其所有后代叶节点(空节点)的简单路径上,均包含相同数量的黑色节点
■5、 每个叶子结点都是黑色的(此处的叶子结点指的是空结点(NIL))。
3.3 问题
为什么满足上面的性质,红黑树就能保证:其最长路径中节点个数不会超过最短路径节点个数的两倍?
对于性质4:从根节点到叶子节点的黑色节点都是相同的。所以最短路径为全黑。又由于性质2和性质3:根节点为黑色,没有连续的两个节点都是红节点,所以最长路径只能是一黑一红,最终红节点和黑节点相等。所以满足上面的性质,就能保证最长路径中节点个数不会超过最短路径节点个数的两倍。
3.4 红黑树节点的定义
同样我们红黑树的定义和AVLTree节点一样的,只是把平衡因子改为了颜色属性。
enum Color {
RED,
BLACK
};
template<class K, class V>
struct RBTreeNode {
RBTreeNode<K, V>* left;
RBTreeNode<K, V>* right;
RBTreeNode<K, V>* parent;
pair<K, V> kv;
enum Color col;
RBTreeNode(const pair<K, V>& _kv)
:left(nullptr), right(nullptr), parent(nullptr), kv(_kv), col(RED)
{}
};
为什么默认节点定义为红色?
因为我们每条路径上的黑节点是相同的,如果默认增加一个节点是黑色的话,那么增加节点的路径中黑节点增加了,不能满足性质4。所以我们默认增加一个节点为红节点。
3.5 红黑树的插入操作
3.5.1 按照二叉搜索树的规则插入节点
template<class K, class V>
struct RBTree {
typedef RBTreeNode<K, V> Node;
public:
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* _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 make_pair(cur, false);
}
}
cur = new Node(kv);
if (_parent->kv.first > kv.first) {
_parent->left = cur;
cur->parent = _parent;
}
else {
_parent->right = cur;
cur->parent = _parent;
}
Node* newNode = cur; //cur在执行下面第二点的代码时,有可能会改变cur节点所以先保留下来
//第二点:检测新节点插入后,红黑树的性质是否造到破坏
root->col = BLACK;//在执行第二点的代码时有可能将根节点的颜色改变,所以在最后将根节点的颜色改为黑色即可。
return make_pair(newNode, true);
}
private:
Node* root=nullptr;
};
3.5.2 检测新节点插入后,红黑树的性质是否造到破坏
因为新节点的默认颜色是红色,因此:如果双亲节点的颜色是黑色,没有违反红黑树任何性质,不需要做任何调整;但是当新插入节点的双亲节点颜色是红色时:就违反了性质3(不能有连续的两个红节点):此时要分类讨论:
约定:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点。
以下图中:我省略了当前节点指向父亲节点的指针,只保留了当前节点指向左右子节点的指针。对于下面的图中有可能是一棵子树也有可能是一棵完整的树。
以下代码中:我以父节点为祖父节点的左节点为例子。
情况1:cur为红,p为红,g为黑,u存在且为红。
C++代码:
Node* uncle = grandfather->right;
if (uncle && uncle->col == RED) {
//调整颜色
_parent->col = uncle->col = BLACK;
grandfather->col = RED;
//继续向上调整
cur = grandfather;
_parent = cur->parent;
}
情况2:cur为红,p为红,g为黑,u不存在或u存在且为黑。
cur的情况一:1、当p为g的左子树,cur为p的左子树。2、当p为g的右子树,cur为p的右子树。
cur的情况二:1、当p为g的左子树,cur为p的右子树。2、当p为g的右子树,cur为p的左子树。
C++代码
else {
//cur为情况一:
if (cur == _parent->left) {
RotateR(grandfather);
_parent->col = BLACK;
grandfather->col = RED;
}
else { //cur为情况二:
RotateL(_parent);
RotateR(grandfather);
cur->col = BLACK;
grandfather->col = RED;
}
break; //不需要再向上调整了
}
//旋转的代码,其中旋转的逻辑和AVLTree的旋转是相同的,只是这里面没有对平衡因子的调节,其他逻辑全都是一样的
void RotateR(Node* _parent) {
Node* subL = _parent->left;
Node* subLR = subL->right;
_parent->left = subLR;
if (subLR)
subLR->parent = _parent;
Node* parentParent = _parent->parent;
subL->right = _parent;
_parent->parent = subL;
if (_parent == root) {
root = subL;
}
else {
if (_parent == parentParent->left) {
parentParent->left = subL;
}
else {
parentParent->right = subL;
}
}
subL->parent = parentParent;
}
void RotateL(Node* _parent) {
Node* subR = _parent->right;
Node* subRL = subR->left;
_parent->right = subRL;
if (subRL)
subRL->parent = _parent;
Node* parentParent = _parent->parent;
subR->left = _parent;
_parent->parent = subR;
if (_parent == root) {
root = subR;
}
else {
if (parentParent->left == _parent) {
parentParent->left = subR;
}
else {
parentParent->right = subR;
}
}
subR->parent = parentParent;
}
调整颜色和旋转的整体代码
while (_parent && _parent->col == RED) {
Node* grandfather = _parent->parent;
//父节点为祖父节点的左子树
if (grandfather->left == _parent) {
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);
_parent->col = BLACK;
grandfather->col = RED;
}
else {
RotateL(_parent);
RotateR(grandfather);
cur->col = BLACK;
grandfather->col = RED;
}
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 (_parent->right == cur) {
RotateL(grandfather);
grandfather->col = RED;
_parent->col = BLACK;
}
else {
RotateR(_parent);
RotateL(grandfather);
cur->col = BLACK;
grandfather->col = RED;
}
break;
}
}
}
}
void RotateR(Node* _parent) {
Node* subL = _parent->left;
Node* subLR = subL->right;
_parent->left = subLR;
if (subLR)
subLR->parent = _parent;
Node* parentParent = _parent->parent;
subL->right = _parent;
_parent->parent = subL;
if (_parent == root) {
root = subL;
}
else {
if (_parent == parentParent->left) {
parentParent->left = subL;
}
else {
parentParent->right = subL;
}
}
subL->parent = parentParent;
}
void RotateL(Node* _parent) {
Node* subR = _parent->right;
Node* subRL = subR->left;
_parent->right = subRL;
if (subRL)
subRL->parent = _parent;
Node* parentParent = _parent->parent;
subR->left = _parent;
_parent->parent = subR;
if (_parent == root) {
root = subR;
}
else {
if (parentParent->left == _parent) {
parentParent->left = subR;
}
else {
parentParent->right = subR;
}
}
subR->parent = parentParent;
}
插入节点的整体代码
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* _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 make_pair(cur, false);
}
}
cur = new Node(kv);
if (_parent->kv.first > kv.first) {
_parent->left = cur;
cur->parent = _parent;
}
else {
_parent->right = cur;
cur->parent = _parent;
}
Node* newNode = cur;
while (_parent && _parent->col == RED) {
Node* grandfather = _parent->parent;
if (grandfather->left == _parent) {
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);
_parent->col = BLACK;
grandfather->col = RED;
}
else {
RotateL(_parent);
RotateR(grandfather);
cur->col = BLACK;
grandfather->col = RED;
}
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 (_parent->right == cur) {
RotateL(grandfather);
grandfather->col = RED;
_parent->col = BLACK;
}
else {
RotateR(_parent);
RotateL(grandfather);
cur->col = BLACK;
grandfather->col = RED;
}
break;
}
}
}
root->col = BLACK;
return make_pair(newNode, true);
}
void RotateR(Node* _parent) {
Node* subL = _parent->left;
Node* subLR = subL->right;
_parent->left = subLR;
if (subLR)
subLR->parent = _parent;
Node* parentParent = _parent->parent;
subL->right = _parent;
_parent->parent = subL;
if (_parent == root) {
root = subL;
}
else {
if (_parent == parentParent->left) {
parentParent->left = subL;
}
else {
parentParent->right = subL;
}
}
subL->parent = parentParent;
}
void RotateL(Node* _parent) {
Node* subR = _parent->right;
Node* subRL = subR->left;
_parent->right = subRL;
if (subRL)
subRL->parent = _parent;
Node* parentParent = _parent->parent;
subR->left = _parent;
_parent->parent = subR;
if (_parent == root) {
root = subR;
}
else {
if (parentParent->left == _parent) {
parentParent->left = subR;
}
else {
parentParent->right = subR;
}
}
subR->parent = parentParent;
}
3.5 RBTree的验证
红黑树的验证分为两步:
1、检测其是否满足二叉搜索树(中序遍历有序)
bool IsOrder(Node* cur,Node* &prev){
if(!root) return true;
if(!IsOrder(cur->left,prev)) return false;
if(!prev) prev=cur;
else{
if(prev->val>=cur->val) return false;
prev=cur;
}
if(!IsOrder(cur->right,prev)) return false;
return true;
}
2、 检测其是否满足红黑树的性质
bool _CheckRedCol(Node* root) {
if (!root)return true;
if (root->col == RED && root->parent->col==RED) {
cout<<"违反规则:不能出现两个连续的红节点"<<endl;
return false;
}
return _CheckRedCol(root->left)&&_CheckRedCol(root->right);
}
bool _CheckBlackNum(Node* root,int &prev,int curNum) {
if (!root) {
if (!prev) {
prev = curNum;
}
else {
//检测每条路径上的节点的黑色节点是否相同
return prev == curNum;
}
return true;
}
if (root->col == BLACK) curNum++;
return _CheckBlackNum(root->left, prev, curNum) && _CheckBlackNum(root->right, prev, curNum);
}
bool IsBalance() {
if (root && root->col == RED) {
cout << "违反规则:根节点是黑色" << endl;
return false;
}
int prev = 0;
return _CheckRedCol(root) && _CheckBlackNum(root,prev,0);
}
3.6 RBTree与AVLTree的比较
RBTree和AVLTree都是高效的平衡二叉搜索树,
增删查改的时间复杂度都是O(log2N)
,红黑树不追求绝对的平衡,其只需保证最长路径不超过最短路径的两倍,相对而言,降低了插入和旋转的次数,所以在经常进行增删的结构中性能比AVLTree更优,而且红黑树实现比较简单,所以实际运用过程中红黑树更多。