红黑树
红黑树的概念
红黑树
,是一种
二叉搜索树
,但
在每个结点上增加一个存储位表示结点的颜色,可以是
Red
或
Black
。 通过 对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩
倍
,因而是
接近平衡
的。
红黑树的性质
1.
每个结点不是红色就是黑色
2.
根节点是黑色的
3.
如果一个节点是红色的,则它的两个孩子结点是黑色的
4.
对于每个结点,从该结点到其所有后代叶结点的简单路径上,均 包含相同数目的黑色结点
5.
每个叶子结点都是黑色的
(
此处的叶子结点指的是空结点
)
思考:为什么满足上面的性质,红黑树就能保证:其最长路径中节点个数不会超过最短路径节点个数的两
倍?
答:假设一条路径黑色节点为H,那么多短路径就是H,最长路径为2H,大佬就是大佬,也不知怎么想出来的。
红黑树节点的定义
enum Colour
{
RED,
BLACK
};
template<class K,class V>
class RBTreeNode
{
public:
RBTreeNode(const std::pair<K, V>& kv)
:_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_kv(kv)
,_col(RED)
{
}
RBTreeNode<K, V>* _left;
RBTreeNode<K, V>* _right;
RBTreeNode<K, V>* _parent;
std::pair<K, V> _kv;
Colour _col;
};
思考:在节点的定义中,为什么要将节点的默认颜色给成红色的?
答:节点定义成红色是为了方便处理。
红黑树结构
为了后续实现关联式容器简单,红黑树的实现中增加一个头结点,因为跟节点必须为黑色,为了与根节点进 行区分,将头结点给成黑色,并且让头结点的 Parent
域指向红黑树的根节点,
Left
域指向红黑树中最小的 节点,Right
域指向红黑树中最大的节点,如下:
红黑树的插入操作
红黑树是在二叉搜索树的基础上加上其平衡限制条件,因此红黑树的插入可分为两步:
1. 按照二叉搜索的树规则插入新节点
template<class K,class V>
class RBTree
{
public:
typedef RBTreeNode<K, V> Node;
RBTree()
:_root(nullptr)
{
}
bool insert(const std::pair<K,V> &kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
_root->_col = BLACK;
return true;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur != nullptr)
{
if (kv.first > cur->_kv.first)
{
parent = cur;
cur = cur->_right;
}
else if (kv.first < cur->_kv.first)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
//新增节点
cur = new Node(kv);
cur->_col = RED;
if (kv.first > parent->_kv.first)
{
parent->_right = cur;
cur->_parent = parent;
}
else
{
parent->_left = cur;
cur->_parent = parent;
}
}
2. 检测新节点插入后,红黑树的性质是否造到破坏
因为
新节点的默认颜色是红色
,因此:如果
其双亲节点的颜色是黑色,没有违反红黑树任何性质
,则不 需要调整;但当新插入节点的双亲节点颜色为红色时,就违反了性质三不能有连在一起的红色节点
,此 时需要对红黑树分情况来讨论:
约定
:cur
为当前节点,
p
为父节点,
g
为祖父节点,
u
为叔叔节点
情况一: cur为红,p为红,g为黑,u存在且为红
解决方式:将p,u改为黑,g改为红,然后把g当成cur,继续向上调整
情况二: cur为红,p为红,g为黑,u不存在/u为黑
说明:u的情况右两种
1.如果u节点不存在,则cur一定是新插入的节点,如果cur不是新插入节点,则cur和p一定有一个节点的颜色是黑色,就不满足性质4,每条路径黑色节点的个数相同。
2.如果u节点存在,则其一定是黑色,那么cur节点原来的颜色也一定是黑色的,现在看到其是红色的原因因为cur的子树在调整过程中将cur的颜色由黑色变成红色的。
p为g的左孩子,cur为p的左孩子,则进行右单旋
p为g的右孩子,cur为p的右孩子,则进行左单旋
p,g变色 --p变黑,g变红。
情况3.cur为红,p为红,g为黑,u不存在/u为黑
p
为
g
的左孩子,
cur
为
p
的右孩子,则针对
p
做左单旋转;相反,
p
为
g
的右孩子,
cur
为
p
的左孩子,则针对
p
做右单旋转
则转换成了情况
2
//控制平衡
while (parent != nullptr && parent->_col == RED) //如果父亲存在并且父亲的节点为红色
{
Node* grandfather = parent->_parent;
if (parent == grandfather->_left)
{
Node* uncle = grandfather->_right;
//情况1 :叔叔节点存在且叔叔节点颜色为红
if (uncle != nullptr && uncle->_col == RED)
{
parent->_col = uncle->_col = BLACK; //父亲节点和叔叔节点变黑
grandfather->_col = RED;
//grandfather可能不是根节点,继续往上更新
cur = grandfather;
parent = cur->_parent;
}
else //情况2 + 3,uncle不存在 / 存在且为黑 可能是由情况1 -> 情况2 / 情况 3
{
// g
// p
// c
if (cur == parent->_left)
{
//右单旋
RotateR(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
else
{
//触发左右双旋
RotateL(parent);
RotateR(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
else
{
Node* uncle = grandfather->_left;
//情况1: uncle 存在且 uncle的颜色为红
if (uncle != nullptr && uncle->_col == RED)
{
parent->_col = uncle->_col = BLACK; //叔叔和父亲变色
grandfather->_col = RED;
//grandfather可能不是根节点,所以可能一直往上更新
cur = grandfather;
parent = cur->_parent;
}
else //情况2 + 3 ,uncle不存在 / 存在且为黑
{
if (cur == parent->_right) //触发左旋
{
RotateL(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
else
{
//触发右左双旋
RotateR(parent);
RotateL(grandfather);
grandfather->_col = RED;
cur->_col = BLACK;
}
break;
}
}
}
_root->_col = BLACK;
return true;
}
旋转代码:
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
Node* parentparent = parent->_parent;
parent->_left = subLR;
if (subLR != nullptr)
{
subLR->_parent = parent;
}
subL->_right = parent;
parent->_parent = subL;
if (_root == parent)
{
_root = subL;
subL->_parent = nullptr;
}
else
{
if (parentparent->_left == parent)
parentparent->_left = subL;
else
parentparent->_right = subL;
subL->_parent = parentparent;
}
}
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
Node* parentparent = parent->_parent;
parent->_right = subRL;
if (subRL != nullptr)
subRL->_parent = parent;
subR->_left = parent;
parent->_parent = subR;
if (parent == _root)
{
_root = subR;
subR->_parent = nullptr;
}
else
{
if (parentparent->_left == parent)
parentparent->_left = subR;
else
parentparent->_right = subR;
subR->_parent = parentparent;
}
}
红黑树的验证
红黑树的检测分为两步:
1.
检测其是否满足二叉搜索树
(
中序遍历是否为有序序列
)
2.
检测其是否满足红黑树的性质
bool IsBalance()
{
if (_root && _root->_col == RED)
{
std::cout << "根节点不是黑色" << std::endl;
return false;
}
// 最左路径黑色节点数量做基准值
int banchmark = 0;
Node* left = _root;
while (left)
{
if (left->_col == BLACK)
++banchmark;
left = left->_left;
}
int blackNum = 0;
return _IsBalance(_root, banchmark, blackNum);
}
bool _IsBalance(Node* root, int banchmark, int blackNum)
{
if (root == nullptr)
{
if (banchmark != blackNum)
{
std::cout << "存在路径黑色节点的数量不相等" << std::endl;
return false;
}
return true;
}
if (root->_col == RED && root->_parent->_col == RED)
{
std::cout << "出现连续红色节点" << std::endl;
return false;
}
if (root->_col == BLACK)
{
++blackNum;
}
return _IsBalance(root->_left, banchmark, blackNum)
&& _IsBalance(root->_right, banchmark, blackNum);
}
红黑树的删除
红黑树的删除本节不做讲解,有兴趣的同学可参考:《算法导论》或者《
STL
源码剖析》
http://www.cnblogs.com/fornever/archive/2011/12/02/2270692.html
http://blog.csdn.net/chenhuajie123/article/details/11951777
红黑树与AVL树的比较
红黑树和
AVL
树都是高效的平衡二叉树,增删改查的时间复杂度都是
O(log2 N
)
,红黑树不追求绝对平衡,其
只需保证最长路径不超过最短路径的
2
倍,相对而言,降低了插入和旋转的次数,所以在经常进行增删的结构
中性能比
AVL
树更优,而且红黑树实现比较简单,所以实际运用中红黑树更多。
红黑树的应用
1.
C++ STL
库
-- map/set
、
mutil_map/mutil_set
2. Java
库
3. linux
内核
4.
其他一些库
http://www.cnblogs.com/yangecnu/p/Introduce-Red-Black-Tree.html
红黑树全部代码:
RBTree.h
#pragma once
#include<iostream>
enum Colour
{
RED,
BLACK
};
template<class K,class V>
class RBTreeNode
{
public:
RBTreeNode(const std::pair<K, V>& kv)
:_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_kv(kv)
,_col(RED)
{
}
RBTreeNode<K, V>* _left;
RBTreeNode<K, V>* _right;
RBTreeNode<K, V>* _parent;
std::pair<K, V> _kv;
Colour _col;
};
template<class K,class V>
class RBTree
{
public:
typedef RBTreeNode<K, V> Node;
RBTree()
:_root(nullptr)
{
}
bool insert(const std::pair<K,V> &kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
_root->_col = BLACK;
return true;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur != nullptr)
{
if (kv.first > cur->_kv.first)
{
parent = cur;
cur = cur->_right;
}
else if (kv.first < cur->_kv.first)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
//新增节点
cur = new Node(kv);
cur->_col = RED;
if (kv.first > parent->_kv.first)
{
parent->_right = cur;
cur->_parent = parent;
}
else
{
parent->_left = cur;
cur->_parent = parent;
}
//控制平衡
while (parent != nullptr && parent->_col == RED) //如果父亲存在并且父亲的节点为红色
{
Node* grandfather = parent->_parent;
if (parent == grandfather->_left)
{
Node* uncle = grandfather->_right;
//情况1 :叔叔节点存在且叔叔节点颜色为红
if (uncle != nullptr && uncle->_col == RED)
{
parent->_col = uncle->_col = BLACK; //父亲节点和叔叔节点变黑
grandfather->_col = RED;
//grandfather可能不是根节点,继续往上更新
cur = grandfather;
parent = cur->_parent;
}
else //情况2 + 3,uncle不存在 / 存在且为黑 可能是由情况1 -> 情况2 / 情况 3
{
// g
// p
// c
if (cur == parent->_left)
{
//右单旋
RotateR(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
else
{
//触发左右双旋
RotateL(parent);
RotateR(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
else
{
Node* uncle = grandfather->_left;
//情况1: uncle 存在且 uncle的颜色为红
if (uncle != nullptr && uncle->_col == RED)
{
parent->_col = uncle->_col = BLACK; //叔叔和父亲变色
grandfather->_col = RED;
//grandfather可能不是根节点,所以可能一直往上更新
cur = grandfather;
parent = cur->_parent;
}
else //情况2 + 3 ,uncle不存在 / 存在且为黑
{
if (cur == parent->_right) //触发左旋
{
RotateL(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
else
{
//触发右左双旋
RotateR(parent);
RotateL(grandfather);
grandfather->_col = RED;
cur->_col = BLACK;
}
break;
}
}
}
_root->_col = BLACK;
return true;
}
private:
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
Node* parentparent = parent->_parent;
parent->_left = subLR;
if (subLR != nullptr)
{
subLR->_parent = parent;
}
subL->_right = parent;
parent->_parent = subL;
if (_root == parent)
{
_root = subL;
subL->_parent = nullptr;
}
else
{
if (parentparent->_left == parent)
parentparent->_left = subL;
else
parentparent->_right = subL;
subL->_parent = parentparent;
}
}
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
Node* parentparent = parent->_parent;
parent->_right = subRL;
if (subRL != nullptr)
subRL->_parent = parent;
subR->_left = parent;
parent->_parent = subR;
if (parent == _root)
{
_root = subR;
subR->_parent = nullptr;
}
else
{
if (parentparent->_left == parent)
parentparent->_left = subR;
else
parentparent->_right = subR;
subR->_parent = parentparent;
}
}
public:
void inoder()
{
Node* cur = _root;
Node* MostRight = nullptr;
while (cur != nullptr)
{
MostRight = cur->_left;
if (MostRight != nullptr)
{
while (MostRight->_right != nullptr && MostRight->_right != cur)
{
MostRight = MostRight->_right;
}
if (MostRight->_right == nullptr)
{
MostRight->_right = cur;
cur = cur->_left;
continue;
}
else
{
MostRight->_right = nullptr;
}
}
std::cout << cur->_kv.first << ":" << cur->_kv.second << std::endl;
cur = cur->_right;
}
}
bool IsBalance()
{
if (_root && _root->_col == RED)
{
std::cout << "根节点不是黑色" << std::endl;
return false;
}
// 最左路径黑色节点数量做基准值
int banchmark = 0;
Node* left = _root;
while (left)
{
if (left->_col == BLACK)
++banchmark;
left = left->_left;
}
int blackNum = 0;
return _IsBalance(_root, banchmark, blackNum);
}
bool _IsBalance(Node* root, int banchmark, int blackNum)
{
if (root == nullptr)
{
if (banchmark != blackNum)
{
std::cout << "存在路径黑色节点的数量不相等" << std::endl;
return false;
}
return true;
}
if (root->_col == RED && root->_parent->_col == RED)
{
std::cout << "出现连续红色节点" << std::endl;
return false;
}
if (root->_col == BLACK)
{
++blackNum;
}
return _IsBalance(root->_left, banchmark, blackNum)
&& _IsBalance(root->_right, banchmark, blackNum);
}
private:
Node* _root;
};
test.cpp
#include"AVL.h"
#include"RBTree.h"
void AVLTreeTest(void)
{
AVLTree<int, int> av;
int array[] = { 9,6,4,3,7,3,2,0,544,43224,23,423,42,4234,2,4242,423,42,7,11,98,5 };
for (const auto& e : array)
{
av.insert(std::pair<int,int>(e,e));
}
av.inoder();
}
void RBTreeTest(void)
{
RBTree<int, int> rb;
int array[] = { 9,6,4,3,7,3,2,0,544,43224,23,423,42,4234,2,4242,423,42,7,11,98,5 };
for (const auto& e : array)
{
rb.insert(std::pair<int, int>(e, e));
std::cout << rb.IsBalance() << std::endl;
}
rb.inoder();
}
int main()
{
//AVLTreeTest();
RBTreeTest();
}