一、红黑树名字的由来
首先要知道的就是红黑树名字的由来,像AVL树的由来是以发明它的大佬的名字命名的,红黑树的命名是它的结点不是红色就是黑色,因此以红黑树进行命名。先进行声明一点就是红黑树并不一定是一棵平衡树,最优的平衡树是AVL树,红黑树是通过颜色来控制这棵搜索树相对平衡的。
二、实现红黑树的规则
红黑树的实现规则:
- 第一条:每一个结点不是红色就是黑色。
- 第二条:根结点是黑色的。
- 第三条:如果一个结点是红色那么它的孩子一定是黑色,也就是说每一条路径上都不可能有连续的红色结点
- 第四条:对于任意一个结点,由该结点到其所有的简单路径上的黑色结点的数目都相同。
在这样的四条规则下会出现一个情况就是:最长路径不会超过最短路径的二倍。
下面需要证明的是为什么会出现这种情况呢?
其实很简单,就是每条路径都不可能出现连续的红色结点,这意味着,如果该路径存在红色结点,则该结点要么是叶子结点,要么是有两个黑色结点。这也表明,最长的路径一定是一黑一红交替出现。最短路径一定是全黑的。由于存在上面四条规则的束缚,这个结论一定是成立的。
不要说在黑色结点后面一直加黑色结点这种没有逻辑的话。第四条规则确保了每条路径上都有相同数量的黑色结点,这就不可能使得任意一条路径上的黑色结点无限多。
三、红黑树模拟实现
3.1、红黑树的效率分析
这两棵树都满足红黑树的规则,它们分别是两个极端,左边这棵树是只有黑色结点的一棵红黑树,他的结点数量一定是最少的满二叉树,而右边这棵树是结点数量最多的满二叉树。
也就是说,我们所有的红黑的结点数量都会介于这两种极端的二叉树之间,我们假设左边这棵树的高度为h那么右边这棵树的高度就为2 * h。也就是所结点数量为2^h - 1 <= N <= 2^2h - 1;也就是说这两种二叉树的效率都是O(logn)的。 这也是我们说的,虽然红黑树不和AVL树一样追求完全的平衡,但是它的效率依然很高。
3.2、模拟实现
3.2.1第一种情况:只进行变色处理即可达到平衡
分析一下这种情况,搜先再插入x结点指点,这棵树是满足红黑树的规则的也就是说在插入x结点之前这棵树是红黑树。插入了x结点后发现这棵树出现了红色结点相连的情况,这就不满足红黑树的规则了。需要进行调整。下面是调整的规则:
将先插入的结点定义为cur,分别找到他的parent,uncle,grandfather,然后进行下面的操作:即先判断parent是否为黑,如果为黑,就不用修改直接结束,如果为红,那就可以确定他一定有爷爷,并且爷爷一定为黑接下来就只是需要判断叔叔了。对于叔叔存在这样的三种情况,这三种情况的处理方式也是不一样的,第一种,叔叔存在且为红(就是图中这种)第二种叔叔存在且为黑,第三种,叔叔不存在。我们先来说图中这种的处理方法,就是将parent和uncle变黑,grandfather变红然后继续向上进行我们这种操作,直到cur不存在爷爷为止。我们发现他就满足我们红黑树的要求了,在这个过程中还会遇到其他的几种情况,下面我们来分开讲解。
if (uncle && uncle->_col == RED)
{
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
cur = grandfather;
parent = cur->_parent;
}
对于uncle存在且为黑的情况是这样的:uncle存在且为黑这种情况,c一定是由下面子树的爷爷变化来的,也就说uncle存在且为黑这种情况一定是经历了一次第一种情况。
反证法:如果c是新插入的结点的话,那么每一条路径上都有相同的黑色结点这一条规则就不满足,所以c不可能是新插入的结点。
RotateR(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
3.3.3、进行双旋的情况
uncle不存在:
uncle存在且为黑:
RotateL(parent);
RotateR(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
四、模拟实现的代码
#pragma once
#include<iostream>
#include<utility>
using namespace std;
namespace Code_Journey
{
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;
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:
bool insert(const pair<K, V>& kv)
{
// 1.插入结点
if (_root == nullptr)
{
_root = new Node(kv);
_root->_col = BLACK;
return 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 false;
}
}
cur = new Node(kv);
if (cur->_kv.first < parent->_kv.first) parent->_left = cur;
else parent->_right = cur;
// 更新cur结点的_parent成员
cur->_parent = parent;
cur->_col = RED;
// 如果parent存在并且颜色为红色就一定是需要进行处理的
// 第一就是parent存在且为红他就一定有爷爷,这个在分析
// 原理的时候说过了,这种需要进行更新的情况就只有uncle
// 是变化的。
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 (uncle == nullptr || uncle->_col == BLACK)
{
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 (uncle == nullptr || uncle->_col == BLACK)
{
if (cur == parent->_right)
{
RotateL(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
else
{
RotateR(parent);
RotateL(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
}
_root->_col = BLACK;
return true;
}
bool IsBalanceTree()
{
int ref = _BlackNodeNums(_root, 0);
// cout << ref << endl;
return _IsBalanceTree(_root, 0, ref);
}
void InOrder()
{
inorder(_root);
cout << endl;
}
int Height()
{
return _Height(_root);
}
Node* find(const K& key)
{
if (_root == nullptr)
{
return nullptr;
}
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;
}
size_t Size()
{
return size(_root);
}
private:
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
Node* ppnode = parent->_parent;
// 更新b子树
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
// 更新parent
subL->_right = parent;
parent->_parent = subL;
// 判断ppnode是否为空
if (parent == _root)
{
_root = subL;
subL->_parent = nullptr;
}
else
{
if (ppnode->_left == parent)
{
ppnode->_left = subL;
}
else
{
ppnode->_right = subL;
}
subL->_parent = ppnode;
}
}
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
Node* ppnode = parent->_parent;
// 更新b子树
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
// 更新parent
subR->_left = parent;
parent->_parent = subR;
// 判断ppnode是否为根结点
if (parent == _root)
{
_root = subR;
subR->_parent = nullptr;
}
else
{
if (ppnode->_left == parent)
{
ppnode->_left = subR;
}
else
{
ppnode->_right = subR;
}
subR->_parent = ppnode;
}
}
size_t size(Node* root)
{
if (root == nullptr)
{
return 0;
}
return size(root->_left) + size(root->_right) + 1;
}
int _Height(Node* root)
{
if (root == nullptr)
return 0;
int leftHeight = _Height(root->_left);
int rightHeight = _Height(root->_right);
return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}
bool _IsBalanceTree(Node* root, int size, int ref)
{
if (nullptr == root)
return true;
if (_root->_col == RED)
return false;
return _check(root, size, ref);
}
bool _check(Node* root, int size, int ref)
{
if (root == nullptr)
{
// 写到里面解决的就是空指针解引用的问题
if (size != ref)
{
return false;
}
return true;
}
if (root->_col == BLACK) size++;
if (root->_col == RED && root->_parent->_col == RED)
{
return false;
}
else
{
return true;
}
return _check(root->_left, size, ref) && _check(root->_right, size, ref);
}
int _BlackNodeNums(Node* root, int size)
{
if (root == nullptr)
{
return size;
}
if (root->_col == BLACK)
{
size++;
}
return _BlackNodeNums(root->_left, size);
}
void inorder(Node* root)
{
if (root == nullptr)
{
return;
}
inorder(root->_left);
cout << root->_kv.first << ' ';
inorder(root->_right);
}
private:
Node* _root = nullptr;
};
}