红黑树
红黑树(Red Black Tree)和AVL树类似,都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡。
红黑树是一颗二叉搜索树,它的每一个节点增加了一个存储位用来表示颜色,可以是Red也可以是Black,通过对任意一条根到叶子节点的颜色来约束,红黑树保证最长路径是最短路径的两倍,因此近似平衡;
红黑树的性质:
1:每个节点不是红色就是黑色
2:根节点是黑色
3:如果一个节点时红,则它两个子节点是黑色的(没有连续的红色)
4:对每个节点,从该节点到其后代的所有叶子节点的简单路径,均有相同数目的黑节点(每条路径的黑色节点色数目相同)
两者的差别:AVL树是完全平衡树,更接近满二叉树,因此它的时间复杂度是O(lgN),在二叉树插入删除时旋转多,维护起来比较麻烦,但相比更直观。而RBT树是近似平衡树,时间复杂度是2O(log n),旋转较少,相对维护起来比较简单,但是相比更抽象。相对来说运用最多的还是RBTree。
红黑树的应用: 在C++ STL中,很多部分都运用了红黑树包括:Linux内核,java c# 还有(包括set, multiset, map, multimap)应用了红黑树的变体(SGI STL中的红黑树有一些变化,这些修改提供了更好的性能,以及对set操作的支持)等等。
下面就是节点的颜色转换以及旋转的情况:
在此只展示了parent为孩子的情况,parent为右孩子情况类似。
具体实现源码如下:
#include <math.h>
#include <iostream>
using namespace std;
enum colour
{
BLACK,
RED,
};
template<class K, class V>
struct RBTreeNode
{
K _key;
V _val;
colour _col;
RBTreeNode<K, V>* _left;
RBTreeNode<K, V>* _right;
RBTreeNode<K, V>* _parent;
int _bf;
RBTreeNode(const K& key, const V& value)
:_left(NULL)
, _right(NULL)
, _parent(NULL)
, _key(key)
, _val(value)
, _bf(0)
, _col(RED)
{}
};
template<class K, class V>
class RBTree
{
typedef RBTreeNode<K, V> Node;
public:
RBTree()
:_root(NULL)
{}
~RBTree()
{}
bool Insert(const K& key, const V& value)
{
if (_root == NULL)
{
_root = new Node(key, value);
_root->_col = BLACK;
return true;
}
Node* parent = NULL;
Node* cur = _root;
while (cur)
{
if (cur->_key < key)//右边
{
parent = cur;
cur = cur->_right;
}
else if (cur->_key>key)//左边
{
parent = cur;
cur = cur->_left;
}
else
{
return false;//不存在
}
}
cur = new Node(key, value);
if (key > parent->_key)
{
parent->_right = cur;
cur->_parent = parent;
}
else
{
parent->_left = cur;
cur->_parent = parent;
}
while (parent && parent->_col==RED)
{
Node* grandparent = parent->_parent;
if (grandparent->_left==parent) //父亲在左边
{
Node* uncle = grandparent->_right;
if (uncle&&uncle->_col==RED)
{
parent->_col = BLACK;
uncle->_col = BLACK;
grandparent->_col = RED;
cur = grandparent; //向上调整
parent = cur->_parent; //
}
else //叔叔不存在或者叔叔为黑,需要旋转
{
if (cur==parent->_right)
{
RotateL(parent);
swap(parent,cur);
}
RotateR(grandparent);
parent->_col = BLACK;
grandparent->_col = RED;
break;
}
}
else //parent = grandparent->_right;
{
Node* uncle = grandparent->_left;
if (uncle&&uncle->_col == RED)
{
parent->_col = BLACK;
uncle->_col = BLACK;
grandparent->_col = RED;
cur = grandparent; //向上调整
parent = cur->_parent; //
}
else //叔叔不存在或者叔叔为黑,需要旋转
{
if (cur == parent->_left)
{
RotateR(parent);
swap(parent, cur); // 若cur在parent的左,cur->_key < parent->_key,旋转后必须交换才符合_key值得排布规则。
}
RotateL(grandparent);
parent->_col = BLACK;
grandparent->_col = RED;
}
}
}
_root->_col = BLACK;
return true;
}
bool Isbalance()
{
if (_root==NULL)
{
return true;
}
if (_root->_col==RED)
{
return false;
}
int Blacknum = 0;
Node* left = _root;
while (left) //遍历任意一边,计算出黑色节点的个数,作为一个基准,将此数与其他路上的书做较,只要不相等就可以说明此树不是平衡红黑树
{
if (left->_col==BLACK)
{
Blacknum++;
}
left = left->_left;
}
int num = 0;
return _IsBalance(_root, Blacknum, num);
}
bool _IsBalance(Node* root, const int Blacknum, int num)
{
if (root == NULL)
{
if (num != Blacknum)
{
cout << "黑节点个数不等" << endl;
return false;
}
else
{
return true;
}
}
if (root->_col == BLACK)
{
num++;
}
if ((root->_col == RED) && (root->_parent->_col == RED))
{
cout << root->_key << " " << root->_parent->_key << " " << endl;
return false;
}
return _IsBalance(root->_left, Blacknum, num) && _IsBalance(root->_right, Blacknum, num);
}
void RotateL(Node* parent)// 左单旋
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if (subRL) //开始旋转
{
subRL->_parent = parent;
} //
subR->_left = parent;
subR->_parent = parent->_parent;
Node* ppnode = parent->_parent;
parent->_parent = subR;/
if (ppnode == NULL)
{
_root = subR;
subR->_parent = NULL;
}
else if (parent == ppnode->_left)
{
ppnode->_left = subR;
}
else
{
ppnode->_right = subR;
}
subR->_parent = ppnode;
}
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)
{
subLR->_parent = parent;
}
subL->_right = parent;
subL->_parent = parent->_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;
}
void InOrder()
{
_InOrder(_root);
cout << endl;
}
protected:
void _InOrder(Node* root)
{
if (root == NULL)
{
return;
}
_InOrder(root->_left);
cout << root->_key << " ";
_InOrder(root->_right);
}
private:
Node* _root;
};
void Test()
{
int a[] = { 5, 3, 4, 1, 7, 8, 2, 6, 0, 9 };
//int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
//int a[] = {2,3,1,4,5};
//int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
RBTree<int, int> t;
for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); i++)
{
//t.Insert(a[i], i);
t.Insert(a[i],i);
cout << t.Isbalance()<< endl;
}
t.InOrder();
}