您的位置:首页 > 理论基础 > 数据结构算法

红黑树

2016-07-21 21:37 961 查看
一、红黑树的基本概念
红黑树是一种自平衡二叉查找树。典型的用途是实现关联数组,在实践中是高效的,时间复杂度为O(log)。主要实现查找,插入和删除功能。它的统计性能要高于平衡二叉树(AVL树)。
红黑树是一种特定类型的二叉树。它用来组织数据,比如数字的块的一种结构,所有数据块都存储在节点中,这些节点中的某一个节点总是担当启始位置的功能,它不是任何节点的儿子,即根节点或根。最多两个"儿子",都是它连接到的其他节点。所有这些儿子都可以有自己的儿子,以此类推。这样根节点就有了把它连接到在树中任何其他节点的路径。
如果一个节点没有儿子,我们称之为叶子节点,因为在直觉上它是在树的边缘上。子树是从特定节点可以延伸到的树的某一部分,其自身被当作一个树。在红黑树中,叶子被假定为 null 或空。
红黑树是二叉查找树。它当中每一个节点的比较值都必须大于或等于在它的左子树中的所有节点,并且小于或等于在它的右子树中的所有节点。这确保红黑树运作时能够快速的在树中查找给定的值。
应用:
在C++ STL中,很多部分(如set,map)应用了红黑树的变体;在Linux中许多虚拟内存的管理,也应用了红黑树。
性质:
1. 节点是红色或黑色。
2. 根节点是黑色。
3 .每个叶节点(空节点)是黑色的。
4.所有路径上不能有两个连续的红色节点。
5. 所有路径都包含相同数目的黑色节点。
这些约束强制了红黑树的关键性质:最长的可能路径不大于最短路径的两倍长。所以这个树大致上是平衡的。
为什么这些特性确保了这个关键性质:最短的可能路径都是黑色节点,最长的可能路径有交替的红色和黑色节点,根据性质5所有最长的路径都有相同数目的黑色节点,这就表明了没有路径能多于任何其他路径的两倍长。

二、红黑树的操作
在红黑树上只读操作不需要对用于二叉查找树的操作做出修改,因为它也是二叉查找树。但是,在插入和删除之后,红黑属性可能就会不符合要求。恢复红黑属性需要少量(O(log n))的颜色变更(这在实践中是非常快速的),并且不超过三次树旋转(插入是两次)。这允许插入和删除保持为 O(log n) 次,但是它导致了非常复杂的操作。

三、插入操作
情况一:叔叔存在且为红
将父亲和叔叔变黑,祖父变红;若祖父的父亲为红色,则将祖父变为刚插入的孩子,继续向上变。





情况二:叔叔存在且为黑或者叔叔不存在(父亲为祖父的左孩子、插入的为父亲的左孩子或者都为右孩子)
都为左孩子:以祖父为轴右旋,将祖父变红,父亲变黑;
都为右孩子:一祖父为轴左旋,将祖父变红,父亲变黑。





情况三:叔叔存在且为黑或者叔叔不存在(父亲为祖父的左孩子、插入的为父亲的右孩子或者都相反)
父亲为左孩子、插入的为右孩子:以父亲为轴左旋,父亲和插入的孩子互换身份,变为第二种情况(都为左孩子);
父亲为右孩子、插入的为左孩子:以父亲为轴右旋,父亲和插入的孩子互换身份,变为第二种情况(都为右孩子);





四、代码栗子
#include<iostream>
using namespace std;

enum color
{
RED,
BLACK
};

template<class K, class V>
struct RBTreeNode
{
K _key;
V _value;
RBTreeNode<K, V>* _parent;
RBTreeNode<K, V>* _left;
RBTreeNode<K, V>* _right;
color _col;

RBTreeNode(const K& key, const V& value)
:_key(key)
,_value(value)
,_parent(NULL)
,_left(NULL)
,_right(NULL)
,_col(RED)
{}
};

