红黑树特点:
1.根节点为黑色
2.每个红色节点的左右孩子为黑色节点,即无连续的红结点
3.每条路径上的黑色节点相等
4.最长路径不超过最短路径的二倍
创建红黑树,在插入节点后(默认插入节点颜色为红色),要对红黑树进行判断并调整
当父节点为红色(以下情况均是父节点为祖父节点左孩子,而父节点为祖父右孩子推理可得)
相关代码:
bool Insert(const K& key, const V& value)
{
if (_root == NULL)
{
_root = new Node(key, value);
_root->color = BLACK;
return true;
}
Node* root = _root;
Node* parent = NULL;
while (root)
{
if (root->_key > key)
{
parent = root;
root = root->_left;
}
else if (root->_key < key)
{
parent = root;
root = root->_right;
}
else
return false;
}
if (parent->_key > key)
{
root=parent->_left = new Node(key, value);
root->_parent = parent;
}
else
{
root = parent->_right = new Node(key, value);
root->_parent = parent;
}
//调整红黑树颜色
while (parent&&parent->color == RED)
{
Node* Gparent = parent->_parent;
if (Gparent->_left== parent)
{
Node* uncle = Gparent->_right;
//叔叔存在且为红 直接将叔叔和父节点变黑 为保证每条路径黑色节点数相等 将祖父节点变红
//若祖父节点为根节点则不变色
if (uncle&&uncle->color == RED)
{
parent->color = uncle->color = BLACK;
if (Gparent == _root)
break;
Gparent->color = RED;
root = Gparent;
parent = root->_parent;
}
//叔叔不存在或者存在且为黑
else
{
if (root == parent->_right)
{
RotateL(parent);
swap(root, parent);
//左旋后当前结点和父节点位置交换 为防止下面右旋(旋转父节点)对象错误,交换两节点
}
RotateR(Gparent);
//交换后变色处理
parent->color = BLACK;
Gparent->color = RED;
}
}
else
{
Node* uncle = Gparent->_left;
if (uncle&&uncle->color == RED)
{
parent->color = uncle->color = BLACK;
if (Gparent == _root)
break;
Gparent->color = RED;
root = Gparent;
parent = root->_parent;
}
else
{
if (root == parent->_left)
{
RotateR(parent);
swap(root, parent);
}
RotateL(Gparent);
parent->color = BLACK;
Gparent->color = RED;
}
}
}
return true;
}
红黑树创建完成后要判断当前树是否为红黑树
判断1.每条路径黑色节点是否相等
先找出一条路径的黑节点个数作为判断依据,再遍历这棵树每条路径
2.是否有连续的红节点
当前结点为红色时,其父节点一定存在,判断其父节点是否为红结点即可
相关代码:
bool _BCount(Node* cur, size_t Bcount, size_t n)//判断每条路径黑节点数是否相等
{
if (cur)
{
if (cur->color == BLACK)
n++;
if (cur->_left == NULL&&cur->_right == NULL)
{
if (n != Bcount)
return false;
}
_BCount(cur->_left, Bcount, n);
_BCount(cur->_right, Bcount, n);
}
return true;
}
bool _Rcont(Node* cur)//判断是否有连续红节点
{
if (cur)
{
if (cur->color == RED)
{
if (cur->_parent->color == RED)
return false;
}
_Rcont(cur->_left);
_Rcont(cur->_right);
}
return true;
}
红黑树完整代码:
#include<iostream>
#include<stack>
using namespace std;
enum Color{ RED, BLACK };
template < typename K, typename V>
struct REDTreeNode
{
REDTreeNode<K, V>* _left;
REDTreeNode<K, V>* _right;
REDTreeNode<K, V>* _parent;
Color color = RED;
K _key;
V _value;
REDTreeNode(const K& key, const V& value)
:_left(NULL)
, _right(NULL)
, _parent(NULL)
, _key(key)
, _value(value)
{}
};
template<typename K,typename V>
class RBTree
{
public:
typedef REDTreeNode<K, V> Node;
RBTree()
:_root(NULL)
{}
bool Insert(const K& key, const V& value)
{
if (_root == NULL)
{
_root = new Node(key, value);
_root->color = BLACK;
return true;
}
Node* root = _root;
Node* parent = NULL;
while (root)
{
if (root->_key > key)
{
parent = root;
root = root->_left;
}
else if (root->_key < key)
{
parent = root;
root = root->_right;
}
else
return false;
}
if (parent->_key > key)
{
root=parent->_left = new Node(key, value);
root->_parent = parent;
}
else
{
root = parent->_right = new Node(key, value);
root->_parent = parent;
}
//调整红黑树颜色
while (parent&&parent->color == RED)
{
Node* Gparent = parent->_parent;
if (Gparent->_left== parent)
{
Node* uncle = Gparent->_right;
//叔叔存在且为红 直接将叔叔和父节点变黑 为保证每条路径黑色节点数相等 将祖父节点变红
//若祖父节点为根节点则不变色
if (uncle&&uncle->color == RED)
{
parent->color = uncle->color = BLACK;
if (Gparent == _root)
break;
Gparent->color = RED;
root = Gparent;
parent = root->_parent;
}
//叔叔不存在或者存在且为黑
else
{
if (root == parent->_right)
{
RotateL(parent);
swap(root, parent);
//左旋后当前结点和父节点位置交换 为防止下面右旋(旋转父节点)对象错误,交换两节点
}
RotateR(Gparent);
//交换后变色处理
parent->color = BLACK;
Gparent->color = RED;
}
}
else
{
Node* uncle = Gparent->_left;
if (uncle&&uncle->color == RED)
{
parent->color = uncle->color = BLACK;
if (Gparent == _root)
break;
Gparent->color = RED;
root = Gparent;
parent = root->_parent;
}
else
{
if (root == parent->_left)
{
RotateR(parent);
swap(root, parent);
}
RotateL(Gparent);
parent->color = BLACK;
Gparent->color = RED;
}
}
}
return true;
}
void RotateL(Node* root)
{
_RotateL(root);
}
void RotateR(Node* root)
{
_RotateR(root);
}
bool IsRBTree()//无连续红节点,每天路径黑节点数相等,头节点为黑
{
if (_root->color !=BLACK)
return false;
Node* root = _root;
size_t Bcount = 0;
size_t n = 0;
while (root)
{
if (root->color == BLACK)
Bcount++;
root = root->_left;
}
return _IsRBTree(_root, Bcount,n);
}
void InOrder()
{
_InOrder(_root);
}
protected:
void _InOrder(Node* root)
{
if (root == NULL)
return;
_InOrder(root->_left);
cout << root->_key << " ";
_InOrder(root->_right);
}
bool _BCount(Node* cur, size_t Bcount, size_t n)
{
if (cur)
{
if (cur->color == BLACK)
n++;
if (cur->_left == NULL&&cur->_right == NULL)
{
if (n != Bcount)
return false;
}
_BCount(cur->_left, Bcount, n);
_BCount(cur->_right, Bcount, n);
}
return true;
}
bool _Rcont(Node* cur)
{
if (cur)
{
if (cur->color == RED)
{
if (cur->_parent->color == RED)
return false;
}
_Rcont(cur->_left);
_Rcont(cur->_right);
}
return true;
}
bool _IsRBTree(Node* root, size_t Bcount,size_t n)
{
if (false == _BCount(root, Bcount, n))//判断每条路径黑节点数是否相等
return false;
if (false == _Rcont(root))//判断是否有连续红节点
return false;
return true;
}
void _RotateL(Node* root)//左旋
{
if (root == NULL)
return;
Node* subR = root->_right;
Node* subRL = subR->_left;
Node* ppNode = root->_parent;
subR->_left = root;
root->_parent = subR;
if (subRL)
{
root->_right = subRL;
subRL->_parent = root;
}
else
root->_right = NULL;
if (ppNode)
{
if (ppNode->_left == root)
ppNode->_left = subR;
else
ppNode->_right = subR;
subR->_parent = ppNode;
}
else
{
_root = subR;
_root->_parent = NULL;
}
}
void _RotateR(Node* root)//右旋
{
if (root == NULL)
return;
Node* subL = root->_left;
Node* subLR = subL->_right;
Node* ppNode = root->_parent;
subL->_right = root;
root->_parent = subL;
if (subLR)
{
root->_left = subLR;
subLR->_parent = root;
}
else
root->_left = NULL;
if (ppNode)
{
if (ppNode->_left == root)
ppNode->_left = subL;
else
ppNode->_right = subL;
subL->_parent = ppNode;
}
else
{
_root = subL;
_root->_parent = NULL;
}
}
private:
Node* _root;
};