STL源码分析之RB-tree关联容器 上
前言
本节将分析STL中难度很高的RB-tree
, 如果对红黑树有所认识的那么分析起来的难度也就不是很大, 对红黑树没有太多了解的直接来分析的难度就非常的大了, 可以对红黑树有个了解红黑树之原理和算法详细介绍. 红黑树是很类似与AVL-tree
的, 但是因为AVL-tree
在插入,删除的操作做的实际操作很多, 综合而言计算机对内存的管理都采用平衡性相对AVL-tree
较差一点的红黑树.
RB-tree
规则:
- 每个节点的颜色是黑色或者红色
- 根节点必须是黑色的
- 每个叶节点(NULL)必须是黑色的
- 如果节点是红色的, 则子节点必须是黑色的
- 从节点到每个子孙节点的路径包括的黑色节点数目相同
// 红黑定义
typedef bool __rb_tree_color_type;
const __rb_tree_color_type __rb_tree_red = false;
const __rb_tree_color_type __rb_tree_black = true;
本节就只分析RB-tree的基本结构, 但rb-tree的很多功能都是调用基本结构实现的功能, 像左旋, 右旋, 删除, 调整红黑树这些都非常的重要.
RB-tree基本结构分析
基本结构与list相似, 将节点与数据分开定义, __rb_tree_node_base
定义指针; __rb_tree_node
继承前者, 增加了数据, 就是一个完整的节点.
RB-tree基本结构
__rb_tree_node_base
struct __rb_tree_node_base
{typedef __rb_tree_color_type color_type; typedef __rb_tree_node_base* base_ptr; color_type color; // 定义节点颜色base_ptr parent; // 定义父节点base_ptr left; // 定义左孩子base_ptr right; // 定义右孩子// 查找最小节点static base_ptr minimum(base_ptr x){while (x->left != 0) x = x->left;return x;}// 查找最大节点static base_ptr maximum(base_ptr x){while (x->right != 0) x = x->right;return x;}
};
__rb_tree_node : 完整的节点
template <class Value>
struct __rb_tree_node : public __rb_tree_node_base // 继承__rb_tree_node_base
{typedef __rb_tree_node<Value>* link_type;Value value_field; // 定义节点数据
};
RB-tree迭代器
__rb_tree_base_iterator 迭代器基本结构
迭代器中increment
和decrement
函数是实现++与–的功能的核心.
struct __rb_tree_base_iterator
{typedef __rb_tree_node_base::base_ptr base_ptr;typedef bidirectional_iterator_tag iterator_category; // bidirectional_iterator_tag类型的迭代器typedef ptrdiff_t difference_type;base_ptr node; // 指针节点// ++核心函数// 节点是从node节点出发, 一直寻找右节点的左孩子, 每次找到比上次大的元素void increment(){// 有右节点, 就往右节点走if (node->right != 0) {node = node->right;// 一直往左节点走, 直到走到头while (node->left != 0)node = node->left;}// 没有右节点, 就寻找父节点else {base_ptr y = node->parent;// 如果该节点是父节点的右孩子就继续往上找, 直到y节点不是父节点的右孩子while (node == y->right) {node = y;y = y->parent;}if (node->right != y)node = y;}}// --核心代码// 节点是从node节点出发, 一直寻找左节点的右孩子, 每次找到比上次小的元素void decrement(){// 只有根节点, 每次--都是根节点if (node->color == __rb_tree_red && node->parent->parent == node)node = node->right;// 有左节点else if (node->left != 0) {// 往左节点走base_ptr y = node->left;// 只要有右节点就一直往右节点走while (y->right != 0)y = y->right;node = y;}// 没有左节点else {// 寻找父节点base_ptr y = node->parent;// 如果当前节点是父节点的左孩子就继续寻找父节点直到不再是左孩子while (node == y->left) {node = y;y = y->parent;}node = y;}}
};
__rb_tree_iterator 迭代器
template <class Value, class Ref, class Ptr>
struct __rb_tree_iterator : public __rb_tree_base_iterator // 继承__rb_tree_base_iterator
{typedef Value value_type;typedef Ref reference;typedef Ptr pointer;typedef __rb_tree_iterator<Value, Value&, Value*> iterator;typedef __rb_tree_iterator<Value, const Value&, const Value*> const_iterator;typedef __rb_tree_iterator<Value, Ref, Ptr> self;typedef __rb_tree_node<Value>* link_type;// 构造函数__rb_tree_iterator() {}__rb_tree_iterator(link_type x) { node = x; } // 初始化node节点__rb_tree_iterator(const iterator& it) { node = it.node; } // 初始化node节点// 重载指针reference operator*() const { return link_type(node)->value_field; }
#ifndef __SGI_STL_NO_ARROW_OPERATORpointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */// 重载++与--操作, 调用increment和decrement函数self& operator++() { increment(); return *this; }self operator++(int) {self tmp = *this;increment();return tmp;}self& operator--() { decrement(); return *this; }self operator--(int) {self tmp = *this;decrement();return tmp;}
};
traits编程
#ifndef __STL_CLASS_PARTIAL_SPECIALIZATION
inline bidirectional_iterator_tag
iterator_category(const __rb_tree_base_iterator&) {return bidirectional_iterator_tag();
}inline __rb_tree_base_iterator::difference_type*
distance_type(const __rb_tree_base_iterator&) {return (__rb_tree_base_iterator::difference_type*) 0;
}template <class Value, class Ref, class Ptr>
inline Value* value_type(const __rb_tree_iterator<Value, Ref, Ptr>&) {return (Value*) 0;
}
#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */
重载
// ==与!= 比较两个tree的node是相同
inline bool operator==(const __rb_tree_base_iterator& x,const __rb_tree_base_iterator& y) {return x.node == y.node;
}
inline bool operator!=(const __rb_tree_base_iterator& x,const __rb_tree_base_iterator& y) {return x.node != y.node;
}
红黑树的调整最重要的就是用左旋和右旋.
左旋
inline void
__rb_tree_rotate_left(__rb_tree_node_base* x, __rb_tree_node_base*& root)
{__rb_tree_node_base* y = x->right; // y为x的右孩子x->right = y->left; // x的右孩子为y的左孩子// 如果y的左节点不为空// 将y的左节点的父节点指向xif (y->left != 0)y->left->parent = x; // y的父节点指向x的父节点y->parent = x->parent;// 如果x就是为根节点if (x == root)root = y;// 如果x为父节点的左孩子// x的父节点的左节点指向yelse if (x == x->parent->left)x->parent->left = y;// 如果x为父节点的右孩子// x的父节点的右节点指向yelsex->parent->right = y;// y的左孩子指向x// x的父节点指向yy->left = x;x->parent = y;
}
右旋
inline void
__rb_tree_rotate_right(__rb_tree_node_base* x, __rb_tree_node_base*& root)
{__rb_tree_node_base* y = x->left; // y为x的左节点x->left = y->right; // x的左节点指向y的右节点// y有右孩子// y的的右孩子的父节点指向节点xif (y->right != 0)y->right->parent = x;// y的父节点指向x的父节点y->parent = x->parent;// 如果x为根节点// 将y改为根节点if (x == root)root = y;// x为父节点的右孩子// x的父节点的左节点指向yelse if (x == x->parent->right)x->parent->right = y;// x的父节点的左节点指向yelsex->parent->left = y;// y的右节点指向x// x的父节点指向yy->right = x;x->parent = y;
}
调整红黑树 :
- (如果) x不是根节点同时x的父节点颜色为红色
- (如果) x的父节点是x的祖节点的左孩子
- 有y为x父节点的兄弟
- (如果) y节点存在并且颜色为红色
- 将父节点和兄弟节点颜色都改为黑色
- 祖节点改为红色
- 当前节点(x)为祖节点
- (否则) y节点不存在或颜色为黑色
- x是父节点的右孩子
- 当前节点为x的父节点
- 左旋
- x父节点颜色改为黑色
- 兄弟节点颜色改为红色
- 以祖节点为节点右旋
- (否则) x的父节点是x的祖节点的右孩子
- 有y为x父节点的兄弟
- (如果) y存在并且颜色为红色
- 将父节点和兄弟节点颜色都改为黑色
- 祖节点改为红色
- 当前节点(x)为祖节点
- (否则) y节点不存在或颜色为黑色
- x是父节点的左孩子
- 右旋
- x父节点颜色改为黑色
- 兄弟节点颜色改为红色
- 以祖节点为节点左旋
- (如果) x的父节点是x的祖节点的左孩子
- (否则) 将根节点调整为黑色, 因为根节点可能会被修改
// 这里x指的当前节点, 因为后面会修改到x, 描述x就会出问题
inline void
__rb_tree_rebalance(__rb_tree_node_base* x, __rb_tree_node_base*& root)
{x->color = __rb_tree_red; // 当前节点颜色改为红色// x不是根节点同时x的父节点颜色为红色while (x != root && x->parent->color == __rb_tree_red) {/************ 1 **********/// x的父节点是x的祖节点的左孩子if (x->parent == x->parent->parent->left) {// 有y为x父节点的兄弟__rb_tree_node_base* y = x->parent->parent->right;/********* a ***********/// y节点存在并且颜色为红色if (y && y->color == __rb_tree_red) {// 将父节点和兄弟节点颜色都改为黑色// 祖节点改为红色// 当前节点(x)为祖节点x->parent->color = __rb_tree_black;y->color = __rb_tree_black;x->parent->parent->color = __rb_tree_red;x = x->parent->parent;}/********* b ***********/// y节点不存在或颜色为黑色else {// x是父节点的右孩子if (x == x->parent->right) {// 当前节点为x的父节点// 左旋x = x->parent;__rb_tree_rotate_left(x, root);}// x父节点颜色改为黑色// 兄弟节点颜色改为红色// 以祖节点为节点右旋x->parent->color = __rb_tree_black;x->parent->parent->color = __rb_tree_red;__rb_tree_rotate_right(x->parent->parent, root);}}/************ 2 **********/// x的父节点是x的祖节点的右孩子else {// 有y为x父节点的兄弟__rb_tree_node_base* y = x->parent->parent->left;/********* a ***********/// y存在并且颜色为红色if (y && y->color == __rb_tree_red) {// 将父节点和兄弟节点颜色都改为黑色// 祖节点改为红色// 当前节点(x)为祖节点x->parent->color = __rb_tree_black;y->color = __rb_tree_black;x->parent->parent->color = __rb_tree_red;x = x->parent->parent;}/********* b ***********/// y节点不存在或颜色为黑色else {// x是父节点的左孩子if (x == x->parent->left) {// 当前节点为x的父节点// 右旋x = x->parent;__rb_tree_rotate_right(x, root);}// x父节点颜色改为黑色// 兄弟节点颜色改为红色// 以祖节点为节点左旋x->parent->color = __rb_tree_black;x->parent->parent->color = __rb_tree_red;__rb_tree_rotate_left(x->parent->parent, root);}}}// 将根节点调整为黑色, 因为根节点可能会被修改root->color = __rb_tree_black;
}
删除节点
// 这里x指的当前节点, 因为后面会修改到x, 描述x就会出问题
inline __rb_tree_node_base*
__rb_tree_rebalance_for_erase(__rb_tree_node_base* z,__rb_tree_node_base*& root,__rb_tree_node_base*& leftmost,__rb_tree_node_base*& rightmost)
{// y保存z节点指针__rb_tree_node_base* y = z;__rb_tree_node_base* x = 0;__rb_tree_node_base* x_parent = 0;/******* 1 *********/// y不存在左节点if (y->left == 0) // z has at most one non-null child. y == z.// 则当前节点修改为x的右孩子x = y->right; // x might be null.// y存在左节点/******* 2 *********/else/******* a *********/ // y不存在右节点if (y->right == 0) // z has exactly one non-null child. y == z.// 则当前节点修改为x的左孩子x = y->left; // x is not null./******* b *********/ // y存在左右节点else { // z has two non-null children. Set y to// y修改为y的右节点// 如果此时y的左节点存在, 就一直往左边走// 当前节点为y的右节点y = y->right; // z's successor. x might be null.while (y->left != 0)y = y->left;x = y->right;}/******* 1 *********/ // 以上的操作就是为了找到z的边的最先的那个节点为y// y节点被修改过if (y != z) { // relink y in place of z. y is z's successor// z的左节点的父节点指向y// y的左节点指向x的左节点z->left->parent = y; y->left = z->left;/******* a *********/// y不为z的右节点if (y != z->right) {// 保存y的父节点x_parent = y->parent;// y的左或右节点存在(x), 则x的父节点指向y的父节点if (x) x->parent = y->parent;// y的父节点指向的左孩子指向x// y的右孩子指向z的右孩子// z的右孩子的父节点指向yy->parent->left = x; // y must be a left childy->right = z->right;z->right->parent = y;}// y是z的右节点elsex_parent = y; // z是根节点if (root == z)root = y;// z是父节点的左孩子else if (z->parent->left == z)z->parent->left = y; // z的父节点的左孩子指向y// z是父节点的右孩子else z->parent->right = y; // z的父节点的右孩子指向y// y的父节点指向z的父节点// 交换y和z的节点颜色// y修改为zy->parent = z->parent;__STD::swap(y->color, z->color);y = z;// y now points to node to be actually deleted}/******* 2 *********/// y没有被修改过else { // y == zx_parent = y->parent;if (x) x->parent = y->parent; // x的父节点指向y的父节点if (root == z)root = x;else if (z->parent->left == z)z->parent->left = x;elsez->parent->right = x;if (leftmost == z) if (z->right == 0) // z->left must be null alsoleftmost = z->parent;// makes leftmost == header if z == rootelseleftmost = __rb_tree_node_base::minimum(x);if (rightmost == z) if (z->left == 0) // z->right must be null alsorightmost = z->parent; // makes rightmost == header if z == rootelse // x == z->leftrightmost = __rb_tree_node_base::maximum(x);}/************ 1 **************/// y节点的颜色不为红色if (y->color != __rb_tree_red) { // x不为根节点并且x为空或颜色为黑色// 下面的分析与上面一样, 这里就不在做详细的分析了, 只要分析的时候画好图就行了while (x != root && (x == 0 || x->color == __rb_tree_black))if (x == x_parent->left) {__rb_tree_node_base* w = x_parent->right;if (w->color == __rb_tree_red) {w->color = __rb_tree_black;x_parent->color = __rb_tree_red;__rb_tree_rotate_left(x_parent, root);w = x_parent->right;}if ((w->left == 0 || w->left->color == __rb_tree_black) &&(w->right == 0 || w->right->color == __rb_tree_black)) {w->color = __rb_tree_red;x = x_parent;x_parent = x_parent->parent;} else {if (w->right == 0 || w->right->color == __rb_tree_black) {if (w->left) w->left->color = __rb_tree_black;w->color = __rb_tree_red;__rb_tree_rotate_right(w, root);w = x_parent->right;}w->color = x_parent->color;x_parent->color = __rb_tree_black;if (w->right) w->right->color = __rb_tree_black;__rb_tree_rotate_left(x_parent, root);break;}} else { // same as above, with right <-> left.__rb_tree_node_base* w = x_parent->left;if (w->color == __rb_tree_red) {w->color = __rb_tree_black;x_parent->color = __rb_tree_red;__rb_tree_rotate_right(x_parent, root);w = x_parent->left;}if ((w->right == 0 || w->right->color == __rb_tree_black) &&(w->left == 0 || w->left->color == __rb_tree_black)) {w->color = __rb_tree_red;x = x_parent;x_parent = x_parent->parent;} else {if (w->left == 0 || w->left->color == __rb_tree_black) {if (w->right) w->right->color = __rb_tree_black;w->color = __rb_tree_red;__rb_tree_rotate_left(w, root);w = x_parent->left;}w->color = x_parent->color;x_parent->color = __rb_tree_black;if (w->left) w->left->color = __rb_tree_black;__rb_tree_rotate_right(x_parent, root);break;}}if (x) x->color = __rb_tree_black;}return y;
}
总结
本节分析了基本结构, 本节重点掌握左旋, 右旋, 删除, 调整红黑树功能的实现, 掌握了这些下节对红黑树的分析就很轻松了.
STL源码分析之RB-tree关联容器 上相关推荐
- STL源码剖析(十三)关联式容器之rb_tree
STL源码剖析(十三)关联式容器之rb_tree 文章目录 STL源码剖析(十三)关联式容器之rb_tree 一.rb_tree的数据结构 二.rb_tree的迭代器 三.rb_tree的操作 3.1 ...
- SDL2源码分析之OpenGL ES在windows上的渲染过程
SDL2源码分析之OpenGL ES在windows上的渲染过程 更新于2018年11月4日. 更新于2018年11月21日. ffmpeg + SDL2实现的简易播放器 ffmpeg和SDL非常强大 ...
- STL 源码分析之string(一)基础篇
STL源码下载: https://www.sgi.com/tech/stl/download.html vs工程代码:http://download.csdn.net/download/jmh1996 ...
- STL源码剖析---红黑树原理详解上
转载请标明出处,原文地址:http://blog.csdn.net/hackbuteer1/article/details/7740956 一.红黑树概述 红黑树和我们以前学过的AVL树类似,都是在进 ...
- WebRTC源码分析-呼叫建立过程之四(上)(创建并添加本地音频轨到PeerConnection)
目录 1. 引言 2. 音频轨创建和添加 2.1 音频源AudioSource的创建 2.1.1 音频源继承树 2.1.2 近端音频源LocalAudioSource 2.1.3 远端音频源Remot ...
- vuex 源码分析_深入Vuex原理(上)
原标题:深入Vuex原理(上) 孔维国,2016年加入去哪儿网技术团队.目前在大住宿事业部/增值业务研发中心,参与开发了TMC.CRM.QTA.Auth等项目,负责node框架nomi的设计以及开发. ...
- C++ STL源码分析——一个万用的 hash function
[侯捷-SL体系结构内核分析-一个万用的 hash function] 我们知道,unordered_set / unordered_multiset / unordered_map / unorde ...
- STL源码分析-bitset
http://note.youdao.com/noteshare?id=0ea12c1fffd3866c6eddb8dc208c109d 转载于:https://www.cnblogs.com/tai ...
- stl源码分析de练习
// StlTest1.cpp : 定义控制台应用程序的入口点. //#include "stdafx.h" #include <vector> #include &l ...
最新文章
- 论一名项目经理的能力素养
- ASP.NET2.0的multiview和wizard控件
- 安全市场五巨头将面临新兴厂商的挑战
- YII 规则rule 里面 min,max 提示错误信息
- a标签创建超链接,利用a标签创建锚点
- 为什么不能线程调用类的成员函数_SLAM从0到1——13.SLAM中的多线程编程(2)
- Matlab数组及多项式运算
- Win10 CMD命令大全与超好用的快捷键
- 如何用R语言做深度学习
- maven for Mac配置,idea 配置maven
- Android利用NotificationListenerService实现消息盒子功能
- dCas9-ROS1——靶向去甲基化的捷径
- ios下 KeyChain 的研究
- python 透明图片合成_python:图片合成(PIL 库Image类模块)
- google android 市场份额,谷歌公布安卓系统市场占有率份额 碎片化依然严重
- XV Open Cup named after E.V. Pankratiev. GP of Siberia-Swimming
- 一个父亲需要挣多少钱,才能撑起一个家?
- pst文件恢复到服务器,如何修复损坏的Outlook PST文件
- Windows Server 2008 R2 服务器系统安装图文教程
- 英语信函范文之介绍信
热门文章
- Mac常用的五款思维导图软件,中文版推荐
- spreadsheet属性方法事件
- 报告预测,到2050年将有超过10亿人流离失所
- 【FPGA】十一、I2C通信回环
- 【GAMES-202实时渲染】1、软阴影01(Shadow Mapping、Peter Panning、PCSS原理超详细)
- Ruby+Appium demo
- java 匹配任意字符_正则表达式匹配任意字符(包括换行符)
- 回归预测 | MATLAB实现GWO-LSTM灰狼算法优化长短期记忆神经网络多输入单输出回归预测
- Unity UGUI DoTween 学习笔记
- 弱电时间同步系统(卫星同步时钟)医院学校标准时钟系统建设的意义