红黑树
红黑树,一种特殊的二叉搜索树, 为每个结点描述了颜色(红色或黑色),通过对所有结点的着色方式限制,红黑树确保了没有一条路径会比其他路径的长度超出两倍,因而是近似平衡的。
红黑树的性质:
红黑树通过以下性质来实现近似平衡结构:
- 根节点是黑色的 ;
- 每个结点不是红色就是黑色;
- 如果一个节点是红色的,则它的两个孩子结点是黑色的 ; (红色结点不能连续出现)
- 对于任意结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点 ;
- 每个叶子结点都是黑色的 ( 此处的叶子结点指的是空结点----NIL结点 )。
根据性质我们可以推出:最短路径为只有黑色结点的路径,最长路径为红黑相间的路径
红黑树和AVL树对比
红黑树搜索的时间复杂度:O(logN)
最短路径:O(logN)
最长路径:2*O(logN)
AVL树搜索的时间复杂度:O(logN)
红黑树的效率比AVL树略差
1、红黑树的性能略差于AVL树,但是对于现代硬件的执行速度来说,差距非常小;
2、AVL树严格的平衡结构是通过大量的旋转及调节平衡因子来实现的,红黑树之所以比AVL树使用更广泛的一个重要原因:红黑树在插入和删除时的旋转操作更少
红黑树的结构
为了后续实现关联式容器简单,红黑树的实现中增加一个头结点,因为跟节点必须为黑色,为了与根节点进行区分,将头结点给成黑色,并且让头结点的 pParent 域指向红黑树的根节点,pLeft域指向红黑树中最小的节点,_pRight域指向红黑树中最大的节点,如下:
红黑树的插入
cur为当前结点;p为父节点;g为祖父结点;u为叔叔结点
情况一
1、如果这里是一棵完整的树(g是根结点),把g再变黑,结束调整;
2、如果这里的树是另一个结点的子树(g不是根结点),g的父节点也有可能是红色,所以还需要继续向上调整:a、如果g的父亲是黑色,结束调整;
b、如果g的父亲是红色,cur更新到g的位置,继续调整。
情况二
情况三
代码:
#include<iostream>
using namespace std;
enum Color{
BLACK,
RED
};
template<class V>
struct RBTreeNode {
RBTreeNode<V>* _left;
RBTreeNode<V>* _right;
RBTreeNode<V>* _parent;
V _val;
Color _color;
RBTreeNode(const V&val = V())
:_parent(nullptr)
,_left(nullptr)
,_right(nullptr)
,_val(val)
,_color(RED)
{}
};
//KeyOfVal:通过V获取其对应的K值
template<class K, class V, class KeyOfVal>
class RBTree {
public:
typedef RBTreeNode<V> Node;
RBTree() :_header(new Node)
{
_header->_left = _header->_right = _header;
}
bool insert(const V&val)
{
//二叉搜索树的插入
if (_header->_parent == nullptr)
{
//创建根结点
Node* root = new Node(val);
_header->_parent = root;
root->_parent = _header;
_header->_left = _header->_right = root;
//根结点是黑色
root->_color = BLACK;
return true;
}
//从根节点开始搜索
Node* cur = _header->_parent;
Node* parent = nullptr;
KeyOfVal kov;
while (cur)
{
parent = cur;
if (kov(cur->_val)==kov(val))
{
//key值不允许重复
return false;
}
else if (kov(cur->_val) > kov(val))
{
cur = cur->_left;
}
else
{
cur = cur->_right;
}
}
//创建待插入的结点
cur = new Node(val);
if (kov(parent->_left) == kov(cur->_val))
parent->_left = cur;
else
parent->_right = cur;
cur->_parent = parent;
//修改颜色或调整结构
//判断是否有红色连续的结点
while (cur != _header->_parent&&cur->_parent->_color == RED)
{
parent = cur->_parent;
Node* gfather = parent->_parent;
//插入发生在祖父结点的左边时
if (gfather->_left == parent)
{
Node* uncle = gfather->_right;
//1.uncle存在并且是红色
if (uncle&&uncle->_color == RED)
{
parent->_color = uncle->_color = BLACK;
gfather->_color = RED;
//继续向上更新
if (gfather != _header->parent)
cur = gfather;
}
else
{
//判断是否为双旋
if (cur == parent->_right)
{
//左旋
RotateL(parent);
//交换cur和parent
swap(cur, parent);
}
//右旋
RotateR(gfather);
gfather->_color = RED;
parent->_color = BLACK;
break;
}
}
//插入发生在祖父结点的右边时
else
{
}
}
_header->_parent->_color = BLACK;
_header->_left = leftMost();
_header->_right = rightMost();
return true;
}
Node* leftMost()
{
Node* cur = _header->_parent;
while (cur&&cur->_left)
{
cur = cur->_left;
}
return cur;
}
Node* rightMost()
{
Node* cur = _header->_parent;
while (cur&&cur->_right)
{
cur = cur->_right;
}
return cur;
}
void inorder()
{
_inorder(_header->_parent);
cout << endl;
}
void _inorder(Node* root)
{
_inorder(root->_left);
cout << root->_val<<" ";
_inorder(root->_right);
}
//左旋
void RotateL(Node* cur)
{
Node* curR = cur->_right;
Node* curRL = curR->_left;
curR->_left = cur;
cur->_right = curRL;
if (curRL)
{
curRL->_parent = cur;
}
if (cur == _header->parent)
{
_header->parent = curR;
curR->_parent = _header;
}
else
{
Node* pparent = cur->_parent;
if (pparent->_left == cur)
pparent->_left = curR;
else
pparent->_right = curR;
curR->_parent = pparent;
}
cur->_parent = curR;
}
//右旋
void RotateR(Node* cur)
{
Node* curL = cur->_left;
Node* curLR = curL->_right;
curL->_right = cur;
cur->_left = curLR;
if (curLR)
{
curLR->_parent = cur;
}
if (cur == _header->parent)
{
_header->parent = curL;
curL->_parent = _header;
}
else
{
Node* pparent = cur->_parent;
if (pparent->_left == cur)
pparent->_left = curL;
else
pparent->_right = curL;
curL->_parent = pparent;
}
cur->_parent = curL;
}
private:
Node* _header = nullptr;
};
void test()
{}
int main()
{
return 0;
}