红黑树是应用的最多的二叉树之一,包括STL中的map和set,以及Linux的内核等等都使用到了红黑树。今天花了一下午的时间实现了红黑树的一些功能,主要是插入节点的情况分析(删除节点还在研究)。
首先红黑树的性质比较重要,这里就简单的说一下吧!
性质1. 节点是红色或黑色。
性质2. 根节点是黑色。
性质3. 每个叶节点是黑色的。
性质4. 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
性质5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
其中最重要的是最后两条,它的特性体现在这两条规则上,记住这两条规则后你就能比较清楚的理解红黑树了。
我设计的红黑树的节点的形式如下:
template<class K,class V>
struct RedBlackTreeNode
{
K _key; //键
V _val; //值
Color _color; //颜色
RedBlackTreeNode<K, V>* _parent; //父节点
RedBlackTreeNode<K, V>* _left; //左子节点
RedBlackTreeNode<K, V>* _right; //右子节点
RedBlackTreeNode(const K& key, const V& val)
: _key(key)
, _val(val)
, _color(Red)
, _parent(NULL)
, _left(NULL)
, _right(NULL)
{}
};
下面我就分析一下红黑树插入节点时候的情况。
常见的情况有上述几种,不过我这里只画出了一半(左半边),右半边和左半边对称,相信凭大家的能力,这点东西算不了什么,所以我们大概只需要考虑这几种情况就行了,在实现的时候将右半边加上就好了,下面我就给出代码,参考一下:
#pragma once
#include <iostream>
using namespace std;
enum Color
{
Red,
Black
};
template<class K,class V>
struct RedBlackTreeNode
{
K _key; //键
V _val; //值
Color _color; //颜色
RedBlackTreeNode<K, V>* _parent; //父节点
RedBlackTreeNode<K, V>* _left; //左子节点
RedBlackTreeNode<K, V>* _right; //右子节点
RedBlackTreeNode(const K& key, const V& val)
: _key(key)
, _val(val)
, _color(Red)
, _parent(NULL)
, _left(NULL)
, _right(NULL)
{}
};
template<class K,class V>
class RedBlackTree
{
typedef RedBlackTreeNode<K, V> Node;
public:
RedBlackTree()
:_root(NULL)
{}
void InOrder()
{
_InOrder(_root);
}
Node* Find(const K &key)
{
Node *cur = _root;
while (cur)
{
if (cur->_key == key)
{
return cur;
}
else if(key < cur->_key)
{
cur = cur->_left
}
else
{
cur = cur->_right;
}
}
return cur;
}
bool Insert(const K &key, const V &val)
{
if (_root == NULL)
{
_root = new Node(key, val);
_root->_color = Black;
return true;
}
//找插入点
Node *parent = NULL;
Node *cur = _root;
while (cur)
{
parent = cur;
if (cur->_key == key)
return false;
else if (cur->_key < key)
cur = cur->_right;
else
cur = cur->_left;
}
//连接节点
cur = new Node(key, val);
cur->_parent = parent;
if (parent->_key > key)
{
parent->_left = cur;
}
else
{
parent->_right = cur;
}
//根据红黑树条件调节
while (parent != _root && parent->_color == Red) //祖父节点存在且父节点为红色
{
Node* grandfa = parent->_parent;
if (grandfa->_left == parent)
{ //新插入节点位于grandfa的左子树
Node *uncle = grandfa->_right;
if (uncle && uncle->_color == Red)
{
grandfa->_color = Red;
parent->_color = Black;
uncle->_color = Black;
cur = grandfa;
if (cur == _root)
{//遍历到根了
break;
}
parent = cur->_parent;
//continue;
}
else
{
if (cur == parent->_right)
{//左单旋
_RotateL(parent);
cur = cur->_left;
parent = cur->_parent;
}
//右单旋
_RotateR(grandfa);
parent->_color = Black;
parent->_left->_color = Red;
parent->_right->_color = Red;
break;
}
}
else
{ //新插入节点位于grandfa的右子树
Node *uncle = grandfa->_left;
if (uncle && uncle->_color == Red)
{
grandfa->_color = Red;
parent->_color = Black;
uncle->_color = Black;
cur = grandfa;
if (cur == _root)
{
break;
}
parent = cur->_parent;
}
else
{
if (cur == parent->_left)
{ //右单旋
_RotateR(parent);
cur = cur->_right;
parent = cur->_parent;
}
//左单旋
_RotateL(grandfa);
parent->_color = Black;
parent->_left->_color = Red;
parent->_right->_color = Red;
break;
}
}
}
_root->_color = Black;
return true;
}
bool Remove(const K &key)
{
Node* pos = Find(key);
if (pos == NULL)
{
return false;
}
/*
未完成
*/
return true;
}
bool IsRight()
{
//统计一条路径上的黑色节点的个数
Node *cur = _root;
int blacknum = 0;
while (cur)
{
if (cur->_color == Black)
++blacknum;
cur = cur->_left;
}
return _CheckRBTree(_root,blacknum,0);
}
~RedBlackTree()
{}
protected:
bool _CheckRBTree(Node *root,int blacknum,int curblacknum)
{
if (root == NULL)
return true;
if (root->_color == Black)
{//黑色节点
++curblacknum;
}
else
{//红色节点
if (root->_parent && root->_parent->_color == Red)
{//不合要求
cout << "连续两个红色节点" << endl;
return false;
}
}
if (root->_left == NULL && root->_right == NULL)
{//叶子结点
if (curblacknum == blacknum)
return true;
return false;
}
return _CheckRBTree(root->_left,blacknum,curblacknum)
&& _CheckRBTree(root->_right,blacknum,curblacknum);
}
void _InOrder(Node *root)
{
if (root)
{
_InOrder(root->_left);
cout << "[" << root->_key << "," << root->_val << "] ";
_InOrder(root->_right);
}
}
void _RotateL(Node *&parent)
{ //左单旋
Node *subR = parent->_right;
Node *subRL = subR->_left;
if (subRL)
{ //如果存在
subRL->_parent = parent;
}
subR->_parent = parent->_parent;
parent->_parent = subR;
subR->_left = parent;
parent->_right = subRL;
parent = subR;
if (parent->_parent)
{
Node* grandfa = parent->_parent;
if (grandfa->_key > parent->_key)
grandfa->_left = parent;
else
grandfa->_right = parent;
}
else
{
_root = parent;
}
}
void _RotateR(Node *&parent)
{ //右单旋
Node* subL = parent->_left;
Node *subLR = subL->_right;
if (subLR)
{
subLR->_parent = parent;
}
subL->_parent = parent->_parent;
parent->_parent = subL;
subL->_right = parent;
parent->_left = subLR;
parent = subL;
if (parent->_parent)
{
Node *grandfa = parent->_parent;
if (grandfa->_key > parent->_key)
grandfa->_left = parent;
else
grandfa->_right = parent;
}
else
{
_root = parent;
}
}
protected:
Node *_root;
};
void TestRedBlackTree()
{
RedBlackTree<int, int> rb;
rb.Insert(3, 1);
rb.Insert(2, 1);
rb.Insert(1, 1);
rb.Insert(5, 1);
rb.Insert(8, 1);
rb.Insert(6, 1);
rb.Insert(7, 1);
rb.InOrder();
cout <<endl<< "isRBTree ? " << rb.IsRight() << endl;
}
这里我主要是实现的是红黑树的插入功能,以及中序遍历,以及检查红黑树是否正确,红黑树的删除还待研究一下,下次补充上来,大家对于上面的过程有什么问题可以给我留言,若是还有不足的地方也欢迎大家指出。