红黑树简介
红黑树是一个高效的平衡搜索树,保证最长路径不超过最短路径的两倍,因而近似平衡,保证了高度,也就保证了效率。增删查改时间复杂度都是O(logN)
性质:
- 每个结点不是红色就是黑色的。
- 根结点是黑色的。
- 如果一个结点是红色的,则它的两个子节点是黑色的(没有连续的红结点)
- 对于每个结点,从该结点到其所有后代叶节点的简单路径上,均包含相同数目的黑色结点(每条路径的黑色节点的数目相等)
- 每个叶子结点都为黑色(此处叶子结点是空结点)
这几条规则保证了红黑树最长路径不超过最短路径的两倍(给个极端情况全黑色,然后在结点之间插入红色结点,即可得到结论)
结点的实现
三叉链实现RBtree,用KV存储结构,最后用枚举包含了相应的颜色。
树的实现
共有成员为空的构造函数,插入函数
私有成员为根,
红黑树的插入
为什么插入结点的颜色为红色好?
如果插入结点为黑色首先违背了第四条规则,每条路径黑色结点数目相同,虽然可以调整但是难调,我们原则上的保持第四条规则,所以选择插入红色节点。
方法:
首先判断是否为空树,接着找到插入结点,根据插入结点的情况来调整。 cur为插入结点,g为组父节点,p是父亲结点,u是叔叔结点
1. 如果插入结点为根结点,则直接插入,并且将根结点赋值为黑色。
2. 如果插入结点的父节点为黑色结点,那么直接插入。
3. 如果插入结点的父节点为红色结点,那么再次插入时,必然会有两个红色结点相连接,此时需要调整。
叔叔结点的情况和调整有关,叔叔的情况有以下几种:
叔叔存在且为红色
叔叔不存在
叔叔为黑色
插入分为三种情况
- 组父节点为黑色,父节点和叔叔结点为为红色,插入节点的为红色。
此种情况下父亲结点和叔叔结点变为黑色,祖父结点变为红色,如果祖父结点是根结点则不影响,如果祖父结点不是根结点,则需要向上更新, 祖父结点为黑色,父亲结点为红色,叔叔结点(不存在或者为黑色),插入结点为红色。(单旋)
- 第一种情况,叔叔不存在,cur为新增结点,
- 第二种情况,叔叔存在且为黑色,parent的一边C一定存在且为黑色,cur为红色结点,cur此时不是新插入的结点,cur存在左右孩子,并且cur原先为黑色((cur此时左右为黑色吗?))
此时旋转来调整结点,观察p和cur均为左孩子,此时右单旋,p和cur均为右孩子,此时左单旋。
- 祖父结点为黑色,父亲结点为红色,叔叔结点(不存在或者为黑色),插入结点为红色。(双旋)
- 第一种情况:u存在并且一定为黑色,cur不是新插入的结点,cur存在左右孩子,并且cur原先为黑色。
- 第二种情况:u不存在,cur一定为新插入的结点。
实现代码如下
#include <iostream>
#include <assert.h>
using namespace std;
enum Colour
{
RED,
BLACK,
};
template <class K,class V>
struct RBTreeNode
{
RBTreeNode* _left;
RBTreeNode* _right;
RBTreeNode* _parent;
K _key;
V _value;
Colour _col;
RBTreeNode(const K& key = K(), const V& value = V(), const Colour& color = RED)
:_left(NULL)
, _right(NULL)
, _parent(NULL)
, _key(key)
, _value(value)
, _col(color)
{}
};
template <class K,class V>
class RBTree
{
typedef RBTreeNode<K, V> Node;
public:
RBTree()
:_root(NULL)
{}
~RBTree()
{
//if (_root)
// _root = _Destroy(_root);
}
RBTree(const RBTree<K, V>& rb)
{
if (this != &rb)
_root = _Copy(_root);
}
RBTree<K, V> operator=(const RBTree<K, V>& rb)
{
if (*this != rb)
{
Node* tmp = _Copy(rb->_root);
_root = _Destroy(_root);
_root = tmp;
}
return *this;
}
bool Insert(const K& key, const V& value)
{
if (_root == NULL)
{
_root = new Node(key, value);
_root->_col = BLACK;
return true;
}
Node* pCur = _root;
Node* pParent = NULL;
while (pCur)
{
if (key < pCur->_key)
{
pParent = pCur;
pCur = pCur->_left;
}
else if (key > pCur->_key)
{
pParent = pCur;
pCur = pCur->_right;
}
else
return false;
}
pCur = new Node(key, value);
if (key < pParent->_key)
pParent->_left = pCur;
else
pParent->_right = pCur;
pCur->_parent = pParent;
//未调整到根节点且父节点还是红色
while (pCur != _root && pParent->_col == RED)
{
Node* grandfather = pParent->_parent;
//先处理左边
if (grandfather->_left == pParent)
{
Node* uncle = pParent->_right;
//叔叔存在且为红色
if (uncle && uncle->_col == RED)
{
pParent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
pCur = grandfather;
pParent = pCur->_parent;
}
//叔叔不存在或者叔叔为黑色
else
{
//pCur为pParent的右孩子
if (pParent->_right == pCur)
{
RotateL(pParent);
std::swap(pCur, pParent);
}
//pCur为pParent的左孩子
else
{
RotateR(grandfather);
grandfather->_col = RED;
pParent->_col = BLACK;
}
}
}
//再处理右边的情况(与上述情况刚好位置相反)
else
{
Node* uncle = grandfather->_left;
//叔叔存在且为红
if (uncle && uncle->_col == RED)
{
pParent->_col = uncle->_col = BLACK;
pCur->_col = RED;
pCur = grandfather;
pParent = pCur->_parent;
}
//叔叔不存在或者叔叔为黑色
else
{
//pCur为pParent的左孩子
if (pParent->_left == pCur)
{
RotateR(pParent);
std::swap(pCur, grandfather);
}
//pCur为pParent的右孩子
else
{
RotateL(grandfather);
grandfather->_col = RED;
pParent->_col = BLACK;
}
}
}
}
_root->_col = BLACK;
return true;
}
void RotateR(Node* parent)
{
assert(parent);
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
Node* pparent = parent->_parent;
subL->_right = parent;
parent->_parent = subL;
if (pparent->_left == parent)
{
pparent->_left = subL;
subL->_parent = pparent;
}
else if (pparent->_right == parent)
{
pparent->_right = subL;
subL->_parent = pparent;
}
else
{
_root = subL;
subL->_parent = NULL;
}
}
void RotateL(Node* parent)
{
assert(parent);
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
Node* pparent = parent->_parent;
subR->_left = parent;
parent->_parent = subR;
if (pparent->_left = subR->_parent)
{
pparent->_left = subR;
subR->_parent = pparent;
}
else if (pparent->_right = subR->_parent)
{
pparent->_right = subR;
subR->_parent = pparent;
}
else
{
_root = subR;
subR->_parent = NULL;
}
}
bool IsBalance()
{
if (NULL == _root)
return true;
if (_root->_col == RED)
return false;
size_t count = 0;
Node* cur = _root;
while (cur)
{
if (cur->_col == BLACK)
count++;
cur = cur->_left;
}
size_t k = 0;
_IsBalance(_root, count, k);
}
void InOrder()
{
_Inorder(_root);
cout << endl;
}
private:
bool _IsBalance(Node* _root, size_t count, size_t k)
{
if (_root == NULL)
return true;
if (_root->_parent&&_root->_col == _root->_parent->_col == RED)
return false;
if (_root->_col == BLACK)
k++;
if (_root->_left == NULL&&_root->_right == NULL)
{
if (count == k)
return true;
else
return false;
}
return ((_IsBalance(_root->_left, count, k))&&(_IsBalance(_root->_right, count, k)));
}
void _Inorder(Node* Root)
{
if (Root)
{
_Inorder(Root->_left);
cout << Root->_key << endl;
_Inorder(Root->_right);
}
}
Node* _Copy(Node* pRoot)
{
Node* pCur = pRoot;
if (pCur)
{
pCur = new Node(pRoot->_key, pRoot->_value);
pCur->_left= _Copy(pRoot->_left);
pCur->_right = _Copy(pRoot->_right);
}
return pCur;
}
//销毁
Node* _Destory(Node* pRoot)
{
if (pRoot)
{
pRoot->_left = _Destory(pRoot->_left);
pRoot->_right = _Destory(pRoot->_right);
delete pRoot;
pRoot = NULL;
}
return pRoot;
}
Node* _root;
};
测试文件:
#include "RBtree.h"
using namespace std;
void test()
{
RBTree<int, int> rb;
int arr[] = { 10, 7, 8, 15, 5, 6, 11, 13, 12 };
for (size_t idx = 0; idx < sizeof(arr) / sizeof(arr[0]); ++idx)
{
rb.Insert(arr[idx], idx);
}
rb.InOrder();
if (rb.IsBalance())
cout << "是红黑树." << endl;
else
cout << "不是红黑树." << endl;
rb.InOrder();
}
int main()
{
test();
system("pause");
return 0;
}
红黑树的应用
红黑树是一颗高效的二叉搜索树,用途很广,例如STL中set\map\unorder_map\unorder_set都运用到了红黑树。