数据结构之红黑树
一.什么是红黑树?
红黑树是一棵二叉搜索树,它在每个结点上增加了一个存储位来表示结点的颜色,可以是red或者black,通过对任何一条从根节点到叶子结点上的简单路径来约束,红黑树保证最长路径不超过最短路径的两倍,因而近似平衡。
二.红黑树满足的条件?
1. 每个结点不是红色就是黑色
2. 根节点是黑色的
3. 如果一个根节点是红色的,则它的两个叶子结点是黑色的(没有两个连续的红色结点)
4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点(每条路径上黑色结点的数量相等)
三.红黑树的插入操作详解
红黑树的情况分类
【情况一】
cur为红,p为红,g为黑,u存在且为红
则将p,u改为黑,g改为红,然后把g当成cur,继续向上调整。
【情况二】
cur为红,p为红,g为黑,u不存在/u为黑
p为g的左孩子,cur为p的左孩子,则进行右单旋转;相反,p为g的右孩子,cur
为p的右孩子,则进行左单旋转
p、g变色--p变黑,g变红
【情况三】
cur为红,p为红,g为黑,u不存在/u为黑
p为g的左孩子,cur为p的右孩子,则针对p做左单旋转;相
反,p为g的右孩子,cur为p的左孩子,则针对p做右单旋转
则转换成了情况2
具体如下图:
左单旋以及右单旋操作请见平衡二叉树:http://blog.youkuaiyun.com/sayhello_world/article/details/70231643
判断此树是否为平衡二叉树:
要满足上述条件
0. 如果根为空则就为平衡二叉树
1. 两个红色结点不能相连
2. 从根节点到任意叶子节点的黑色结点数目必须相同
bool CheckRBTree()
{
if (_pRoot == NULL)
return true;
if (_pRoot->_color == RED)
{
cout << "根为红色不满足" << endl;
return false;
}
//计算黑色结点的个数 应该每一条路径上数目都相同
int BlackCount = 0;
Node* pCur = _pRoot;
//只走最左边的那一条路
while (pCur)
{
if (pCur->_color == BLACK)
BlackCount++;
pCur = pCur->_pLeft;
}
int k = 0;
return _CheckRBTree(_pRoot,BlackCount,k);
}
bool _CheckRBTree(Node* pRoot,const size_t blackCount,size_t k)
{
if (pRoot == NULL)
return true;
//如果两个连续的红色 就违反规则
Node* Parent = pRoot->_pParent;
if (Parent && Parent->_color == RED && pRoot->_color == RED)
{
cout << "两个红色不能相连接" << endl;
return false;
}
//判断是否k=blackCount
//如果此时为黑色结点 k要++
if (pRoot->_color == BLACK)
k++;
if (pRoot->_pLeft == NULL && pRoot->_pRight == NULL)
{
if (k != blackCount)
{
cout << "违反两个黑色结点应该相同原则" << endl;
return false;
}
}
return _CheckRBTree(pRoot->_pLeft, blackCount, k) && _CheckRBTree(pRoot->_pRight, blackCount, k);
}
总代码:
BRTree.cpp
#pragma once
#include <iostream>
using namespace std;
enum Color
{
RED,
BLACK
};
template<class K, class V>
struct RBTreeNode
{
public:
RBTreeNode(const V&value, const K& key)
:_value(value)
, _key(value)
, _pLeft(NULL)
, _pRight(NULL)
, _pParent(NULL)
, _color(RED)//初始化为红色结点
{}
V _value;
K _key;
RBTreeNode<K, V>* _pLeft;
RBTreeNode<K, V>* _pRight;
RBTreeNode<K, V>* _pParent;
Color _color;
};
template < class K, class V>
class RBTree
{
typedef RBTreeNode<K, V> Node;
public:
RBTree()
:_pRoot(NULL)
{}
bool Insert(const K& key, const V& value)
{
//判断根节点是否为空
if (NULL == _pRoot)
{
_pRoot = new Node(key, value);
return false;
}
Node* pCur = _pRoot;
Node* pParent = NULL;
//找插入位置
while (pCur)
{
if (key > pCur->_key)
{
pParent = pCur;
pCur = pCur->_pRight;
}
else if (key < pCur->_key)
{
pParent = pCur;
pCur = pCur->_pLeft;
}
else
return false;
}
//插入结点
pCur = new Node(key, value);
if (key < pParent->_key)
pParent->_pLeft = pCur;
else if (key > pParent->_key)
pParent->_pRight = pCur;
pCur->_pParent = pParent;
//对结点的颜色进行处理
//从下往上修改颜色 到根节点且根节点为红结束
while (_pRoot != pCur && pParent->_color == RED)
{
Node* grandFather = pParent->_pParent;
if (pParent == grandFather->_pLeft)
{
Node* uncle = grandFather->_pRight;
//当前插得为红,双亲为红,叔叔也为红
//此时应该把祖先变为红,把双亲叔叔变为黑
if (uncle && uncle->_color == RED)
{
grandFather->_color = RED;
pParent->_color = BLACK;
uncle->_color = BLACK;
pCur = grandFather;
pParent = pCur->_pParent;
}
//否则叔叔不存在 或者叔叔为黑
else
{
//如果cur在父母的右边 则左单旋 再右单旋
if (pParent->_pRight == pCur)
{
RotateLeft(pParent);
std::swap(pParent, pCur);
}
//否则只右单旋
pParent->_color = BLACK;
grandFather->_color = RED;
RotateRight(grandFather);
}
}
//否则父母结点在祖先节点的右边
else
{
Node* uncle = grandFather->_pLeft;
if (uncle && uncle->_color == RED)
{
pParent->_color = BLACK;
uncle->_color = BLACK;
grandFather->_color = RED;
pCur = grandFather;
pParent = pCur->_pParent;
}
else
{
if (pCur == pParent->_pLeft)
{
RotateRight(pParent);
std::swap(pParent, pCur);
}
grandFather->_color = RED;
pParent->_color = BLACK;
RotateLeft(grandFather);
}
}
}
//最后要把根节点换成黑色的
_pRoot->_color = BLACK;
return true;
}
bool CheckRBTree()
{
if (_pRoot == NULL)
return true;
if (_pRoot->_color == RED)
{
cout << "根为红色不满足" << endl;
return false;
}
//计算黑色结点的个数 应该每一条路径上数目都相同
int BlackCount = 0;
Node* pCur = _pRoot;
//只走最左边的那一条路
while (pCur)
{
if (pCur->_color == BLACK)
BlackCount++;
pCur = pCur->_pLeft;
}
int k = 0;
return _CheckRBTree(_pRoot, BlackCount, k);
}
bool _CheckRBTree(Node* pRoot, const size_t blackCount, size_t k)
{
if (pRoot == NULL)
return true;
//如果两个连续的红色 就违反规则
Node* Parent = pRoot->_pParent;
if (Parent && Parent->_color == RED && pRoot->_color == RED)
{
cout << "两个红色不能相连接" << endl;
return false;
}
//判断是否k=blackCount
//如果此时为黑色结点 k要++
if (pRoot->_color == BLACK)
k++;
if (pRoot->_pLeft == NULL && pRoot->_pRight == NULL)
{
if (k != blackCount)
{
cout << "违反两个黑色结点应该相同原则" << endl;
return false;
}
}
return _CheckRBTree(pRoot->_pLeft, blackCount, k) && _CheckRBTree(pRoot->_pRight, blackCount, k);
}
void InOrder()
{
_InOrder(_pRoot);
}
private:
void _InOrder(Node* pRoot)
{
if (pRoot == NULL)
return;
_InOrder(pRoot->_pLeft);
cout << pRoot->_key << " ";
_InOrder(pRoot->_pRight);
}
void RotateLeft(Node*& pRoot)
{
Node* SubR = pRoot->_pRight;
Node* SubRL = SubR->_pLeft;
pRoot->_pRight = SubRL;
if (SubRL)
SubRL->_pParent = pRoot;
SubR->_pLeft = pRoot;
SubR->_pParent = pRoot->_pParent;
pRoot->_pParent = SubR;
pRoot = SubR;
if (pRoot->_pParent == NULL)
_pRoot = pRoot;
else if (pRoot->_pParent->_key > pRoot->_key)
pRoot->_pParent->_pLeft = pRoot;
else if (pRoot->_pParent->_key < pRoot->_key)
pRoot->_pParent->_pRight = pRoot;
}
void RotateRight(Node*& pRoot)
{
Node* SubL = pRoot->_pLeft;
Node* SubLR = SubL->_pRight;
pRoot->_pLeft = SubLR;
if (SubLR)
SubLR->_pParent = pRoot;
SubL->_pRight = pRoot;
SubL->_pParent = pRoot->_pParent;
pRoot->_pParent = SubL;
pRoot = SubL;
if (pRoot->_pParent == NULL)
_pRoot = pRoot;
else if (pRoot->_pParent->_key > pRoot->_key)
pRoot->_pParent->_pLeft = pRoot;
else if (pRoot->_pParent->_key < pRoot->_key)
pRoot->_pParent->_pRight = pRoot;
}
private:
Node* _pRoot;
};