SGISTL源码探究-STL中的红黑树(上)

SGI STL内存池源码剖析 SGI STL内存池源码理解,附代码 阅读详情

前言

本小节将进入到SGISTL的红黑树部分。关于红黑树,是一种比较复杂的数据结构,但是并不是特别难。如果对红黑树不太了解,可以去网上查阅相关的资料,因为本文的主要目的是分析STL中的红黑树的源码,和普通的红黑树略有不同,还要复杂一些,需要有一定的基础。

基本概念

首先什么是二叉搜索树,二叉搜索树即符合任何一个节点的值一定大于其左子树的任何一个节点的值并且小于其右子树的任何一个节点的值(节点的值不允许重复),我们把符合这样一个性质的二叉树称为二叉搜索树。二叉搜索树的查找、插入、删除的平均效率很高,为O(logn)。
但是请思考这样一个场景,插入一个递增的有序数组。这样会使得二叉搜索树退化成链表,而链表的复杂度大家都知道。
为了解决这个问题,引入了平衡二叉搜索树,在还是一个二叉搜索树的前提下,加入了对平衡性的控制。简单来说就是不允许某节点的两个子树的深度相差太大,如果超过标准,则进行调整。

简单的介绍一下红黑树的四大性质:
1. 根节点为黑
2. 每个节点为红色或者黑色
3. 如果一个节点是红色的,则它的左右孩子节点都为黑色
4. 对每个节点,从该节点到其所有后代叶节点的路径上,均包含相同数目的黑色节点。

红黑树属于平衡二叉搜索树的一种,它对平衡的要求不像AVL树那么严格,但是因为以上的几个特性使得一棵有n个节点的红黑树的高度保持在logn,并且它的插入、删除、查找操作的时间复杂度也是O(logn),总的来说是一个很经典并且高效的树。

当我们对红黑树进行插入、删除时,可能会导致红黑树无法满足以上的性质3或4,这样我们就需要操作来调整红黑树,使得它重新满足一棵红黑树的性质。这样的操作有左旋、右旋、双旋等,在这里我们不去将它们具体是怎么旋转的,而是在源码中分析。

源码分析

关于rb_tree,所有的源码都在stl_tree.h中,实现一棵完整的红黑树的代码量一般都在几百行,由于stl需要对其进行泛化,所以代码量有1099行左右。关于红黑树的插入操作,算是比较简单了,它的删除操作需要分的情况特别多,而《STL源码剖析》一书中也并未提到删除操作,关于这一块,可能需要你查阅其他资料并且尝试自己跟着画图去进行理解。
接下来,我们按照它的节点设置,以及迭代器,定义部分、构造/析构函数、一些简单的成员函数,各种复杂的操作这样的顺序来依次分析。

节点设置

红黑树的每个节点有红色/黑色其中一种颜色,在stl中,由true和false表示。

//红色为false,黑色为true
typedef bool __rb_tree_color_type;
const __rb_tree_color_type __rb_tree_red = false;
const __rb_tree_color_type __rb_tree_black = true;

//红黑树的节点(无值部分)
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;
};
红黑树的迭代器

关于红黑树的迭代器部分,increment以及decrement中,有两种情况比较诡异。这都是因为SGISTL实现红黑树时使用了小技巧,在根节点(root)上面还有一个header节点。
当红黑树处于初始状态时,只有header节点(为红色),它的左右孩子初始状态指向自己,当插入节点时,header的父节点指向根结点,左子节点指向最小的节点,右子节点指向最大的节点。
图解如下:
这里写图片描述

//迭代器的基础类
struct __rb_tree_base_iterator
{
  typedef __rb_tree_node_base::base_ptr base_ptr;
  typedef bidirectional_iterator_tag iterator_category;
  typedef ptrdiff_t difference_type;
  base_ptr node;