template<class K, class V>
class RBTree
{
typedef RBTreeNode<K, V> Node;
private:
Node* _root;

public:
RBTree()
:_root(NULL)
{}

void Instert(K key, V value)
{
//没有节点时创建并插入一个根节点
if(_root == NULL)
{
_root = new Node(key, value);
_root->_col = BLACK;
return;
}

//本来有节点,找到合适的位置,创建节点并插入
Node* cur = _root;
Node* parent = NULL;
while(cur)
{
parent = cur;
if(cur->_key > key)
{
cur = cur->_left;
if(cur == NULL)
{
parent->_left = new Node(key, value);
cur = parent->_left;
cur->_parent = parent;
break;
}

}
else if(cur->_key < key)
{
cur = cur->_right;
if(cur == NULL)
{
parent->_right = new Node(key, value);
cur = parent->_right;
cur->_parent = parent;
break;
}

}
}
_root->_col = BLACK;

//处理节点的颜色
while(cur != _root && parent->_col == RED)
{
Node* grandfather = parent->_parent;
if(grandfather->_left == parent)
{
Node* uncle = grandfather->_right;
//1.叔叔存在且为红
if(uncle && uncle->_col == RED)
{
grandfather->_col = RED;
parent->_col = BLACK;
uncle->_col = BLACK;

cur = grandfather;
parent = cur->_parent;
}
//2.叔叔不存在或叔叔存在且为黑
else
{
//    <
if(cur == parent->_right)
{
RotateL(parent);
swap(cur, parent);
}

//   /
parent->_col = BLACK;
grandfather->_col = RED;
RotateR(grandfather);
break;
}
}
//grandfather->_right == parent
else
{
Node*uncle = grandfather->_left;
//1.叔叔存在且为红
if(uncle && uncle->_col == RED)
{
grandfather->_col = RED;
parent->_col = BLACK;
uncle->_col = BLACK;

cur = grandfather;
parent = cur->_parent;
}
//2.叔叔不存在或叔叔存在且为黑
else
{
//        >
if(cur == parent->_left)
{
RotateR(parent);
swap(parent, cur);
}
//         /
parent->_col = BLACK;
grandfather->_col = RED;
RotateL(grandfather);
break;
}
}
}
_root->_col = BLACK;
}

bool IsBalance()
{
int key = 0;
Node* cur = _root;
while(cur)
{
if(cur->_col == BLACK)
key++;//计算一条路径的黑色节点作为基准值
cur = cur->_left;
}

int count = 0;
return _IsBalance(_root, key, count);
}

void InOrder()
{
_InOrder(_root);
}

private:
void _InOrder(Node* root)
{
if(root == NULL)
return;

_InOrder(root->_left);
cout << root->_key << "->";
_InOrder(root->_right);
}

bool _IsBalance(Node* root, const int k, int count)
{
if(root == NULL)
return true;

if(root->_col == BLACK)
count++;

if(root->_col == RED && root->_parent->_col == RED)
{
cout << "连续红色" << endl;
return false;
}
if(root->_left == NULL && root->_right == NULL && count != k)
{
cout << "黑色数目不相等" << endl;
return false;
}

return _IsBalance(root->_left, k, count) && _IsBalance(root->_right, k, count);
}

void RotateR(Node* parent)
{
Node* SubL = parent->_left;
Node* SubLR = SubL->_right;
Node* ppNode = parent->_parent;

SubL->_right = parent;
parent->_parent = SubL;
parent->_left = SubLR;
if(SubLR)
SubLR->_parent = parent;

if(ppNode == NULL)
{
_root = SubL;
SubL->_parent = NULL;
}
else if(ppNode->_left == parent)
{
ppNode->_left = SubL;
SubL->_parent = ppNode;
}
else
{
ppNode->_right = SubL;
SubL->_parent = ppNode;
}
}

void RotateL(Node* parent)
{
Node* SubR = parent->_right;
Node* SubRL = SubR->_left;
Node* ppNode = parent->_parent;

SubR->_left = parent;
parent->_parent = SubR;
parent->_right = SubRL;
if(SubRL)
{
SubRL->_parent = parent;
}

if(ppNode == NULL)
{
_root = SubR;
SubR->_parent = NULL;
}
else if(ppNode->_left == parent)
{
ppNode->_left = SubR;
SubR->_parent = ppNode;
}
else
{
ppNode->_right = SubR;
SubR->_parent = ppNode;
}
}

};

int main()
{
RBTree<int, int> t;
int a[] = {1, 2, 3, 4, 5, 6, 7, 9, 8};
for(int i = 0; i<(sizeof(a)/sizeof(a[0]));i++)
{
t.Instert(a[i],i);
cout << a[i] << t.IsBalance() << endl;
}

t.InOrder();
cout << t.IsBalance() << endl;

system("pause");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数据结构 红黑树