C++ deque/queue/stack的底层原理

deque容器的存储结构

和 vector 容器采用连续的线性空间不同,deque 容器存储数据的空间是由一段一段等长的连续空间构成,各段空间之间并不一定是连续的,可以位于在内存的不同区域。

deque采用一块所谓的map数组(注意,不是STL的map容器)作为主控。这里所谓map是一小块连续空间(类似于vector),其中每个元素(此处称为一个节点,node)都是指针,指向另一段(较大的)连续线性空间,称为缓冲区。缓冲区才是deque的储存空间主体。SGI STL 允许我们指定缓冲区大小,默认值0表示将使用512 bytes 缓冲区。
在这里插入图片描述

通过建立 map 数组,deque 容器申请的这些分段的连续空间就能实现“整体连续”的效果。换句话说,当 deque 容器需要在头部或尾部增加存储空间时,它会申请一段新的连续空间,同时在 map 数组的开头或结尾添加指向该空间的指针,由此该空间就串接到了 deque 容器的头部或尾部。

如果 map 数组满了怎么办?很简单,再申请一块更大的连续空间供 map 数组使用,将原有数据(很多指针)拷贝到新的 map 数组中,然后释放旧的空间。

deque 容器的分段存储结构,提高了在序列两端添加或删除元素的效率,但也使该容器迭代器的底层实现变得更复杂。

deque容器迭代器的底层实现

由于 deque 容器底层将序列中的元素分别存储到了不同段的连续空间中,因此要想实现迭代器的功能,必须先解决如下 2 个问题:

  1. 迭代器在遍历 deque 容器时,必须能够确认各个连续空间在 map 数组中的位置;
  2. 迭代器在遍历某个具体的连续空间时,必须能够判断自己是否已经处于空间的边缘位置。如果是,则一旦前进或者后退,就需要跳跃到上一个或者下一个连续空间中。

为了实现遍历 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 数组中存储的指向当前连续空间的指针。

借助这 4 个指针,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;}

stack和queue的原理

由stack和queue源码可知,其实stack和queue是将deque容器进行再封装,其底层是一个deque容器。
对stack和queue操作,其实间接操作的是deque容器。

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

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

相关文章

LeetCode 0874. 模拟行走机器人:哈希表模拟

【LetMeFly】874.模拟行走机器人&#xff1a;哈希表模拟 力扣题目链接&#xff1a;https://leetcode.cn/problems/walking-robot-simulation/ 机器人在一个无限大小的 XY 网格平面上行走&#xff0c;从点 (0, 0) 处开始出发&#xff0c;面向北方。该机器人可以接收以下三种类…

rabbitmq模块启动报java.net.SocketException: socket closed的解决方法

问题 最近在接手一个项目时&#xff0c;使用的是spring-cloud微服务构架&#xff0c;mq消息消费模块是单独一个模块&#xff0c;但启动这个模块一直报如下错误&#xff1a; java.net.SocketException: socket closed 这个错误是这个模块注册不到nacos报的错&#xff0c;刚开…

day34-Animated Countdown(动画倒计时)

50 天学习 50 个项目 - HTMLCSS and JavaScript day34-Animated Countdown&#xff08;动画倒计时&#xff09; 效果 index.html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport&q…

态势标绘专题介绍

介绍 这个专栏是专门针对基于Cesium来实现态势标绘的专题专栏,专栏主要实现了30余种态势几何形状的标绘和编辑、文本的标绘和编辑、图片的标绘和编辑以及简单模型的标绘,同时支持标绘结果的导出以及导入。包括最终编写成的一个完整的Vue3.2+TS+Cesium1.107.2的标绘组件。专栏…

C#仿热血江湖

目录 1 GClass10 1.1 定义属性 1.2 int method 1.3 method 1.4 Byte method GClass0 定义属性private byte[] byte_0; private byte[] byte_1;

线性代数——线性方程组

文章目录 版权声明补充知识求和公式的性质常用希腊字符读音 线性方程组有解判定定理齐次线性方程组的基础解系非齐次线性方程组解的结构 版权声明 本文大部分内容皆来自李永乐老师考研教材和视频课。 补充知识 求和公式的性质 ∑ i 1 n k a i k ∑ i 1 n a i \sum_{i1}^n…

从用户的角度谈GPT时代技术突破的两大关键逻辑

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

EtherCAT转TCP/IP网关EtherCAT解决方案

你是否曾经为生产管理系统的数据互联互通问题烦恼过&#xff1f;曾经因为协议不同导致通讯问题而感到困惑&#xff1f;现在&#xff0c;我们迎来了突破性的进展&#xff01; 介绍捷米特JM-TCPIP-ECT&#xff0c;一款自主研发的Ethercat从站功能的通讯网关。它能够连接到Etherc…