  /* 用于实现迭代器++
   * 其实就是找到当前节点的值的下一个最近的值
   */
  void increment()
  {
    /* 有右子树时,一直往右子树的左子树走到底
     * 即可找到当前节点的下一个值
     */
    if (node->right != 0) {
      node = node->right;
      while (node->left != 0)
        node = node->left;
    }
    else {
      /* 没有右子树时,则只有往上找了
       * 这是因为由于二叉搜索树的特性
       * 比node值大的只能是在上层中
       * 若当前节点是其父节点的右孩子
       * 则一直上移(这是因为若是右孩子,则比父节点的值大,所以不可取)
       * 只有当当前节点为父节点的左孩子时,才能取得该值
       /

      /* 这里注意一个特殊的情况,即当node为root节点并且无右子树时
       * 此时的y为header,而y->right=root
       * 所以会进一次循环,将node更新为header,y更新为root
       * 此时由于y->right=null!=node所以退出循环
       * 接下来不会进入node->right != y这个条件判断,将node置成y
       * 结果就是node指向header
       * 这种情况很特殊,网上该部分大多数都是直接抄书,这里请配合我画的图进行理解
       */
      base_ptr y = node->parent;
      while (node == y->right) {
        node = y;
        y = y->parent;
      }
      /* 此时节点的右孩子不为父节点
       * 这个判断看起来很奇怪,因为y不是node的父节点吗
       * 其实为了处理当node为root时并且root无右子树的特殊情况
       * 若不是这种特殊情况,那么node就该取其父节点的值,因为node是y的左孩子,而y的值大于其左子树
       */
      if (node->right != y)
        node = y;
    }
  }
  /供重载--操作符调用
  void decrement()
  {
    /* 这里又是一种特殊的情况,配合上面的图还是很容易理解的
     * 特殊情况:当node指向header时
     * header的颜色为红色,并且header的父节点的父节点为本身,满足条件
     * 对应前面只有根结点并且根结点无右子树,进行++为header的情况
     * 这里指向header,进行--,应该为header的右子树,为整棵红黑树的最大值节点
     */
    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;
    }
  }
};

//迭代器
template <class Value, class Ref, class Ptr>
struct __rb_tree_iterator : public __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; }
  __rb_tree_iterator(const iterator& it) { node = it.node; }

  //重载* 和 ->操作符,比较简单
  reference operator*() const { return link_type(node)->value_field; }
#ifndef __SGI_STL_NO_ARROW_OPERATOR
  pointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */

  //重载++操作符,主要就是调用了基类的increment函数
  self& operator++() { increment(); return *this; }
  self operator++(int) {
    self tmp = *this;
    increment();
    return tmp;
  }

  //重载--操作符,主要调用了基类的decrement函数
  self& operator--() { decrement(); return *this; }
  self operator--(int) {
    self tmp = *this;
    decrement();
    return tmp;
  }
};

