这里我来提供两篇写的不错的文章供大家参考:
http://www.cnblogs.com/fornever/archive/2011/12/02/2270692.html
http://blog.csdn.net/chenhuajie123/article/details/11951777
http://www.cnblogs.com/v-July-v/archive/2011/01/03/2009187.html
红黑树是一棵二叉树,它的每个节点上增加了一个存储位来表示节点颜色,它保证根节点到每个叶子节点的最长路径总是不超过最短路径的二倍。
我们先来看看红黑树的性质:
1,红黑树的节点非黑即红;
2,根节点一定是黑色的;
3,对于每个节点,到他所有的子节点的每条路径上的黑节点数目总是相等的;
4,没有连续的红节点;
5,这里把NULL节点叫做叶子节点,每一个叶子节点都是黑色的。
下面主要来讲一下插入操作:
插入:
插入的五种情况(重点后三种):
1,插入节点为根节点;
2,父节点为黑;
3,父节点为红色,叔叔节点为红色;
4,父节点为红色,叔叔节点为黑/不存在(此时cur是P左孩子,P是g左孩子,或同时都为右孩子);
5,父节点为红色,叔叔节点为黑/不存在(cur是p左孩子,p是g右孩子,或cur是p右孩子,p是g左孩子)
下图是我画的,可以参考一下
对于情况1,只需将cur置为黑,因为他是根节点;
对于情况2,因为父节点是黑色,cur是红色,不需调整;
对于情况3,父节点为红,叔叔节点为红,此时只需将p和u置黑,g置红即可;
对于情况4,若均为左孩子,进行右单旋,若均为右孩子,进行左单旋,这里以右单旋为例,p改为黑,g改为红即可;
对于情况5,以cur是p左孩子,p是g右孩子为例,进行右单旋,(cur是p右孩子,p是g左孩子,进行左单旋)这时就成了情况4,继续按情况4处理。
下面我们用代码来继续讲解:
先从树的左单旋,右单旋开始
左单旋:
void RotateL(Node* parent)
{
Node* subR = parent->_rifht;
Node* subRL = subR->_left;
parent->_right = subRL;
if(subRL)
subRL->_parent = parent;
subR->_left = parent;
Node* pparent = parent->_parent;
parent->_parent = subR;
if(pparent == NULL) //parent为根节点
{
_root = subR;
subR->_parent = NULL;
}
else
{
if(pparent->_left == parent)
{
pparent->_left = subR;
subR->_parent = pparent;
}
else
{
pparent->_right = subR;
subR->_parent = pparent;
}
}
}
右单旋:
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
subL->_right = parent;
Node* pparent = parent->_parent;
parent->_parent = subL;
if (pparent == NULL)
{
_root = subL;
subL->_parent = NULL;
}
else
{
if (pparent->_left == parent)
{
pparent->_left = subL;
subL->_parent = pparent;
}
else
{
pparent->_right = subL;
subL->_parent = pparent;
}
}
}
左右旋转
void RotateLR(Node* parent)
{
RotateL(parent->_left);
RotateR(parent);
}
右左旋转
void RotateRL(Node* parent)
{
RotateR(parent->_right);
RotateL(parent);
}
下面我们来看看红黑树的插入:
bool Insert(const K& key,const V& value)
{
if (_root == NULL) //情况1
{
_root = new Node(key,value);
_root->_col = BLACK;
return true;
}
Node* cur = _root;
Node* parent = NULL;
while (cur)
{
if (key < cur->_key)
{
parent = cur;
cur = cur->_left;
}
else if (key > cur->_key)
{
parent = cur;
cur = cur->_right;
}
else
return false;
}
cur = new Node(key, value);
if (parent->_key > key)
{
parent->_left = cur;
}
else
{
parent->_right = cur;
}
cur->_parent = parent;
//插进节点后,进行调整
while (parent && parent->_col == RED) //调整的三种情况
{
Node* grandfather = parent->_parent; //父节点是红,爷爷节点肯定存在
if (grandfather->_left == parent)
{
Node* uncle = grandfather->_right; //定义叔叔节点(重点)
if(uncle && uncle->_col == RED) //情况3(只进行颜色调整)
{
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
cur = grandfather;
parent = cur->_parent;
}
else
{
//if (parent->_left == cur) // 情况4 : 同为左孩子(还有下面同为右孩子)
//{
// //右单旋
// RotateR(grandfather);
// grandfather->_col = RED;
// parent->_col = BLACK;
//}
//else //情况5 (p是g的左孩子,cur是p的右孩子)
//{
// //左右旋转
// RotateL(parent);
// swap(parent, cur);
// RotateR(grandfather);
// grandfather->_col = RED;
// parent->_col = BLACK;
//}
if (cur == parent->_right) //情况5
{
RotateL(parent);
swap(parent, cur);
}
// 情况4
RotateR(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
break;
}
}
else //grandfather->_right = parent
{
Node* uncle = grandfather->_left; //定义叔叔节点(重点)
if (uncle && uncle->_col == RED) //情况3(只进行颜色调整)
{
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
cur = grandfather;
parent = cur->_parent;
}
else
{
//if (parent->_right == cur) // 情况4 : 同为右孩子(还有上面同为左孩子)
//{
// //左单旋
// RotateL(grandfather);
// grandfather->_col = RED;
// parent->_col = BLACK;
//}
//else //情况5 (p是g的右孩子,cur是p的左孩子)
//{
// //右左旋转
// RotateR(parent);
// swap(parent, cur);
// RotateL(grandfather);
// grandfather->_col = RED;
// parent->_col = BLACK;
//}
if (cur == parent->_left) //情况5
{
RotateR(parent);
swap(parent, cur);
}
RotateL(grandfather); //情况4
parent->_col = BLACK;
grandfather->_col = RED;
break;
}
}
}
_root->_col = BLACK;
return true;
}
在红黑树插入工作完成后,我们就可以构建一棵红黑树,但是我们还得判断这棵树是否是真的红黑树,这就使得我们必须写一个函数,判断是否是红黑树。
在写之前,我们先分析一下,需要判断哪些条件:
1,根节点为黑;
2,不能出现连续红节点;
3,每条路径黑节点数相同。(以最左路径为标尺(黑节点数不一定是正确的),判断其他路径是否相等)
bool IsBalance()
{
if (_root == NULL)
return true;
if (_root && _root->_col == RED)
return false;
int numBlack = 0; //统计最左路径的黑节点数作为标尺
Node* cur = _root;
while (cur)
{
if (cur->_col == BLACK)
{
numBlack++;
}
cur = cur->_left;
}
int num = 0;
return _IsBalance(_root, num, numBlack);
}
//不能出现连续红节点,每条路径黑节点数等于标尺数
bool _IsBalance(Node* root, int num, int numBlack) //num:根节点到当前节点的黑节点数
{
if (root == NULL)
return true;
if (root->_col == RED && root->_parent->_col == RED)
return false;
if (root->_col == BLACK)
++num;
if (root->_left == NULL && root->_right == NULL)
{
if (num == numBlack)
return true;
else
return false;
}
return _IsBalance(root->_left, num, numBlack) && _IsBalance(root->_right, num, numBlack);
}
完整代码
#include<iostream>
using namespace std;
enum color
{
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;
int _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)
{}
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
subR->_left = parent;
Node* pparent = parent->_parent;
parent->_parent = subR;
if (pparent == NULL) //parent为根节点
{
_root = subR;
}
else
{
if (pparent->_left == parent)
{
pparent->_left = subR;
}
else
{
pparent->_right = subR;
}
}
subR->_parent = pparent;
}
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
subL->_right = parent;
Node* pparent = parent->_parent;
parent->_parent = subL;
if (pparent == NULL)
{
_root = subL;
_root->_parent = NULL;
}
else
{
if (pparent->_left == parent)
{
pparent->_left = subL;
}
else
{
pparent->_right = subL;
}
subL->_parent = pparent;
}
}
void RotateLR(Node* parent)
{
RotateL(parent->_left);
RotateR(parent);
}
void RotateRL(Node* parent)
{
RotateR(parent->_right);
RotateL(parent);
}
bool Insert(const K& key,const V& value)
{
if (_root == NULL) //情况1
{
_root = new Node(key,value);
_root->_col = BLACK;
return true;
}
Node* cur = _root;
Node* parent = NULL;
while (cur)
{
if (key < cur->_key)
{
parent = cur;
cur = cur->_left;
}
else if (key > cur->_key)
{
parent = cur;
cur = cur->_right;
}
else
return false;
}
cur = new Node(key, value);
if (parent->_key > key)
{
parent->_left = cur;
}
else
{
parent->_right = cur;
}
cur->_parent = parent;
//插进节点后,进行调整
while (parent && parent->_col == RED) //调整的三种情况
{
Node* grandfather = parent->_parent; //父节点是红,爷爷节点肯定存在
if (grandfather->_left == parent)
{
Node* uncle = grandfather->_right; //定义叔叔节点(重点)
if(uncle && uncle->_col == RED) //情况3(只进行颜色调整)
{
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
cur = grandfather;
parent = cur->_parent;
}
//if ((uncle && uncle->_col == BLACK) || (uncle == NULL)) 注意,这和上面是对立的,不能if
else
{
if (cur == parent->_right) //情况5
{
RotateL(parent);
swap(parent, cur);
}
// 情况4
RotateR(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
break;
}
}
else //grandfather->_right = parent
{
Node* uncle = grandfather->_left; //定义叔叔节点(重点)
if (uncle && uncle->_col == RED) //情况3(只进行颜色调整)
{
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
cur = grandfather;
parent = cur->_parent;
}
else
{
if (cur == parent->_left) //情况5
{
RotateR(parent);
swap(parent, cur);
}
RotateL(grandfather); //情况4
parent->_col = BLACK;
grandfather->_col = RED;
break;
}
}
}
_root->_col = BLACK;
return true;
}
void InOrder()
{
_InOrder(_root);
cout << endl;
}
void _InOrder(Node* root)
{
if (root == NULL)
return;
_InOrder(root->_left);
cout << root->_key << " ";
_InOrder(root->_right);
}
bool IsBalance()
{
if (_root == NULL)
return true;
if (_root && _root->_col == RED)
return false;
int numBlack = 0; //统计最左路径的黑节点数作为标尺
Node* cur = _root;
while (cur)
{
if (cur->_col == BLACK)
{
numBlack++;
}
cur = cur->_left;
}
int num = 0;
return _IsBalance(_root, num, numBlack);
}
//不能出现连续红节点,每条路径黑节点数等于标尺数
bool _IsBalance(Node* root, int num, int numBlack) //num:根节点到当前节点的黑节点数
{
if (root == NULL)
return true;
if (root->_col == RED && root->_parent->_col == RED)
return false;
if (root->_col == BLACK)
++num;
if (root->_left == NULL && root->_right == NULL)
{
if (num == numBlack)
return true;
else
return false;
}
return _IsBalance(root->_left, num, numBlack) && _IsBalance(root->_right, num, numBlack);
}
private:
Node* _root;
};
测试代码
void Test()
{
RBTree<int, int> t;
int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
//int a[] = {4, 2, 6, 1, 3, 5, 15, 7, 16, 14};
for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
{
t.Insert(a[i], i);
cout << a[i] << "IsBalance?" << t.IsBalance() << endl;
}
t.InOrder();
cout << "IsBalance?" << t.IsBalance() << endl;
}
应用场景
1,STL关联式容器Map,Set就是基于红黑树
2,Linux内核CFS进程调度策略
3,epoll核心数据结构(红黑树+就绪队列(链表))