红黑树:是一棵二叉搜索树,它在每个节点上增加了一个存储位来表示节点的颜色,可以是Red或Black。通过对任何一条从根到叶子简单路径上的颜色来约束,红黑树保证最长路径不超过最短路径的两倍,因而近似于平衡(由于性质中红色节点不连续,最短路径可为全是连续黑结点,最长路径则由于红节点不连续,则每间隔一个黑的插入一个红的节点,所以最长路径为两倍)。
它主要满足以下几个性质:
1. 每个节点,不是红色就是黑色的;
2. 根节点是黑色的;
3. 如果一个节点是红色的,则它的两个子节点是黑色的;
4. 对每个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点。
在这里主要实现红黑树的插入:插入时要满足红黑树的性质,方便下保证黑节点个数不变情况,只能插入红节点,然后则只需考虑是否红节点连续这一种情况,若连续,则进行调整。
插入红节点主要调整情况如下:
ps:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点
1.第一种情况cur为红,p为红,g为黑,u存在且为红
则将p,u改为黑,g改为红,然后把g当成cur,继续向上调整。
2.第二种情况(单旋)
cur为红,p为红,g为黑,u不存在/u为黑
p为g的左孩子,cur为p的左孩子,则进行右单旋转;相反,p为g的右孩子,cur为p的右孩子,则进行左单旋转p、g变色--p变黑,g变红
3.第三种情况(双旋)
cur为红,p为红,g为黑,u不存在/u为黑
p为g的左孩子,cur为p的右孩子,则针对p做左单旋转;相反,p为g的右孩子,cur为p的左孩子,则针对p做右单旋转则转换成了情况2
其中还有两种情况及树为空或父节点为黑色则直接插入或不处理无影响。
代码实现:并实现功能测试是否为红黑树代码IsBalance()
enum Colour
{
RED,
BLACK,
};
template<class K,class V>
struct RBTreeNode
{
K _key;
V _value;
Colour _col;
RBTreeNode<K,V>* _left;
RBTreeNode<K,V>* _right;
RBTreeNode<K,V>* _parent;
RBTreeNode(const K& key,const V& value)
:_key(key),_value(value),_col(RED)
,_left(NULL),_right(NULL),_parent(NULL)
{}
};
template<class K,class V>
class RBTree
{
typedef RBTreeNode<K,V> Node;
public:
RBTree()
:_root(NULL)
{}
bool Insret(const K& key,const V& value)
{
//若根为空直接插入新结点
if(_root==NULL)
{
_root=new Node(key,value);
_root->_col=BLACK;
return true;
}
//不为空找插入位置
Node* cur=_root;
Node* parent=NULL;
while(cur)
{
parent=cur;
if(cur->_key>key)
cur=cur->_left;
else if(cur->_key<key)
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;
}
//若父节点存在且为红色
while(parent&&parent->_col==RED)
{
Node* grandfather=parent->_parent;
if(grandfather->_left==parent)
{
Node* uncle=grandfather->_right;
//1.叔叔结点存在且为红结点时
if(uncle&&uncle->_col==RED)
{
parent->_col=uncle->_col=BLACK;
grandfather->_col=RED;
cur=grandfather;
parent=cur->_parent;
}
//2、3.叔叔结点不存在或叔叔结点为黑色时
else
{
if(cur==parent->_right)
{
RotateL(parent);
swap(cur,parent);
}
RotateR(grandfather);
grandfather->_col=RED;
parent->_col=BLACK;
break;
}
}
else
{
Node* uncle=grandfather->_left;
//1.叔叔结点存在且为红结点时
if(uncle&&uncle->_col==RED)
{
parent->_col=uncle->_col=BLACK;
grandfather->_col=RED;
cur=grandfather;
parent=cur->_parent;
}
//2、3.叔叔结点不存在或叔叔结点为黑色时
else
{
if(cur==parent->_left)
{
RotateR(parent);
swap(cur,parent);
}
RotateL(grandfather);
grandfather->_col=RED;
parent->_col=BLACK;
break;
}
}
}
_root->_col=BLACK;
return true;
}
bool IsBalance()//判断是否为红黑树
{
if(_root->_col==RED)
return false;
//统计最左路径黑结点个数,比较
size_t k=0;
Node* cur=_root;
while(cur)
{
if(cur->_col==BLACK)
++k;
cur=cur->_left;
}
size_t num=0;
return CheakColour(_root)&&CheakBlackNum(_root,k,num);
}
void Inorder()
{
_Inorder(_root);
cout<<endl;
}
~RBTree()
{
_Destroy(_root);
}
protected:
//检测红色节点是否有连续
bool CheakColour(Node* root)
{
if(root==NULL)
return true;
if(root->_col==RED&&(root->_parent)->_col==RED)
return false;
return CheakColour(root->_left)&&CheakColour(root->_right);
}
//检测各路径黑色节点个数是否相等
bool CheakBlackNum(Node* root,size_t k,size_t num)
{
if(root==NULL)
return true;
if(root->_col==BLACK)
++num;
if(root->_left==NULL&&root->_right==NULL&&k!=num)
return false;
return CheakBlackNum(root->_left,k,num)&&CheakBlackNum(root->_right,k,num);
}
void _Inorder(Node* root)
{
if(root==NULL)
return;
_Inorder(root->_left);
cout<<root->_key<<" ";
_Inorder(root->_right);
}
void _Destroy(Node* root)
{
if(root==NULL)
return;
_Destroy(root->_left);
_Destroy(root->_right);
delete root;
root=NULL;
}
private:
void RotateL(Node* parent)
{
Node* subR=parent->_right;
Node* subRL=subR->_left;
if(subRL)
subRL->_parent=parent;
parent->_right=subRL;
subR->_left=parent;
Node* ppNode=parent->_parent;
parent->_parent=subR;
if(ppNode==NULL)
{
_root=subR;
subR->_parent=NULL;
}
else
{
if(ppNode->_left==parent)
ppNode->_left=subR;
else
ppNode->_right=subR;
subR->_parent=ppNode;
}
}
void RotateR(Node* parent)
{
Node* subL=parent->_left;
Node* subLR=subL->_right;
if(subLR)
subLR->_parent=parent;
parent->_left=subLR;
subL->_right=parent;
Node* ppNode=parent->_parent;
parent->_parent=subL;
if(ppNode==NULL)
{
_root=subL;
subL->_parent=NULL;
}
else
{
if(ppNode->_left==parent)
ppNode->_left=subL;
else
ppNode->_right=subL;
subL->_parent=ppNode;
}
}
private:
Node* _root;
};
#include <iostream>
#include <cstdlib>
#include "RBTree.h"
using namespace std;
void testRBTree()
{
RBTree<int,int> t;
int arr[]={16,3,7,9,11,26,18,14};
//int arr[]={3,7,5,8,4,2,9,0};
for(int i=0;i<sizeof(arr)/sizeof(arr[0]);++i)
{
t.Insret(arr[i],i);
cout<<"IsBalance?: "<<t.IsBalance()<<endl;
}
t.Inorder();
cout<<"IsBalance?: "<<t.IsBalance()<<endl;
}
int main()
{
testRBTree();
system("pause");
return 0;
}