关于红黑树的迭代器部分就这样,它和红黑树的节点有这样的联系。(这里直接使用了《STL源码剖析》书中的图。
这里写图片描述

定义部分及构造/析构、一些简单的成员函数

该部分主要是介绍红黑树的相关定义以及初始化、构造等,还有一些简单的函数。比较复杂的操作,如插入、删除等,我们放在下一小节分析。
以下是定义部分,以及一些获取节点成员的函数。

template <class Key, class Value, class KeyOfValue, class Compare,
          class Alloc = alloc>
/* 首先我们应该注意的是模板的参数
 * key代表红黑树上存储节点时依据的值
 * value即节点的值
 * KeyOfValue是仿函数,用于通过value获取到key,至于仿函数是什么,现在没必要知道,我们后面会进行专门的分析
 * Compare为比较key大小的标准
 * Alloc就是我们熟悉的空间配置器了
 */
class rb_tree {
protected:
  //一些简单的类型声明以及专属空间配置器
  typedef void* void_pointer;
  typedef __rb_tree_node_base* base_ptr;
  typedef __rb_tree_node<Value> rb_tree_node;
  typedef simple_alloc<rb_tree_node, Alloc> rb_tree_node_allocator;
  typedef __rb_tree_color_type color_type;
public:
  typedef Key key_type;
  typedef Value value_type;
  typedef value_type* pointer;
  typedef const value_type* const_pointer;
  typedef value_type& reference;
  typedef const value_type& const_reference;
  typedef rb_tree_node* link_type;
  typedef size_t size_type;
  typedef ptrdiff_t difference_type;
protected:
  //获取一个新的节点(注意还没初始化)
  link_type get_node() { return rb_tree_node_allocator::allocate(); }
  //释放指定节点
  void put_node(link_type p) { rb_tree_node_allocator::deallocate(p); }
  //创建一个节点并初始化为x
  link_type create_node(const value_type& x) {
    link_type tmp = get_node();
    __STL_TRY {
      construct(&tmp->value_field, x);
    }
    __STL_UNWIND(put_node(tmp));
    return tmp;
  }
  //复制节点,包括颜色
  link_type clone_node(link_type x) {
    link_type tmp = create_node(x->value_field);
    tmp->color = x->color;
    tmp->left = 0;
    tmp->right = 0;
    return tmp;
  }
  //销毁节点
  void destroy_node(link_type p) {
    destroy(&p->value_field);
    put_node(p);
  }

protected:
  size_type node_count; // keeps track of size of tree
  //header节点
  link_type header;
  //大小比较的标准,因为节点的类型并不是只能int之类的,也可能是对象,所以需要有一个比较大小的标准  
  Compare key_compare;

  /* 获取根结点 */
  link_type& root() const { return (link_type&) header->parent; }
  /* 获取红黑树的key值最小的节点
   * header的左孩子指向key值最小的节点
   */
  link_type& leftmost() const { return (link_type&) header->left; }
  /* 获取红黑树的key值最大的节点
   * header的右孩子指向key值最大的节点
   */
  link_type& rightmost() const { return (link_type&) header->right; }

  //返回当前节点的左孩子
  static link_type& left(link_type x) { return (link_type&)(x->left); }
  static link_type& right(link_type x) { return (link_type&)(x->right); }
  //返回当前节点的右孩子
  static link_type& parent(link_type x) { return (link_type&)(x->parent); }
  //获取当前节点的value
  static reference value(link_type x) { return x->value_field; }
  //通过value获取当前节点的key
  static const Key& key(link_type x) { return KeyOfValue()(value(x)); }
  //获取当前节点的颜色
  static color_type& color(link_type x) { return (color_type&)(x->color); }

  static link_type& left(base_ptr x) { return (link_type&)(x->left); }
  static link_type& right(base_ptr x) { return (link_type&)(x->right); }
  static link_type& parent(base_ptr x) { return (link_type&)(x->parent); }
  static reference value(base_ptr x) { return ((link_type)x)->value_field; }
  static const Key& key(base_ptr x) { return KeyOfValue()(value(link_type(x)));}
  static color_type& color(base_ptr x) { return (color_type&)(link_type(x)->color); }
  //获取最小值和最大值
  static link_type minimum(link_type x) {
    return (link_type)  __rb_tree_node_base::minimum(x);
  }
  static link_type maximum(link_type x) {
    return (link_type) __rb_tree_node_base::maximum(x);
  }

public:
  //声明迭代器
  typedef __rb_tree_iterator<value_type, reference, pointer> iterator;
  typedef __rb_tree_iterator<value_type, const_reference, const_pointer>
          const_iterator;

......
private:
  //定义插入、复制、删除操作,注意前面加了下划线,证明是由提供给外部的插入、复制、删除操作调用的
  iterator __insert(base_ptr x, base_ptr y, const value_type& v);
  link_type __copy(link_type x, link_type p);
  void __erase(link_type x);
  //初始化,即红黑树的初始状态
  void init() {
    //给header申请空间并将颜色置为红
    header = get_node();
    color(header) = __rb_tree_red; // used to distinguish header from
                                   // root, in iterator.operator++
    /* 根结点为空并且header的左右孩子指向自己
     * 这样的用法第一次见可能有点奇怪,不过它是合法的,因为是左值引用
     */
    root() = 0;
    leftmost() = header;
    rightmost() = header;
  }

以下便是构造/析构函数部分

public:
                                // allocation/deallocation
  //设置大小比较标准,并且调用init()进行初始化
  rb_tree(const Compare& comp = Compare())
    : node_count(0), key_compare(comp) { init(); }
  //拷贝构造函数
  rb_tree(const rb_tree<Key, Value, KeyOfValue, Compare, Alloc>& x)
    : node_count(0), key_compare(x.key_compare)
  {
    //设置header
    header = get_node();
    color(header) = __rb_tree_red;
    /* 若x无根结点,就比较简单了,将header的左右孩子节点设置为自己即可
     * 否则调用__copy函数进行拷贝,并设置header,最后将node_count更新
     */
    if (x.root() == 0) {
      root() = 0;
      leftmost() = header;
      rightmost() = header;
    }
    else {
      __STL_TRY {
        root() = __copy(x.root(), header);
      }
      __STL_UNWIND(put_node(header));
      leftmost() = minimum(root());
      rightmost() = maximum(root());
    }
    node_count = x.node_count;
  }
  /* 析构函数
   * 调用clear删除除了header之外的所有节点
   * 最后删除header节点
   */
  ~rb_tree() {
    clear();
    put_node(header);
  }
  rb_tree<Key, Value, KeyOfValue, Compare, Alloc>&
  operator=(const rb_tree<Key, Value, KeyOfValue, Compare, Alloc>& x);

以下是一些简单的函数

public:    
                                // accessors:
  Compare key_comp() const { return key_compare; }
  //起始迭代器是最小节点
  iterator begin() { return leftmost(); }
  const_iterator begin() const { return leftmost(); }
  //末尾迭代器是header
  iterator end() { return header; }
  const_iterator end() const { return header; }
  ......
  bool empty() const { return node_count == 0; }
  size_type size() const { return node_count; }
  size_type max_size() const { return size_type(-1); }

小结

在本小节中,我们了解了SGISTL中的红黑树的节点、迭代器及部分实现,它主要是为了实现set、map容器奠定下了基础。在下一小节中,我们将针对它的插入、删除等复杂的操作进行分析。

STL源码剖析——RB-Tree(红黑树) 前言 有关红黑树的zh 阅读详情

相关推荐

别再手动续期SSL证书了!用acme.sh配合阿里云DNS API,实现全自动HTTPS证书管理

本文详细介绍了如何使用acme.sh配合阿里云DNS API实现SSL/TLS证书的全自动管理,彻底解决手动续期带来的风险与不便。通过自动化部署流程,包括环境准备、API集成、多域名证书申请等关键步骤,帮助运维人员构建高效、可靠的HTTPS证书管理体系,显著提升安全性和运维效率。

weixin_29200485的博客 271

红黑树(带头结点)

bool blacknum(node* root, int sum,int num)//用来检测每个路径的黑色节点个数是否相等。bool singlered(node* root)//用来检测是否有连续的红色结点。bool IsBalanceTree()//检测函数。node* rightmax()//树的最右节点。node* leftmin()//树的最小节点。

2401_86702190的博客 674

BEVFormer vs BEVFusion:5个关键差异点帮你选对环视感知方案

本文深入对比了自动驾驶领域两大主流环视感知方案BEVFormer与BEVFusion。BEVFormer作为纯视觉BEV感知的标杆,通过注意力机制隐式学习深度,成本较低;而BEVFusion作为多模态融合典范,融合激光雷达与摄像头数据,在性能、小目标检测及极端环境鲁棒性上优势显著。文章从计算效率、部署成本、数据依赖性等五个核心维度提供选型指南,帮助技术决策者根据自身算力预算与传感器配置做出明智选择。

weixin_29306011的博客 124

stl map底层之红黑树插入步骤详解与代码实现

文章用图片的方式对红黑树插入过程的调整进行了详细解释。并给出红黑树插入调整实现的C++源码。

mxway的专栏 2万+

第1期技术: DQN算法原理及实现过程

利用神经网络近似值函数的方法表示为: V^(s,w)≈Vπ(s)q^(s,a,w)≈qπ(s,a) \hat{V}(s, w) \approx V_{\pi}(s) \\ \hat{q}(s, a, w) \approx q_{\pi}(s, a) V^(s,w)≈Vπ​(s)q^​(s,a,w)≈qπ​(s,a) 那么具体的工作过程是怎样实现的? 以及如何从端到端的过程,本文将讲解Deep Q Network(DQN, 而这正是由DeepMind于2013年和2015年分别提出的两篇论文《Playi

深度强化学习实验室:一个“开源开放、共享共进”的强化学习学术组织。 4955

Windows BITS服务:后台智能文件传输技术详解

后台文件传输技术是现代IT基础设施中的关键组件,Windows BITS(Background Intelligent Transfer Service)作为微软原生解决方案,通过队列管理和智能调度实现高效数据传输。其核心技术原理包括分块传输、断点续传和带宽自适应,能够根据网络状况动态调整传输速率(默认占用空闲带宽的80%)。在工程实践中,BITS特别适用于企业软件分发和自动化数据采集场景,通过PowerShell命令即可实现高优先级传输和代理配置。相比传统FTP方案,BITS在跨国文件传输中将失败率从30

weixin_42116058的博客 281

红黑树实现源码(C++)

本文展示红黑树的源码,源码是作者由linux内核代码封装成C++类,然后再次封装成API函数的方式。 RBTree.h和RBTree.cpp是用c++类的方式实现了红黑树的封装,RbtAPI.h、RbtAPI.cpp实现了二次封装,更方便开发人员直接使用。 1、RBTree.h #ifndef RBTREE_H #define RBTREE_H #include "RbtAPI.h" #define RB_RED 0 #define RB_BLACK 1 typedef struct r..

freeland008的专栏 1081

STM32实战:电容触摸屏I2C转USB HID设备全解析

本文详细解析了基于STM32的电容触摸屏I2C转USB HID设备实现方案。通过硬件选型、协议分析和代码实现,展示了如何将GT911触摸屏数据转换为标准USB HID协议,并提供了关键调试经验与性能优化技巧,为智能家居控制面板等应用提供高性价比解决方案。

weixin_42548829的博客 320

【C++】-- STL之用红黑树模拟实现map和set

用红黑树同时封装出set和map时,set传给value的是一个value,map传给value的是一个pair,set和map传给红黑树的value决定了这棵树里面存的节点值类型。上层容器不同,底层红黑树的Key和T也不同。

局部变量和全局变量 1295

Odoo 入门 | 什么是 Odoo?

Odoo是一套全球开源的ERP/CRM系统,最初的名字为TinyERP,08年5月之后称之为OpenERP,之后又改为Odoo。

洛阳泰山的博客 6208

Atlas 300I Duo - vllm部署Qwen3-VL-8B-Instruct

本文介绍了在Ascend NPU环境下部署Qwen3-VL-8B大语言模型的步骤。主要包括:1)安装驱动、docker和vllm镜像;2)创建特权容器并挂载设备与目录;3)进入容器安装指定版本的transformers;4)设置环境变量和NPU卡配置;5)启动vllm服务;6)测试API接口。部署过程涉及多块NPU卡的使用,需注意内存碎片化问题,最终通过vllm框架提供模型推理服务。

