首页 > 编程语言 >《STL 源码剖析》 deque 实现原理

《STL 源码剖析》 deque 实现原理

时间:2022-11-18 15:02:08浏览次数:40  
标签:node deque 迭代 map STL 元素 源码 缓冲区

目录

deque概述

deque是双向开口的连续线性空间,而vector是单向开口的连续线性空间。

deque没有容量的概念,它是动态地以分段连续空间组合而成,随时可以增加一点新的空间并链接起来。 不会像 vector 因 “旧空间不足,而重新配置更大空间,然后复制旧元素,再释放旧空间”。

因此deque 没有reserve功能。

deque提供 Ramdon Access Iterator,但复杂度和vector不能相提并论,这也影响到各类算法方面。因此,除非必要,应尽量使用vector。

例如,对deque进行排序,为了最高效率,可以将deque复制到vector,采用stl sort排序完,再复制回deque。

deque 是表象的连续线性空间。实际上deque 由一段一段的定量连续空间构成。deque最大任务,对多段连续空间的处理,维护整体连续的假象,并提供随机存取接口。而它的代价在于复杂的迭代器结构。

deque中控器

deque 采用一块所谓的map(非stl map)作为主控,map是一小块连续空间。每个元素(节点)都是指针,其指向一段较大的连续性空间,被称为缓冲区。缓冲区才是 deque的存储主体。

deque 迭代器和数据结构

deque 为了维持整体连续的假象,因此总体的任务就落在迭代器的 opterator ++ 和 opteartor – 身上。

其迭代器主要由四个元素构成:

  1. cur:当前指向的元素地址
  2. firest:元素所属缓冲区的头
  3. last:元素所属缓冲区的尾
  4. node:指向缓冲区所属的map的位置

在缓冲区内,迭代器遍历方式和普通迭代器相同,当进行到缓冲区边缘时,需要调用 set_node() 跳到下一个缓冲区。

void set_node(map_pointer new_node)
{
   node = new_node;
   first = *new_node;
   last = first + difference_typ(buffer_size());
}

deque数据结构主要内容

  1. map: 指向map
  2. map_size: map内有多少指针
  3. start:第一个节点的第一个元素
  4. finish:最后一个节点的最后一个元素

deque 操作原理

deque随机存储

deque 实现其随机存储的方式,总体思路上,根据总长度和每段缓冲区固定长度,来决定,要查找map中第几个node,再确定是缓冲区中,第几块内存。不过具体详细实现还是需要看源代码

例子:

  1. 假设一个缓冲区可以放入8个元素;
  2. 当deque查找[20] 元素时,20/8 + 1 = 3 (第三个node,为何+1? 是因为 map结构中 要预留头尾两个节点,用于扩充,实际元素在map 第二个node开始存储);
  3. 缓冲区第几个: 20%8 = 4(缓冲区第四个元素)

deque 插入

deque 头尾插入,push_front,push_back,在通常情况下,缓冲区剩余空间足够时,和vector类似,当不足时(只剩一个时),将会插入元素,并申请一块新的缓冲区。

deque 指定位置插入insert(iterator postion,const T& x),当postion 等于收尾时,则直接调用 push_front,push_back;当postion在中间位置时,会调用内部私有成员函数insert_aux进行实现。

insert_aux 原理,查看插入的postion前后元素数量多少,对少的的部分进行,移动式拷贝;

如果,前半部分元素少,则对前半部分的元素,进行整体前移拷贝;

如果,后半部分元素少,则对后半部分元素,进行整体后移拷贝。

由此可见,insert_aux 效率不高,由于虚构的连续空间,效率上,比vector更差。

deque 删除

deque 头尾删除,pop_front,pop_back,与插入相反,当pop的元素是缓冲区第一个或最后一个时,将删除元素后,并清除该缓冲区。

deque 指定迭代器位置删除erase(iterator pos) 原理和insert_aux类似,主要移动式拷贝的方向是缩收的。

如果,前半部分元素少,则对前半部分的元素,进行整体后移拷贝;

如果,后半部分元素少,则对后半部分元素,进行整体前移拷贝。

deque 指定范围删除erase(iterator first, iterator last) 原理上和 删除单个类似。不同在于删除的元素多少问题,以及缓冲区的释放

deque 和stack、queue的关系

stack 和 queue的实现是基于deque,只是对其操作做了限制;
由于stack和queue 对deque的操作进行进行了限制,因此在其操作效率上都比较高。
(我认为 stack和queue实际上是一个算法容器概念的逻辑,只要能符合其先进先出先进后出的逻辑。也可以用list实现)

标签:node,deque,迭代,map,STL,元素,源码,缓冲区
From: https://www.cnblogs.com/q1076452761/p/16903229.html

相关文章

  • 如何修改npm包源码后,重新npm包的时候能是修改后的版本
    肯定是clone一份到gitHub啦保存一份修改后的npm包到自己的私有库npm安装git仓库的方式npminstall<gitremoteurl>例如npminstallgithub:mygithubuser/mypro......
  • html字符串转pdf源码
        ///<summary>     ///将Html文字输出到PDF     ///</summary>     ///<paramname="htmlText......
  • Vue3源码解读之patch
    例子代码本篇将要讲解domdiff,那么咱们结合下面的例子来进行讲解,这个例子是在上一篇文章的基础上,加了一个数据变更,也就是list的值发生了改变。html中增加了一个按钮change......
  • 如何正确学习vue3.0源码
    为什么要学源码技术是第一生产力学习API的设计目的、思路、取舍学习优秀的代码风格学习组织代码的方式学习实现方法的技巧学习ES67新API、TS高级用法不给自......
  • 上帝视角看Vue源码整体架构+相关源码问答
    前言这段时间利用课余时间夹杂了很多很多事把Vue2源码学习了一遍,但很多都是跟着视频大概过了一遍,也都画了自己的思维导图。但还是对详情的感念模糊不清,故这段时间对源码......
  • React源码中的dom-diff
    这一章就来讲讲React在协调阶段的beginWork里面主要做的事情--domdiff。本文主要讲的是React17.0.2版本的diff,在此我也画了一个简单的流程图:reconcileChildrendomd......
  • Ubutu下 vim 的.vimrc配置以及YourCompletedMe无法stl代码提示的解决办法
    我的vim效果预览主题颜色是desertEx有目录树,和函数显示器,以及代码提示,根据文件类型自动生成文件头下面是我的.vimrc配置!请全屏观看点击查看代码setnocompatible......
  • c++STL
    C++11常用特性的使用经验总结std::unordered_map与std::map用法基本差不多,std::map使用的数据结构为二叉树,而std::unordered_map内部是哈希表的实现方式;//std::uno......
  • 基于微信小程序的疫情核酸预约系统设计与实现-计算机毕业设计源码+LW文档
    小程序开发说明开发语言:Java框架:ssmJDK版本:JDK1.8服务器:tomcat7数据库:mysql5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包:Maven3.3.9......
  • vue 项目源码映射失败问题解决
    目录vue项目源码映射失败问题解决前言解决方案效果参考vue项目源码映射失败问题解决前言不知何时起,项目控制台调试进入源代码变成编译后的文件了,调试起来十分不便,强迫......