一:红黑树
红黑树是一颗二叉搜索树,它的每一个节点增加了一个存储位用来表示颜色,可以是Red也可以是Black,通过对任意一条根到叶子节点的颜色来约束,红黑树保证最长路径是最短路径的两倍,因此近似平衡;
红黑树的性质:
1:每个节点不是红色就是黑色
2:根节点是黑色
3:如果一个节点时红,则它两个子节点是黑色的(没有连续的红色)
4:对每个节点,从该节点到其后代的所有叶子节点的简单路径,均有相同数目的黑节点(每条路径的黑色节点色数目相同)
定义一个红黑树:
template <class K,class V>
struct RBTreeNode
{
RBTreeNode<K, V> *_left;
RBTreeNode<K, V> *_right;
RBTreeNode<K, V> *_parent;
K _key;
V _value;
color _color;
RBTreeNode(const K&key, const V&value =0)
:_left(NULL)
, _right(NULL)
, _parent(NULL)
, _key(key)
, _value(value)
, _color(RED)
{}
};
思考为什么满足上述约束条件,最长路径不超过黑色节点的两倍
假设最极端的情况下,最长路径和最短路径的节点都为黑色,在黑色节点的中间加上红色节点,且红色节点的个数和黑色节点的个数相等,那么此时最长路径就是最短路径的2倍;
二:插入分析:
ps:cur为当前节点,p为父亲节点,u为叔叔节点,g为祖父节点
第一种情况:
cur为红,p为红,g为黑,u存在且为红,
此时要进行变色处理,p,u变黑,g变红,然后把g给cur,向上调整;
三角表示为子树,可能存在也可能不存在;
第二种情况:
cur为红,p为红,g为黑,u不存在或者是存在且为黑;
p为g的左孩子,cur是p的左孩子,此时进行右单旋,p和g变色。p变黑,g变红;
此时要经过旋转;
1:右旋
2:左旋
cur是p的右孩子,p是g的右孩子,进行左单旋。变色p和g变色,p变黑,g变红;
第三种情况:
cur为红,p为红g为黑;
u不存在或者是存在且为黑
p是g的左孩子cur是p的右孩子,此时要进行双旋,对p进行左单旋,对g进行右单旋
双旋的具体过程和AVL树很像,只有少了平衡因子的更新,但是多了变色处理;
AVL树的旋转http://blog.csdn.net/f2016913/article/details/69367756
当p在左边的过程也是如此,分为u存在且为红,u不存在或者是存在且为黑,u不存在或者是存在且为黑,p是g的左孩子cur是p的右孩子
三:插入算法:
```
//插入
bool _Insert(const K&key)
{
if (_root == NULL)
{
_root = new Node(key);
_root->_color = 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);
if (parent->_key < key)//右边
{
parent->_right = cur;
cur->_parent = parent;
}
else
{
parent->_left = cur;
cur->_parent = parent;
}
//父亲存在,且颜色为红
while (parent &&parent->_color == RED)
{
Node*grandparent = parent->_parent;//祖父一定存在
if (parent == grandparent->_left)//父亲在左边
{
//叔叔存在且为红
Node*uncle = grandparent->_right;
if (uncle&&uncle->_color == RED)
{
//父亲和叔叔的颜色变黑,祖父的颜色变红
parent->_color = uncle->_color = BLACK;
grandparent->_color = RED;
cur = grandparent;//可能为子树上调
parent =cur->_parent;
}
//叔叔不存在或者是存在且为黑
else
{
//旋转
if ( cur==parent->_right)
{
//双旋
_RotateL(parent);
swap(parent, cur);
}
//右单旋
_RotateR(grandparent);///
parent->_color = BLACK;
grandparent->_color = RED;
break ;
}
}
//父亲在右边
else//parent == grandparent->_right
{
//叔叔存在且为红
Node*uncle = grandparent->_left;
if (uncle&&uncle->_color == RED)
{
//变色
parent->_color = uncle->_color = BLACK;
grandparent->_color = RED;
//上调
cur = grandparent;
parent =cur->_parent;
}
//叔叔不存在或者存在且为黑
else
{
//双旋
if (cur == parent->_left)
{
_RotateR(parent);
swap(parent, cur);
}
_RotateL(grandparent);//右旋
parent->_color = BLACK;
grandparent->_color = RED;
break;
}
}
}
_root->_color = BLACK;
return true;
}
四:判断一个红黑树是否平衡
红黑树的性质,要满足任何一个路径黑色节点的个数相等;我们可以分别统计每条黑色节点的个数,当相等时就//判断是不是红黑树
//判断是不是红黑树
bool IsBalance()
{
if (_root == NULL)
{
return true;
}
if (_root->_color == RED)//根节点为红
{
return false;
}
//统计黑节点的个数
int blacknum = 0;
Node*left = _root;
while (left)
{
if (left->_color == 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->_color == BLACK)
{
++num;
}
//相邻的红节点
if((root->_color == RED)
&&(root->_parent->_color == RED))
{
cout <<"存在连续的红节点"<< root->_key << endl;
return false;
}
return _IsBalance(root->_left, blacknum, num)
&& _IsBalance(root->_right, blacknum, num);
}
五:完整代码:
#pragma once
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;
color _color;
RBTreeNode(const K&key, const V&value =0)
:_left(NULL)
, _right(NULL)
, _parent(NULL)
, _key(key)
, _value(value)
, _color(RED)
{}
};
template<class K,class V>
class RBTree
{
typedef RBTreeNode<K, V>Node;
public:
RBTree()
:_root(NULL)
{}
RBTree(const RBTree<K, V>&tree)
{
_Copy(tree._root);
}
RBTree<K, V>&operator =(RBTree<K, V> tree)
{
RBTree<K, V> tmp(tree._root);
swap(tree._root, _root);
return *this;
}
~RBTree()
{
_Destroy(_root);
}
//中序
void InOrder()
{
_InOrder(_root);
cout << endl;
}
//插入
void Insert(const K& key)
{
_Insert(key);
}
//判断是不是红黑树
bool IsBalance()
{
if (_root == NULL)
{
return true;
}
if (_root->_color == RED)//根节点为红
{
return false;
}
//统计黑节点的个数
int blacknum = 0;
Node*left = _root;
while (left)
{
if (left->_color == 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->_color == BLACK)
{
++num;
}
//相邻的红节点
if((root->_color == RED)
&&(root->_parent->_color == RED))
{
cout <<"存在连续的红节点"<< root->_key << endl;
return false;
}
return _IsBalance(root->_left, blacknum, num)
&& _IsBalance(root->_right, blacknum, num);
}
protected:
//中序遍历
void _InOrder(Node*root)
{
Node*cur = root;
if (cur == NULL)
{
return;
}
_InOrder(cur->_left);
cout << cur->_key << " ";
_InOrder(cur->_right);
}
//拷贝
void _Copy(Node*root)
{
Node*cur = root;
Node*newNode = NULL;
while (cur)
{
newNode = new Node(cur->_key);
newNode->_left = _Copy(cur->_left);
newNode->_right = _Copy(cur->_right);
}
return newNode;
}
//删除
void _Destroy(Node*root)
{
if (root == NULL)
{
return;
}
Node*cur = root;
while (cur)
{
_Destroy(cur->_left);
_Destroy(cur->_right);
delete cur;
cur = NULL;
}
}
//插入
bool _Insert(const K&key)
{
if (_root == NULL)
{
_root = new Node(key);
_root->_color = 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);
if (parent->_key < key)//右边
{
parent->_right = cur;
cur->_parent = parent;
}
else
{
parent->_left = cur;
cur->_parent = parent;
}
//父亲存在,且颜色为红
while (parent &&parent->_color == RED)
{
Node*grandparent = parent->_parent;//祖父一定存在
if (parent == grandparent->_left)//父亲在左边
{
//叔叔存在且为红
Node*uncle = grandparent->_right;
if (uncle&&uncle->_color == RED)
{
//父亲和叔叔的颜色变黑,祖父的颜色变红
parent->_color = uncle->_color = BLACK;
grandparent->_color = RED;
cur = grandparent;//可能为子树上调
parent =cur->_parent;
}
//叔叔不存在或者是存在且为黑
else
{
//旋转
if ( cur==parent->_right)
{
//双旋
_RotateL(parent);
swap(parent, cur);
}
//右单旋
_RotateR(grandparent);///
parent->_color = BLACK;
grandparent->_color = RED;
break ;
}
}
//父亲在右边
else//parent == grandparent->_right
{
//叔叔存在且为红
Node*uncle = grandparent->_left;
if (uncle&&uncle->_color == RED)
{
//变色
parent->_color = uncle->_color = BLACK;
grandparent->_color = RED;
//上调
cur = grandparent;
parent =cur->_parent;
}
//叔叔不存在或者存在且为黑
else
{
//双旋
if (cur == parent->_left)
{
_RotateR(parent);
swap(parent, cur);
}
_RotateL(grandparent);//右旋
parent->_color = BLACK;
grandparent->_color = RED;
break;
}
}
}
_root->_color = BLACK;
return true;
}
protected:
//左旋
void _RotateL(Node*parent)
{
Node*subR = parent->_right;
Node*subRL = subR->_left;
parent->_right = subRL;
if (subRL)
{
subRL->_parent = parent;
}
subR->_left = parent;
Node*ppnode = parent->_parent;
parent->_parent = subR;
if (ppnode == NULL)
{
_root = subR;
subR->_parent = NULL;
}
else//祖父不为空
{
if (ppnode->_left == parent)
{
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;
Node*ppnode = parent->_parent;
parent->_parent = subL;
if (ppnode == NULL)
{
_root = subL;
subL->_parent = NULL;
}
else
{
if (ppnode->_right== parent)
{
ppnode->_right = subL;
}
else
{
ppnode->_left = subL;
}
subL->_parent = ppnode;
}
}
protected:
Node*_root;
};
void TestRBTree()
{
RBTree<int, int> t;
int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
for (int i = 0; i < sizeof(a)/sizeof(a[0]); ++i)
{
t.Insert(a[i]);
}
t.InOrder();
cout << "IsBalance?"<<t.IsBalance() << endl;
}
.cpp文件
#include<iostream>
#include"RBTree.h"
using namespace std;
int main()
{
TestRBTree();
system("pause");
return 0;
}
六:红黑树和AVL树的比较:
红黑树的优点,高效的二叉搜索树,
AVL树的时间复杂度是O(lgN);
红黑树的时间复杂度是O(2lgN);近似平衡;最长路径是最短路径的2倍,此时不用选装,而AVL树当左右字数的高度差的绝对值大于1要进行旋转,而且还要更新平衡因子;所以综合来看红黑树比AVL树高效;
红黑树的应用:
1. C++ STL库 – map
2. Java 库
3. linux内核
4. 其他一些库