m0_50105717的博客 1561

SGISTL源码探究-STL中的红黑树(下)

前言在上一小节中,我们针对SGISTL中的红黑树的分析完成了一半,接下来的各种操作才是重点的部分。通过以下分析可以了解到红黑树是如何保持平衡的。(STL中实现红黑树定义的重载版本函数太多,我舍去了一部分定义,直接对其声明进行分析,不然篇幅太长)红黑树的常用操作clear上一小节中,析构函数调用了clear,它的实现如下 void clear() { if (node_count != 0)

Move_now的博客 872

金融数字化——详解2025年金融智能体深度应用报告【附全文阅读】

《2025年金融智能体深度应用报告》显示,金融智能体已实现80%部署率,推动行业效率提升30%-50%。报告指出智能体通过"感知-推理-规划-执行-进化"机制突破大模型局限,在风控、客服、投研等100+场景实现自动化。典型案例显示,工商银行信贷审批效率提升60%,蚂蚁数科智能客服解决80%问题。尽管面临系统协同、标准缺失等挑战,未来趋势将向多模态交互、自主进化和ESG投资等方向拓展。

cdfunlove的博客 205

SGISTL源码探究-关联式容器:multimap

前言在本小节中我们将分析multimap的实现。它和map的最大的不同之处在于,map不允许重复的键值插入,而multimap允许重复的键值插入,对应到底层的实现,multimap调用的是insert_equal进行插入操作,而map调用的是insert_unique进行插入操作。 另外还有一个不同之处是multimap不支持下标运算,这个也很合理,因为可能有重复键,访问下标时可能就对应了多个值,

Move_now的博客 863

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

SGISTL源码阅读二十 map关联式容器

SGISTL源码阅读二十 map关联式容器 前言 map是一种关联式容器,底层同样是红黑树实现的,所有的元素都会根据元素的键值自动被排序。map中所有的元素pair,pair将两个数据合成一个,将pair的第一个值视为键值,第二个值视为实值,非常符合key``````value的要求。 我们知道set保证了数据的唯一性,map也一样,在map中不允许两个元素拥有相同的键值。 深入源码 map的定义...

Lyn&Xx 470

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

[STL] SGI STL红黑树实现的边界条件

背景 SGI STL红黑树实现上的特殊点,在于红黑树有一个header辅助节点; - 该header的父节点为root节点; - 其左节点为当前二叉树中的最小值(最左); - 其右节点为当前二叉树中的最大值(最右); - 该节点本身就正好用来当做end迭代器; 其初始化代码如下: void init() { header = new Node(); hea...

sai_j的博客 364

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

【C++取经之路】红黑树封装set

本文参考《STL源码剖析》中SGI STL对红黑树的结构设计,涉及到红黑树迭代器的实现等,所以在读这篇文章之前,我希望你对红黑树有一定的了解,比如在红黑树插入时的变色和旋转操作,最好自己实现过。不然这篇文章对你可能不太友好,因为本文对红黑树的结构设计较为复杂,插入时的操作细节不会在本文详细说明。说实话,封装set对其实很简单,难点在于前期的红黑树设计上,在设计上的一些细节还是很有挑战的。下面我们进入正题,一起领略写SGI STL的大佬们的风采。//旋转时需要访问父节点//颜色//数据域{}

记录代码路上的点滴思考。 902

SGISTL源码阅读十九 set关联式容器

SGISTL源码阅读十九 set容器 前言 之前我们已经分析了vector,list,deque三个容器。如果按照“数据在容器中的排列”特性,容器可以分为序列式(sequence)和关联式(associative)两种,前面学习过的三种容器都是序列式容器。 接下来我们将学习关联式容器。标准的STL关联式容器分为set(集合)和map(映射表)两大类,以及这两大类的衍生体muiltiset(多键集合...

Lyn&Xx 321

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

5.1 树的导览      标准的STL关联式容器分为set(集合)和map(映射表)两大类,以及这两大类的衍生体multiset(多键集合)和multimap(多键映射表)。这些容器的底层机制均以RB-tree(红黑树)完成。RB-tree也是一个独立的容器,但并不开放给外界使用。 此外,SGI STL还提供了一个不在标准规格之列的关联式容器:hash table(散列表),以及以此hash

灯火阑珊处 758

SGISTL源码-容器 笔记

本文是在阅读SGI STL v3.3源码中,遇到的一些问题及有意思的点。本文建立在已经观看过侯捷老师STL源码剖析课程的基础上。是在阅读源码过程中,对其中的内容进行补充、修饰。

weixin_46065476的博客 596

STL源码剖析 1、STL概论与令人困惑的一些语法

STL概论 STL的诞生 软件界一直希望建立一种可重复运用的东西,即提升复用性。复用性必须建立在某种标准之上。 为了建立数据结构与算法的一套标准,并且降低其间的耦合关系以提升各自的独立性、弹性、相互合作性,STL诞生了 STL组件 ●容器(container):常用数据结构,大致分为两类,序列容器,如vector,list,deque,关联容器,如set,map。在实现上,是类模板(class template) ●迭代器(iterator):一套访问容器的接口,行为类似于指针。它为不同算法提供的相对统一的

ziggy7的博客 358

SGISTL源码探究-关联式容器:multiset

前言multiset和set的实现十分相似,除了允许键值重复之外,几乎一样。而实现允许键值重复这一功能的是红黑树中提供的操作insert_equal,接下来我们就进入到它的源码,顺便也复习一下set,看看到底和set有什么不同。multiset的实现#ifndef __STL_LIMITED_DEFAULT_TEMPLATES template <class Key, class Compare =

Move_now的博客 847

SGISTL源码探究-关联式容器:set

前言在本小节中,我们将分析set容器,它的特性是,所有的元素会根据键值自动在set内部排序,set的键值就是实值,并且不允许两个相同值的元素在set中存在。并且set的元素值不能通过迭代器进行改变,因为一旦改变,就意味着set内部有序就被打破了。 set实现的机制和map一样,同样以红黑树作为底部实现,而关于set的操作,也只用调用红黑树提供的接口就行了。set的实现定义部分#ifndef __S

Move_now的博客 686

《STL源码剖析》提炼总结:概览

最近在看侯捷的《STL源码剖析》,想分享几篇心得,目的是学习C++和泛型编程。从一开始本人就没打算事无巨细面面俱到,毕竟毫无重点也不是阅读源码的好习惯。所以本人打算把重点放在空间配置器,迭代器,容器以及少量算法的实现上。这四者已能体现STL的大部分设计精髓。至于仿函数和配接器,暂不做打算。 除这篇之外,这个系列暂定写6篇,分别对应空间配置器allocator,迭代器iterator,序列容器vector,红黑树的实现,关联容器map和算法。 1. 准备 C++编译器,最好是GCC SGI STL的源

syj_comeon的专栏 291

SGISTL源码探究-关联式容器:map

前言在本小节中,我们将分析map容器,它与set最大的不同就是,它是key-value型的,而set的key和value是同一个。map和set底层都由红黑树实现,map上存储的都是pair,即键值对,存储到红黑树中时,排序依据的就是pair的第一个元素。 之前提到在set中,不允许更改元素的值,而在map中,key值同样不允许修改,但是value可以修改,因为value不涉及到map整体内部结构

Move_now的博客 913

学习笔记----STL源码剖析

自己的学习笔记

2301_80428401的博客 684
上一篇: SGISTL源码探究-优先级队列
下一篇: SGISTL源码探究-STL中的红黑树(下)
UKey_
博客等级 码龄10年 258粉丝 186原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值