C++之深入解析STL deque容器的底层实现原理

news2024/11/28 6:35:23

一、deque 容器的存储结构

  • 事实上,STL 中每个容器的特性,和它底层的实现机制密切相关,deque 自然也不例外,deque 容器擅长在序列的头部和尾部添加或删除元素。
  • 想搞清楚 deque 容器的实现机制,需要先了解 deque 容器的存储结构以及 deque 容器迭代器的实现原理。
  • 和 vector 容器采用连续的线性空间不同,deque 容器存储数据的空间是由一段一段等长的连续空间构成,各段空间之间并不一定是连续的,可以位于在内存的不同区域。为了管理这些连续空间,deque 容器用数组(数组名假设为 map)存储着各个连续空间的首地址。也就是说,map 数组中存储的都是指针,指向那些真正用来存储数据的各个连续空间。如下所示:

在这里插入图片描述

  • 通过建立 map 数组,deque 容器申请的这些分段的连续空间就能实现“整体连续”的效果。换言之,当 deque 容器需要在头部或尾部增加存储空间时,它会申请一段新的连续空间,同时在 map 数组的开头或结尾添加指向该空间的指针,由此该空间就串接到了 deque 容器的头部或尾部。
  • 可能你会问,如果 map 数组满了怎么办?很简单,再申请一块更大的连续空间供 map 数组使用,将原有数据(很多指针)拷贝到新的 map 数组中,然后释放旧的空间。
  • deque 容器的分段存储结构,提高了在序列两端添加或删除元素的效率,但也使该容器迭代器的底层实现变得更复杂。

二、deque 容器迭代器的底层实现

  • 由于 deque 容器底层将序列中的元素分别存储到不同段的连续空间中,因此要想实现迭代器的功能,必须先解决如下两个问题:
    • 迭代器在遍历 deque 容器时,必须能够确认各个连续空间在 map 数组中的位置;
    • 迭代器在遍历某个具体的连续空间时,必须能够判断自己是否已经处于空间的边缘位置;如果是,则一旦前进或者后退,就需要跳跃到上一个或者下一个连续空间中。
  • 为了实现遍历 deque 容器的功能,deque 迭代器定义如下的结构:
template<class T,...>
struct __deque_iterator{
    ...
    T* cur;
    T* first;
    T* last;
    map_pointer node;//map_pointer 等价于 T**
}
  • 可以看到,迭代器内部包含 4 个指针,它们各自的作用为:
    • cur:指向当前正在遍历的元素;
    • first:指向当前连续空间的首地址;
    • last:指向当前连续空间的末尾地址;
    • node:它是一个二级指针,用于指向 map 数组中存储的指向当前连续空间的指针。
  • 借助这四个指针,deque 迭代器对随机访问迭代器支持的各种运算符进行了重载,能够对 deque 分段连续空间中存储的元素进行遍历。例如:
// 当迭代器处于当前连续空间边缘的位置时,如果继续遍历,就需要跳跃到其它的连续空间中,该函数可用来实现此功能
void set_node(map_pointer new_node) {
    node = new_node;	// 记录新的连续空间在 map 数组中的位置
    first = *new_node;  // 更新 first 指针
    // 更新 last 指针,difference_type(buffer_size())表示每段连续空间的长度
    last = first + difference_type(buffer_size());
}
// 重载 * 运算符
reference operator*() const{return *cur;}
pointer operator->() const{return &(operator *());}
// 重载前置 ++ 运算符
self & operator++() {
    ++cur;
    // 处理 cur 处于连续空间边缘的特殊情况
    if(cur == last) {
        // 调用该函数,将迭代器跳跃到下一个连续空间中
        set_node(node+1);
        // 对 cur 重新赋值
        cur = first;
    }
    return *this;
}
// 重置前置 -- 运算符
self& operator--() {
    // 如果 cur 位于连续空间边缘,则先将迭代器跳跃到前一个连续空间中
    if(cur == first){
        set_node(node-1);
        cur == last;
    }
    --cur;
    return *this;
}

三、deque 容器的底层实现

  • 了解了 deque 容器底层存储序列的结构,以及 deque 容器迭代器的内部结构之后,那么来看看 deque 容器究竟是如何实现的。
  • deque 容器除了维护先前讲过的 map 数组,还需要维护 start、finish 这 2 个 deque 迭代器。如下所示,为 deque 容器的定义:
// _Alloc为内存分配器
template<class _Ty,
    class _Alloc = allocator<_Ty>>
class deque{
    ...
protected:
    iterator start;
    iterator finish;
    map_pointer map;
...
}
  • 其中,start 迭代器记录着 map 数组中首个连续空间的信息,finish 迭代器记录着 map 数组中最后一个连续空间的信息。另外需要注意的是,和普通 deque 迭代器不同,start 迭代器中的 cur 指针指向的是连续空间中首个元素;而 finish 迭代器中的 cur 指针指向的是连续空间最后一个元素的下一个位置。
  • 因此,deque 容器的底层实现如下所示:

在这里插入图片描述

  • 借助 start 和 finish,以及 deque 迭代器中重载的诸多运算符,就可以实现 deque 容器提供的大部分成员函数,比如:
// begin() 成员函数
iterator begin() {
	return start;
}
// end() 成员函数
iterator end() { 
	return finish;
}
// front() 成员函数
reference front() {
	return *start;
}
// back() 成员函数
reference back(){
    iterator tmp = finish;
    --tmp;
    return *tmp;
}
// size() 成员函数
size_type size() const {
	return finish - start;
} // deque迭代器重载了 - 运算符
// enpty() 成员函数
bool empty() const {
	return finish == start;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/423340.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Python】实战:生成有关联单选问卷 csv《营养不良风险评估表》

目录 一、适用场景 二、业务需求 三、Python 文件 &#xff08;1&#xff09;创建文件 &#xff08;2&#xff09;示例代码 四、csv 文件 &#xff08;1&#xff09;营养不良风险评估表&#xff08;问题 6 不选“不能取得”&#xff09; &#xff08;2&#xff09;营养…

从输入url到页面展现(一)从浏览器解析url开始

前端面试有一道很考验人的问题&#xff0c;那就是&#xff1a;请你说一下从用户从输入url到页面展现的过程是怎样的&#xff1f;在接下来的一段时间呢&#xff0c;狗哥会从这一问题出发&#xff0c;开始剖析这个过程&#xff0c;希望可以让更多的小伙伴掌握到这个过程&#xff…

【加载plist文件展示单组数据 Objective-C语言】

一、接下来,我们要为大家演示如何通过加载plist文件,使用UITableView展示单组数据, 1.最后运行起来的效果,是一个什么效果呢,是这样一个效果: 2.这个里面,这就是一个单元格吧, 这就是一个单元格, 这个单元格里面,包括一个图片框、一个TextLabel、一个DetailLabel、…

JAVA开发(通过网关gateway过滤器进行返回结果加密)

在对C的网站或者APP后端接口中&#xff0c;参数的传输往往需要加密传输。这时我们 可以通过springcloud的网关过滤器进行统一的控制。 网关过滤器的执行顺序&#xff1a; 请求进入网关会碰到三类过滤器&#xff1a;当前路由过滤器、DefaultFilter、GlobalFilter。 请求路由后…

ChatGPT团队中,3个清华学霸,1个北大学霸,共9位华人

众所周知&#xff0c;美国硅谷其实有着众多的华人&#xff0c;哪怕是芯片领域&#xff0c;华为也有着一席之地&#xff0c;比如AMD 的 CEO 苏姿丰、Nvidia 的 CEO 黄仁勋 都是华人。 还有更多的美国著名的科技企业中&#xff0c;都有着华人的身影&#xff0c;这些华人&#xff…

Vue组件化编程【Vue】

2.Vue 组件化编程 2.1 模块与组件、模块化与组件化 2.1.1 模块 理解&#xff1a;向外提供特定功能的js程序&#xff0c;一般就是一个js文件为什么&#xff1a;js文件很多很复杂作用&#xff1a;复用js、简化js的编写、提高js运行效率。 2.1.2 组件 理解&#xff1a;用来实…

Linux搭建Web服务器(二)——Web Server 与 HTTP

目录 0x01 Web Server 静态网络服务器&#xff08;static web server&#xff09; 动态网络服务器&#xff08;dynamic web server&#xff09; 0x02 HTTP协议 HTTP概述 HTTP工作原理 HTTP请求报文格式 HTTP响应报文格式 0x01 Web Server 一个Web Server就是一个服务器…

我们要被淘汰了?从科技变革看"ChatGPT"与"无代码开发"

现在只要一上网&#xff0c;就能看见GPT都在说“好厉害”、“太牛了”、“新技术要诞生了”、“我们人类要被淘汰了”之类的话题。但是这伟大的技术变革到底给我们带来了什么呢&#xff1f;答案好像又比较模糊。现在ChatGPT的代写、问答&#xff0c;以及开始做的搜索、办公是目…

sql查询语句-01

1.单表查询 ◆限制显示结果 使用limit限制显示的行数&#xff0c;分页函数limit m,n,从m1行开始显示n条记录 例&#xff1a;查询选修课程成绩排在前5的学生的学号和成绩。 select sno,score from SCorder by score desc limit 5;limit 1,3 零是第一条 ◆汇总数据(聚集函数&…

coinex06 // 前端数据 -> ringbuffer -> cpu

目录 0. 逻辑树 1 exchange-service 发送消息 1.1 exchange-service 添加依赖 1.2. yml配置文件 1.3. Source 1.4. 配置类 1.5. 发送消息到撮合引擎 service -> impl -> EntrustOrderServiceImpl 1.6. recket-server:8080 2. match-server 接收数据 2.1 数据转…

【SQL 必知必会】- 第十七课 创建和操纵表

目录 17.1 创建表 17.1.1 表创建基础 替换现有的表 17.1.2 使用NULL值 主键和NULL 值 理解NULL 17.1.3 指定默认值 使用DEFAULT 而不是NULL 值 17.2 更新表 小心使用ALTER TABLE 17.3 删除表 使用关系规则防止意外删除 17.4 重命名表 17.5 小结 这一课讲授创建、更改和删除…

【MyBatis Plus】002 -- 通用CRUD(插入、更新、删除、查询)

目录 3、通用CRUD 3.1 插入操作 3.1.1 方法定义 3.1.2 测试用例 3.1.3 测试 3.1.4 TableField 3.2 更新操作 3.2.1 根据id更新 3.2.2 根据条件更新 3.3 删除操作 3.3.1 根据id删除&#xff08;deleteById&#xff09; 3.3.2 根据Map删除数据&#xff08;deleteByMap&#xff09…

程序员必备技巧:Git 和 GitHub 中高效地将单个文件还原为特定提交

Git 和 GitHub 用于存储您的旧代码&#xff0c;允许您在出现问题时回滚并安全地恢复以前的准确代码。 与其他开发人员协作时&#xff0c;了解如何将单个文件恢复为特定提交也变得至关重要。这是因为&#xff0c;在处理某个功能时&#xff0c;您可能需要修改不相关的文件来测试…

Cursor编程初体验,搭载GPT-4大模型,你的AI助手,自然语言编程来了

背景 这两天体验了下最新生产力工具Cursor&#xff0c;基于最新的 GPT-4 大模型&#xff0c;目前免费&#xff0c;国内可访问&#xff0c;不限次数&#xff0c;跨平台&#xff0c;你确定不来体验一把&#xff1f;官方的 Slogan &#xff1a; Build Software. Fast. Write, edi…

【CSS】课程网站 Banner 制作 ② ( Banner 栏版心盒子测量 | Banner 版心盒子模型左侧导航栏代码示例 )

文章目录一、Banner 栏版心盒子测量1、测量版心元素尺寸2、课程表测量二、Banner 版心盒子模型左侧导航栏代码示例1、HTML 标签结构2、CSS 样式3、展示效果一、Banner 栏版心盒子测量 1、测量版心元素尺寸 拉四条辅助线 , 将版心包起来 , 可以测量 Banner 条版心的尺寸为 1200 …

Nginx网站服务详解(第二部分:Nginx服务的主配置文件 ——nginx.conf)

1. 全局配置的六个模块简介 全局块&#xff1a;全局配置&#xff0c;对全局生效&#xff1b;events块&#xff1a;配置影响 Nginx 服务器与用户的网络连接&#xff1b;http块&#xff1a;配置代理&#xff0c;缓存&#xff0c;日志定义等绝大多数功能和第三方模块的配置&…

SLBR通过自校准的定位和背景细化来去除可见的水印

一、简要介绍 本文简要介绍了论文“Visible Watermark Removal via Self-calibrated Localization and Background Refinement ”的相关工作。在图像上叠加可见的水印&#xff0c;为解决版权问题提供了一种强大的武器。现代的水印去除方法可以同时进行水印定位和背景恢复&#…

C++ 实现 Matlab 的 lp2lp 函数

文章目录1. matlab 的 lp2lp 函数的作用2. matlab 的 lp2lp 函数的使用方法3. C 实现3.1 complex.h 文件3.2 lp2lp.h 文件4. 测试结果4.1 测试文件4.2 测试3阶的情况4.3 测试9阶的情况1. matlab 的 lp2lp 函数的作用 去归一化 H(s) 的分母 2. matlab 的 lp2lp 函数的使用方法…

人脸识别经典网络-MTCNN(含Python源码实现)

人脸检测-mtcnn 本文参加新星计划人工智能赛道&#xff1a;https://bbs.csdn.net/topics/613989052 文章目录人脸检测-mtcnn1. 人脸检测1.1 人脸检测概述1.2 人脸检测的难点1.3 人脸检测的应用场景2. mtcnn2.1 mtcnn概述2.2 mtcnn的网络结构2.3 图像金字塔2.4 P-Net2.5 R-Net2…

为什么说过早优化是万恶之源?

Donald Knuth&#xff08;高德纳&#xff09;是一位计算机科学界的著名学者和计算机程序设计的先驱之一。他被誉为计算机科学的“圣经”《计算机程序设计艺术》的作者&#xff0c;提出了著名的“大O符号”来描述算法的时间复杂度和空间复杂度&#xff0c;开发了TeX系统用于排版…