【STL源码剖析】第五章 关联式容器 之 RB-tree(红黑树)

2024-08-22 13:08

本文主要是介绍【STL源码剖析】第五章 关联式容器 之 RB-tree(红黑树),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

RB-tree

[ 红黑树比AVL树的优势 ]( https://blog.csdn.net/mmshixing/article/details/51692892 )

RB-tree不仅是一个二叉搜索树,而且必须满足一些规则:

  1. 每个节点不是红色就是黑色(图中深色代表黑,浅色代表红)

  2. 根节点为黑色

  3. 如果节点为红,其子节点必须为黑

  4. 任一节点至NULL(树尾端)的任何路径,所含之黑节点数必须相同

根据规则4,新增节点不许为红;根据规则3,新增节点之父节点必须为黑。当新节点根据二叉搜索树的规则到达其插入点,却未能符合上述条件时,就必须调整颜色并旋转树形。

插入节点

在图5-13的RB-tree分别插入3,8,35,75,根据二叉搜索树的规则,这四个新节点落脚处应如图5-14所示,它们破坏了RB-tree的规则,因此必须调整树形,也就是旋转树形并改变节点颜色。

假设新节点为X,其父节点为P,祖父节点为G,伯父节点(父节点的兄弟节点)为S,曾祖父节点为GG

  • 状况1:S为黑且X为外侧插入。对此情况,先对P,G做一次单选转,再更改P,G颜色,即可重新满足红黑树的规则3。

  • 状况2:S为黑且X为内测插入。对此情况,必须现对P,X做一次单选转并更改G,X颜色,再将结果对G做一次单选转,即可再次满足红黑树规则3。

  • 状况3:S为红且X为外侧插入。对此情况,现对P和G做一次单选转,并改变X的颜色。此时如果GG为黑,一切搞定,但如果GG为红,则问题比较大,见状况4。

  • 状况4:S为红且X为外侧插入。对此情况,先对P和G做一次单选转,并改便X的颜色。此时如果GG也为红。害的持续网上做,直到不再有父子连续为红的情况。

一个自上而下的程序

为避免插入节点的情况4,可以用自顶向下的方法:假设新增节点为A,就顺着A的路径,当遇到一个节点X的两个儿子都为红,就将X改为红,两个儿子改为黑。当X的父节点也为红使用情况1或情况2中的方法做调整。

RB-tree的节点设计

RB-tree有红黑二色,并且拥有左右子节点,很容易勾勒出其结构风貌。下面是SGI STL的实现源码。为了有更大的弹性,节点分为两层。

由于RB-tree的各种操作时常需要上溯其父节点,所以特别在数据结构中安排了一个parent指针。

  typedef bool __rb_tree_color_type;  const __rb_tree_color_type __rb_tree_red = false;     // 红色为0  const __rb_tree_color_type __rb_tree_black = true; // 黑色为1    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;                               }  };    template <class Value>  struct __rb_tree_node : public __rb_tree_node_base  {    typedef __rb_tree_node<Value>* link_type;    Value value_field;   //节点值  }; 
RB-tree的迭代器

SGI将RB-tree迭代器实现分为两层。图5-16是两层节点结构和双层迭代器结构间的关系,其中主要意义是: _ rb_tree_node 继承自 rb_tree_node_base ,rb_tree_iterator继承自_rb_tree_base_iterator。

RB-tree的元素操作

RB-tree提供两种插入操作:insert_unique()和insert_equal(),前者标识被插入节点的键值(key)在整棵树中必须独一无二(因此,如果整棵树中已存在相同的键值,插入操作就不会真正进行),后者标识被插入节点的键值在整棵树中可以重复,因此,无论如何插入都会成功(除非空间不足导致配置失败)。



这篇关于【STL源码剖析】第五章 关联式容器 之 RB-tree(红黑树)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1096360

相关文章

Python实现无痛修改第三方库源码的方法详解

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择... 目录需求不符合模拟示例 1. 修改源文件2. 继承修改3. 猴子补丁4. 追踪局部变量需求不符合很

如何将Tomcat容器替换为Jetty容器

《如何将Tomcat容器替换为Jetty容器》:本文主要介绍如何将Tomcat容器替换为Jetty容器问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Tomcat容器替换为Jetty容器修改Maven依赖配置文件调整(可选)重新构建和运行总结Tomcat容器替

C++从序列容器中删除元素的四种方法

《C++从序列容器中删除元素的四种方法》删除元素的方法在序列容器和关联容器之间是非常不同的,在序列容器中,vector和string是最常用的,但这里也会介绍deque和list以供全面了解,尽管在一... 目录一、简介二、移除给定位置的元素三、移除与某个值相等的元素3.1、序列容器vector、deque

C++常见容器获取头元素的方法大全

《C++常见容器获取头元素的方法大全》在C++编程中,容器是存储和管理数据集合的重要工具,不同的容器提供了不同的接口来访问和操作其中的元素,获取容器的头元素(即第一个元素)是常见的操作之一,本文将详细... 目录一、std::vector二、std::list三、std::deque四、std::forwa

Python容器类型之列表/字典/元组/集合方式

《Python容器类型之列表/字典/元组/集合方式》:本文主要介绍Python容器类型之列表/字典/元组/集合方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. 列表(List) - 有序可变序列1.1 基本特性1.2 核心操作1.3 应用场景2. 字典(D

Spring 中 BeanFactoryPostProcessor 的作用和示例源码分析

《Spring中BeanFactoryPostProcessor的作用和示例源码分析》Spring的BeanFactoryPostProcessor是容器初始化的扩展接口,允许在Bean实例化前... 目录一、概览1. 核心定位2. 核心功能详解3. 关键特性二、Spring 内置的 BeanFactory

mysql关联查询速度慢的问题及解决

《mysql关联查询速度慢的问题及解决》:本文主要介绍mysql关联查询速度慢的问题及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录mysql关联查询速度慢1. 记录原因1.1 在一次线上的服务中1.2 最终发现2. 解决方案3. 具体操作总结mysql

Go语言中三种容器类型的数据结构详解

《Go语言中三种容器类型的数据结构详解》在Go语言中,有三种主要的容器类型用于存储和操作集合数据:本文主要介绍三者的使用与区别,感兴趣的小伙伴可以跟随小编一起学习一下... 目录基本概念1. 数组(Array)2. 切片(Slice)3. 映射(Map)对比总结注意事项基本概念在 Go 语言中,有三种主要

MYSQL关联关系查询方式

《MYSQL关联关系查询方式》文章详细介绍了MySQL中如何使用内连接和左外连接进行表的关联查询,并展示了如何选择列和使用别名,文章还提供了一些关于查询优化的建议,并鼓励读者参考和支持脚本之家... 目录mysql关联关系查询关联关系查询这个查询做了以下几件事MySQL自关联查询总结MYSQL关联关系查询

Go中sync.Once源码的深度讲解

《Go中sync.Once源码的深度讲解》sync.Once是Go语言标准库中的一个同步原语,用于确保某个操作只执行一次,本文将从源码出发为大家详细介绍一下sync.Once的具体使用,x希望对大家有... 目录概念简单示例源码解读总结概念sync.Once是Go语言标准库中的一个同步原语,用于确保某个操