macOS Ventura sublime无法加载Package Control

突然发现我的sublime text 的package control不起作用了&#xff0c;设置也变成灰色的了。 本以为是st出问题了&#xff0c;从官网重新下载&#xff0c;然后点菜单命令中的install package control&#xff0c;还是一样的不起作用。 启动st后&#xff0c;用ctrl~ 打开st的conso…

通过FPGA实现基于RS232串口的指令发送并控制显示器中目标位置

目录 1.算法理论概述 串口通信模块 指令解析模块 位置控制模块 显示器驱动模块 2.部分核心程序 3.算法运行软件版本 4.算法运行效果图预览 5.算法完整程序工程 1.算法理论概述 通过FPGA实现基于RS232串口的指令发送并控制显示器中目标位置是一种常见的应用场景&#x…

Prompt 技巧指南-让 ChatGPT 回答更准确

随着 ChatGPT 等大型语言模型 (LLM)的兴起&#xff0c;人们慢慢发现&#xff0c;怎么样向 LLM 提问、以什么技巧提问&#xff0c;是获得更加准确的回答的关键&#xff0c;也由此产生了提示工程这个全新的领域。 提示工程(prompt engineering)是一门相对较新的领域&#xff0c;用…

Golang中函数和方法的区别

在Golang中&#xff0c;函数和方法之间有一些区别。 函数是一段独立的代码块&#xff0c;可以接收输入参数并返回结果。它可以在任何地方被调用&#xff0c;而不依赖于任何特定的结构或类型。 方法是与特定类型关联的函数。它是类型的一部分&#xff0c;可以通过该类型的实例…

java学习003

Java数组 Java 语言中提供的数组是用来存储固定大小的同类型元素&#xff0c;这一点和PHP语言的可变数组长度不同。 声明变量数组 首先必须声明数组变量&#xff0c;才能在程序中使用数组。下面是声明数组变量的语法&#xff1a; dataType[] arrayRefVar; // 首选的方法 或 …

C++(13):拷贝控制

一个类通过定义五种特殊的成员函数来控制这些操作&#xff0c;包括&#xff1a;拷贝构造函数(copy constructor)、拷贝赋值运算符&#xff08;copy-assignment operator)、移动构造函数&#xff08;moveconstructor)、移动赋值运算符&#xff08;move-assignment operator)和析…

云计算——云计算与虚拟化的关系

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​ 目录 前言 一.虚拟化 1.什么是虚拟化 2.虚拟化技术作用 二.云计算与虚拟化的关系 三.虚…

华为eNSP:ospf的配置

一、拓扑图 二、路由器的配置 1、路由器依据规划配置接口IP AR1: <Huawei>system-view [Huawei]int g0/0/0 [Huawei-GigabitEthernet0/0/0]ip add 10.10.10.1 24 [Huawei-GigabitEthernet0/0/0]qu AR2: <Huawei>system-view [Huawei]int g0/0/0 [Huawei-Gi…

RabbitMQ消息可靠性问题及解决

说明&#xff1a;在RabbitMQ消息传递过程中&#xff0c;有以下问题&#xff1a; 消息没发到交换机 消息没发到队列 MQ宕机&#xff0c;消息在队列中丢失 消息者接收到消息后&#xff0c;未能正常消费&#xff08;程序报错&#xff09;&#xff0c;此时消息已在队列中移除 …

STM32(HAL库)驱动AD8232心率传感器

目录 1、简介 2、CubeMX初始化配置 2.1 基础配置 2.1.1 SYS配置 2.1.2 RCC配置 2.2 ADC外设配置 2.3 串口外设配置 2.4 GPIO配置 2.5 项目生成 3、KEIL端程序整合 3.1 串口重映射 3.2 ADC数据采集 3.3 主函数代码整合 4 硬件连接 5 效果展示 1、简介 本文通过STM32…

springboot整合redis

先在配置文件中加好配置 然后引入相关依赖 然后 写好如下配置bean即可整合redis 1.加配&#xff08;yml格式&#xff09; redis: client-type: jedis host: 101.227.52.230 password: 892660rG port: 6379 jedis: pool: # 连接池最大连接数&#xff08;使用负值表示没有限制&a…

Linux文件处理命令

目录&#xff1a; linux系统与shell环境准备linux常用命令之文件处理Linux系统登录与文件操作 1.linux系统与shell环境准备 Linux 系统简介&#xff1a; Linux 内核最初只是由芬兰人林纳斯托瓦兹&#xff08;Linus Torvalds&#xff09;在赫尔辛基大学上学时出于个人爱好而…