红黑树
红黑树是一颗二叉搜索树,它在每一个节点上增加了一个存储位来表示节点的颜色,可以是Red或是Black。通过对任何一条从根到叶子简单路径上的颜色的约束,红黑树保证最长路径不超过最短路径的两倍,因而近似平衡。
红黑树的性质
- 每个节点,不是红色就是黑色;
- 根节点是黑色;
- 如果一个节点是红色的,那么它的子节点都是黑色的;
- 对于每一个节点,从该节点到其多有的后代叶子节点的简单路径上,均包含相同数目的黑色节点。
插入
cur为红有两种情况:
- cur为新增节点
- cur不是新增节点,而是cur的子树新增节点,相当于调节完子树后cur为红,则需要再向上调整。
其中两种情况比较简单:
1.第一种情况:
树为空,cur是新插入的节点,cur为红,则需要将cur变为黑
2.第二种情况:
cur为红,P为黑,所以整个树的颜色都不用变
3. 第三种情况
cur为红,g为黑, p为红,u存在且为红.
调整后:
cur为红,g改为红, p.U改为黑.
4. 第四种情况
cur为红,g为黑, p为红,u不存在/u为黑.
调整后:
p.g变颜色—p变黑,g变红.
情况1:左单旋转
情况2:右单旋转
5. 第五种情况
cur为红,g为黑, p为红,u不存在/u为黑.
1. 而p为g的左孩子,cur为p的右孩子,则需要对p先做出左单旋转;
2. 而p为g的右孩子,cur为p的左孩子,则需要对p先做出右单旋转;最后将情况转为第二种情况。
1.
2.
代码实现:
#include<iostream>
using namespace std;
enum Colour
{
RED,
BLACK,
};
template<class K, class V>
struct RBTreeNode
{
RBTreeNode<K,V>* _left;
RBTreeNode<K,V>* _right;
RBTreeNode<K,V>* _parent;
K _key;
V _value;
Colour _col;
RBTreeNode(const K& key, const V& value)
:_left(NULL)
,_right(NULL)
,_parent(NULL)
,_key(key)
,_value(value)
,_col(RED)
{}
};
template <class K, class V>
class RBTree
{
typedef RBTreeNode<K,V> Node;
public:
RBTree()
:_root(NULL)
{}
bool Insert(const K& key, const V& value)
{
//1.为空则插入新节点 并且把颜色置为黑色
//2.不为空则找到要插入的位置
if(_root == NULL)
{
_root = new Node(key,value);
_root->_col = BLACK;
return true;
}
Node* cur = _root;
Node* parent = NULL;
while(cur)
{
if(cur->_key > key)
{
parent = cur;
cur = cur->_left;
}else if(cur->_key < key)
{
parent = cur;
cur = cur->_right ;
}else
{
return false;
}
}
//找到位置 插入新节点链起来
cur = new Node(key,value);
if(parent->_key > key)
{
parent->_left = cur;
cur->_parent = parent;
}else
{
parent->_right = cur;
cur->_parent = parent;
}
//检验规则
//1. parent 不为黑且parent存在
//2. cur 为红 parent为红 uncle存在且为红
//3. cur 为红 parent为红 uncle不存在或者存在为黑
while(parent && parent->_col == RED)
{
Node* grandfather = parent->_parent ;
if(parent == grandfather->_left )
{
Node* uncle = grandfather->_right ;
//uncle 存在且为红-----第2种情况
if(uncle && uncle->_col == RED)
{
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
//接着向上检查
cur = grandfather;
parent = cur->_parent ;
}
else //uncle 不存在或者存在且为黑-----第三种情况
{
if(cur = parent->_right )
{
RotateL(parent);
}
RotateR(grandfather);
}
}
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(cur = parent->_left )//右左双旋
{
RotateR(parent);
}
RotateL(grandfather);
}
}
}
_root->_col = BLACK;
return true;
}
void RotateR(Node* parent) //右单旋转
{
Node* subL = parent->_left ;
Node* subLR = subL->_right ;
Node* ppNode = parent->_parent ;
parent->_left = subLR;
if(subLR)
{
subLR->_parent = parent;
}
subL->_right = parent;
parent->_parent = subL;
if(ppNode == NULL)
{
_root = subL;;
subL->_parent = NULL;
}else if(ppNode->_left == parent)
{
ppNode->_left = subL;
subL->_parent = ppNode;
}else
{
ppNode->_right = subL;
subL->_parent = ppNode;
}
parent->_col = RED;
subL->_col = BLACK;
parent = subL;
}
void RotateL(Node* parent) //左单旋转
{
Node* subR = parent->_right ;
Node* subRL = subR ->_left ;
Node* ppNode = parent->_parent ;
parent->_right = subRL;
if(subRL)
{
subRL->_parent = parent;
}
subR->_left = parent;
parent->_parent = subR;
if(ppNode == NULL)
{
_root = subR;
subR->_parent = NULL;
}else if(ppNode->_left == parent)
{
ppNode->_left = subR;
subR->_parent = ppNode;
}else
{
ppNode->_right = subR;
subR->_parent = ppNode;
}
parent->_col = RED;
subR->_col = BLACK;
parent = subR;
}
void InOrder()
{
_InOrder(_root);
}
void _InOrder(Node* root)
{
if(root == NULL)
{
return;
}
_InOrder(root->_left );
cout<<root->_key <<" ";
_InOrder(root->_right );
}
bool IsBalance()
{
//通过规则来评定是否是红黑树
//1.根为黑
//2.每条路的黑节点相同 (可以从叶子节点向上遍历然后带回黑色节点的个数)
//3.红色不相邻
if(_root && _root->_col == RED)
{
return false;
}
int k = 0;
Node* cur = _root;
while(cur)
{
if(cur->_col == BLACK)
{
++k;
}
cur = cur->_left ;
}
int blacknum = 0;
return _IsBalance(_root,k,blacknum);
}
bool _IsBalance(Node* root,int k,int blacknum)
{
if(root == NULL)
{
if(k != blacknum)
{
cout<<"黑节点的个数不同"<<endl;
return false;
}
return true;
}
if(root->_col == RED && (root->_parent)->_col == RED)
{
cout<<"有连续的红节点"<<endl;
return false;
}
if(root->_col == BLACK)
{
blacknum++;
}
return _IsBalance(root->_left ,k,blacknum)&&_IsBalance(root->_right ,k,blacknum);
}
private:
Node* _root;
};