enum Colour
{
RED,
BLACK
};
template
class RBTreeNode
{
public:
RBTreeNode(const std::pair& kv)
:_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_kv(kv)
,_col(RED)
{
}
RBTreeNode* _left;
RBTreeNode* _right;
RBTreeNode* _parent;
std::pair _kv;
Colour _col;
};
思考:在节点的定义中,为什么要将节点的默认颜色给成红色的?
答:节点定义成红色是为了方便处理。
红黑树结构
为了后续实现关联式容器简单,红黑树的实现中增加一个头结点,因为跟节点必须为黑色,为了与根节点进 行区分,将头结点给成黑色,并且让头结点的 Parent
域指向红黑树的根节点,
Left
域指向红黑树中最小的 节点,Right
域指向红黑树中最大的节点,如下:
红黑树的插入操作
红黑树是在二叉搜索树的基础上加上其平衡限制条件,因此红黑树的插入可分为两步:
1. 按照二叉搜索的树规则插入新节点
template2. 检测新节点插入后,红黑树的性质是否造到破坏 因为 新节点的默认颜色是红色 ,因此:如果 其双亲节点的颜色是黑色,没有违反红黑树任何性质 ,则不 需要调整;但当新插入节点的双亲节点颜色为红色时,就违反了性质三不能有连在一起的红色节点 ,此 时需要对红黑树分情况来讨论: 约定 :cur 为当前节点, p 为父节点, g 为祖父节点, u 为叔叔节点 情况一: cur为红,p为红,g为黑,u存在且为红 解决方式:将p,u改为黑,g改为红,然后把g当成cur,继续向上调整 情况二: cur为红,p为红,g为黑,u不存在/u为黑class RBTree { public: typedef RBTreeNode Node; RBTree() :_root(nullptr) { } bool insert(const std::pair &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; } }
说明: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 #includeenum Colour { RED, BLACK }; template class RBTreeNode { public: RBTreeNode(const std::pair & kv) :_left(nullptr) ,_right(nullptr) ,_parent(nullptr) ,_kv(kv) ,_col(RED) { } RBTreeNode * _left; RBTreeNode * _right; RBTreeNode * _parent; std::pair _kv; Colour _col; }; template class RBTree { public: typedef RBTreeNode Node; RBTree() :_root(nullptr) { } bool insert(const std::pair &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 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(e,e));
}
av.inoder();
}
void RBTreeTest(void)
{
RBTree 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(e, e));
std::cout << rb.IsBalance() << std::endl;
}
rb.inoder();
}
int main()
{
//AVLTreeTest();
RBTreeTest();
}



