STL之deque容器

deque容器:
应该是比vector和list要复杂得多的容器了,它与vector的区别主要有两点:
1)它类似于vector容器的连续,但是又不是完全连续,它利用一个中控单元实现假象的连续,中控单元中的每一个元素都管理者一个缓冲区(其实就是一个固定大小的数组);
2)但是在vector中当空间不足时,是需要重新分配一个新的空间,然后将现有的元素移动过去,然后销毁原来的空间,这个在deque中是不存在的;

结构描述:
deque使用了中控组织控制每个独立单元的形式,当deque初始为空的时候,它会先维护一个缓冲区(这个缓冲区一定是处于控制组织的最中心位置的,这样保证了向前
插入和向后插入的效率和空间一样大),假如说,现在规定一个deque<int,alloc,8>  dq(20,6),要求该容器初始情况为:元素类型为int型,每个缓冲区为容纳
8个int型变量的大小,该容器初始有20个元素,每个元素的值都是6;现在就会占用3个缓冲区(因为20个元素需要3个8才能容下),这时候STL会根据实际情况而定。
默认的情况是中控组织map中最少容量为8(也即可以指向8个缓冲区),很明显现在需要的是3个,比默认值小,所以会自动的将map数组的大小定为8。如果
比默认值打的话,就会将map数组的大小设置为(需要的节点数加2,前边后边各一个空余)。

插入元素:
包括前向插入和后向插入,在插入元素的过程中,如果map中没有空间了,也会根据实际情况来判断
①:如果在前向插入,map中的第一个节点所指向的缓冲区中剩下两个及以上的空间,则会直接插入该位置;如果map中的第一个节点所指向的缓冲区中只剩下一个空间,
则会使用A_before函数进行判断;
②:后向插入和前向一样的道理;
现在介绍一下A_before函数的原理,如果是前向插入,就计算出当前总共使用的map节点数A,如果A满足:2*A < mapsize,则将现在使用的节点向后移动即可,
意思是只移动map数组中的节点就好了;如果不满足,则重新配置一个空间用于存放map数组(也即使map数组变大),空间的大小等于max(A,mapsize)+2;
然后拷贝map数组到新的位置即可,并将原来的map数组销毁;


迭代器:
这里注意,每个迭代器存放了四个内容,即:迭代器“当前所指的缓冲区的first起始位置”,“和当前所指的缓冲区的last结束位置”,
“迭代器在该缓冲区中所指的具体位置”‘以及“迭代器所指的缓冲区在map中的位置”;
因为结构的复杂性,又必须满足STL中该有的迭代器操作(包括解引用和->,++,--),所以这种容器的迭代器是比较复杂的,在迭代器前进的过程中,
如果迭代器已经到达该缓冲区的最后last位置,则应该跳到下一个map节点位置的first位置,如果是后退的话也是一样的道理;

元素操作:
pop_back函数如果在执行后盖缓冲区没有数据,则销毁该缓冲区,并且将容器的end指针设为前一个缓冲区的last位置;
同样的pop_front函数一样的道理:在执行插入元素的时候,会先判断在插入位置之前的元素个数numBefore和插入点之后的元素个数numAfter,
如果numBefore小于numAfter,则将前边的元素向前移动一格,否则将后边的元素向后移动一格;clear操作同样会将容器设置为只有一个缓冲区的原始状态;
erase函数也是可能会伴随着缓冲区的释放进行的;
### C++ STL `deque` 使用方法及特性 #### 一、基本概念 `std::deque<T>` 是标准模板库(STL)提供的一种双端队列容器,支持快速的随机访问以及高效的两端插入和删除操作。这种灵活性使得它适用于多种场景下的数据存储需求。 #### 二、主要功能与使用方式 ##### (一)创建与初始化 可以像其他STL容器一样通过默认构造函数来实例化一个空的`deque`对象;也可以指定初始大小或填充特定数量相同类型的元素进行初始化[^4]。 ```cpp // 创建一个整型dequeue,默认无参数则为空 std::deque<int> myDeque; // 初始化含有五个零值整数的dequeue std::deque<int> anotherDeque(5, 0); ``` ##### (二)元素存取 提供了`front()`获取头部元素引用,`back()`获得尾部元素引用的方法。对于任意位置上的元素,则可以直接利用下标运算符[]来进行读写操作。 ```cpp myDeque.push_back(1); // 向后追加新项 anotherDeque.front(); // 访问第一个元素 anotherDeque.back(); // 获取最后一个元素 anotherDeque[2]; // 索引第三个元素 (假设存在) ``` ##### (三)增删改查 - 插入:除了常规的`push_back()/push_front()`外,在C++20版本之后还增加了更灵活的方式——`emplace_*`系列成员函数允许直接在目标地点构建对象而无需先创建临时变量再转移所有权[^3]; - 删除:不仅能够分别针对前后两端调用`pop_back()/pop_front()`移除单个节点,还可以借助于新增API如`erase_if()`批量清除符合条件的所有条目[^1]; - 修改:可通过迭代器配合算法库中的工具完成复杂变换任务,比如下面的例子展示了如何将每一个数值翻倍处理[^2]: ```cpp std::for_each(myDeque.begin(), myDeque.end(), [](int& elem){ elem *= 2; }); ``` ##### (四)查询统计 为了方便开发者判断当前状态,内置了一些辅助性的属性接口,例如检测是否为空(`empty()`)或是计算总长度(`size()`)等. #### 三、内部结构特点分析 不同于连续内存布局的传统数组向量(vector),`deque`采用了分段式的管理策略,即将整个序列分割成若干固定大小的小块(block),每一块之间保持一定间隔以便后续扩展时能更容易找到合适的位置安插新的片段而不至于频繁触发大规模重定位动作。这样的设计既保留了一定程度上类似于链表那样动态调整的优势,又兼顾到了接近线性寻址所带来的性能提升效果. #### 四、适用范围对比总结 当面对需要频繁执行双向末端更新且偶尔涉及中间部分修改的应用场合时,选用`deque`往往可以获得更好的综合表现。然而值得注意的是由于其特殊的组织形式可能会造成缓存命中率下降进而影响到某些情况下顺序扫描效率,所以在实际项目选型过程中应当权衡利弊做出合理抉择.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值