C++ deque与vector对比的优缺点
作者:川入 发布时间:2023-08-28 13:19:16
deque容器
deque的相关文档
deque与vector十分的相识。vector是单向开口的连续线性空间(单向扩容),deque则是一种双向开口的连续线性空间(双向扩容)。双向开口:可以在头尾两端分别做元素的插入和删除操作。区别就在此,vector当然也可以在头尾两端进行操作,但是其头部操作的效率奇差,无法被接受,如:stack与queue的容量适配器就在二者其中,选择deque(当然使用vector也可)。
vector与deque的差异:
deque允许于常数时间内对头端进行元素的插入或移除操作。
deque没有所谓的容量观念,因为它是动态地以分段连续空间组合而成,随时可以增加一段新的空间并连接起来。
与stack相比deque的优缺点:
优势:
头尾插入删除很方便
劣势:
operator[]计算稍显复杂,大量使用,性能下降(下标需要经过计算)。
中间插入删除效率不高(下标需要经过计算,并且需要挪动元素)。
底层角度迭代器会很复杂。
结论:
头尾的插入删除deque非常适合,相比vector而言,很适合去做stack和queue的默认适配容器。
中间插入删除少用deque,可以用:list(因为无需挪动元素)。
随机访问多用vector(因为下标是确定的)。
deque的迭代器
需要注意,deque是连续的空间,但是这只是其逻辑上的,物理上并不是。所以在迭代器上维持其“整体连续”假象的工作,就落在迭代器中的operator++与operator--上了。
首先,连续重要的就是能够指出分段空间在哪里,其次,它必须能够判断自己是否已经处于其所在的存储边缘,如果是,一旦前行或后退时就必须跳跃到下一个或上一个存储空间。
// __deque_iterator的源码
template <class T, class Ref, class Ptr, size_t BufSiz>
struct __deque_iterator
{
typedef __deque_iterator<T, T&, T*> iterator;
typedef __deque_iterator<T, const T&, const T*> const_iterator;
static size_t buffer_size() {return __deque_buf_size(0, sizeof(T)); }//buffer_size()用于确定缓冲区的大小
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef Ptr pointer;
typedef Ref reference;
typedef size_t size_type; // size_t 是unsigned 类型,通常用来指明数组长度
typedef ptrdiff_t difference_type; // ptrdiff_t 是 signed 整型,通常用来保存两个指针减法操作的结果
typedef T** map_pointer;
typedef __deque_iterator self;
// 保持与容器的联结,是对某一个缓冲区而言的
T* cur; // 此迭代器所指之缓冲区中的现行元素
T* first; // 此迭代器所指之缓冲区的头
T* last; // 此迭代器所指之缓冲区的尾(含备用空间)
map_pointer node; // 指向管控中心
...
}
//deque_buf_size()全局函数
inline size_t deque_buf_size(size_t n, size_t sz){
return n != 0 ? n : (sz < 512 ? size_t(512 / sz) : size_t(1));
}
//定义:
//1. 如果n不为0,传回n,表示buffer size由使用者自定。
//2. 如果n为0,表示buffer size使用默认值,那么:
// 如果sz不小于 512,返回1。
// 如果sz(元素大小,sizeof(value_type))小于512,传回512/sz。
void set_node(map_pointer new_node) {
node = new_node;
first = *new_node;
last = first + difference_type(buffer_size());
}
reference operator*() const { return *cur; }
pointer operator->() const { return &(operator*()); }
difference_type operator-(const self& x) const {
return difference_type(buffer_size()) * (node - x.node - 1) + (cur - first) + (x.last - x.cur);
}
self& operator++() {
++cur; //切换至下个元素
if (cur == last) { //如果已达所在缓冲区的尾端,就切换至下一节点(亦即缓冲区)的第一个元素
set_node(node + 1);
cur = first;
}
return *this;
}
self operator++(int) { //后置式,标准写法
self tmp = *this;
++*this;
return tmp;
}
self& operator--() {
if (cur == first) {//如果已达所在缓冲区的头端, 就切换至前一节点(亦即缓冲区)的最后一个元素
set_node(node - 1);
cur = last;
}
--cur; //切换至前一个元素
return *this;
}
self operator--(int) { //后置式,标准写法
self tmp = *this;
--*this;
return tmp;
}
// 以下实现随机存取。迭代器可以直接跳跃n个距离
self& operator+=(difference_type n) {
difference_type offset = n + (cur - first);
if (offset >= 0 && offset < difference_type(buffer_size()))
//标的位置在同一缓冲区内
cur += n;
else {
//标的位置不在同一缓冲区内
difference_type node_offset =
offset > 0 ? offset / difference_type(buffer_size()) : -difference_type((-offset - 1) / buffer_size()) - 1;
// 切换至正确的节点(亦即缓冲区)
set_node(node + node_offset);
// 切换至正确的元素
cur = first + (offset - node_offset * difference_type(buffer_size()));
}
return *this;
}
self operator+(difference_type n) const {
self tmp = *this;
return tmp += n; //调用operator+=
}
//利用operator+=完成operator-=
self& operator-=(difference_type n) { return *this += -n; }
self operator-(difference_type n) const {
self tmp = *this;
return tmp -= n; //调用operator-=
}
//实现随机存取,迭代器可以直接跳跃n个距离
reference operator[] (difference_type n) const { return * (*this + n);)}
bool operator==(const self& x) const { return cur == x.cur; }
bool operator!=(const self& x) const { return !(*this == x); }
bool operator<(const self& x) const {
return (node == x.node) ? (cur < x.cur) : (node < x.node);
}
deque的成员函数
函数成员 | 函数功能 |
---|---|
begin() | 返回指向容器中第一个元素的迭代器。 |
end() | 返回指向容器最后一个元素所在位置后一个位置的迭代器,通常和 begin() 结合使用。 |
rbegin() | 返回指向最后一个元素的迭代器。 |
rend() | 返回指向第一个元素所在位置前一个位置的迭代器。 |
cbegin() | 和 begin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。 |
cend() | 和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。 |
crbegin() | 和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。 |
crend() | 和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。 |
size() | 返回实际元素个数。 |
max_size() | 返回容器所能容纳元素个数的最大值。这通常是一个很大的值,一般是 232-1,我们很少会用到这个函数。 |
resize() | 改变实际元素的个数。 |
empty() | 判断容器中是否有元素,若无元素,则返回 true;反之,返回 false。 |
shrink _to_fit() | 将内存减少到等于当前元素实际所使用的大小。 |
at() | 使用经过边界检查的索引访问元素。 |
front() | 返回第一个元素的引用。 |
back() | 返回最后一个元素的引用。 |
assign() | 用新元素替换原有内容。 |
push_back() | 在序列的尾部添加一个元素。 |
push_front() | 在序列的头部添加一个元素。 |
pop_back() | 移除容器尾部的元素。 |
pop_front() | 移除容器头部的元素。 |
insert() | 在指定的位置插入一个或多个元素。 |
erase() | 移除一个元素或一段元素。 |
clear() | 移出所有的元素,容器大小变为 0。 |
swap() | 交换两个容器的所有元素。 |
emplace() | 在指定的位置直接生成一个元素。 |
emplace_front() | 在容器头部生成一个元素。和 push_front() 的区别是,该函数直接在容器头部构造元素,省去了复制移动元素的过程。 |
emplace_back() | 在容器尾部生成一个元素。和 push_back() 的区别是,该函数直接在容器尾部构造元素,省去了复制移动元素的过程。 |
来源:https://blog.csdn.net/weixin_64609308/article/details/127639609


猜你喜欢
- 一、导论java技术体系中所提到的内存自动化管理归根结底就是内存的分配与回收两个问题,之前已经和大家谈过java回收的相关知识,今天来和大家
- 用户退出应用前给出一个提示是很有必要的,因为可能是用户并不真的想退出,而只是一不小心按下了返回键,大部分应用的做法是在应用退出去前给出一个D
- 最近想业余做一款android游戏,发现我国一款古老好玩的智力游戏-九格智能拼图挺好玩的,相信大多80后小时玩过,因此有了开发的想法。一、九
- 异常捕获机制 C#1.示意图2.异常捕获机制,代码:3.异常捕获机制,结果:4.求几周,剩余几天?代码:5.结果:6.求几月几周零几天 设一
- 这个是SpringBoot的Maven插件,主要用来打包的,通常打包成jar或者war文件。其中goal标签可以有5个值:repackage
- FileOutPutStream:子类,写出数据的通道步骤:1.获取目标文件2.创建通道(如果原来没有目标文件,则会自动创建一个)3.写入数
- 使用官方的刷新控件SwipeRefreshLayout来实现下拉刷新,当RecyclerView滑到底部实现下拉加载(进度条效果用Recyc
- 本文实例讲述了C#简单输出日历的方法。分享给大家供大家参考。具体如下:用C#输出日历,此功能可用于Ajax方式列出计划日程相关的内容,由于是
- 随着互联网的飞跃式发展,移动支付已越来越受欢迎并且已成为常态,很多三方支付公司推出了很多支付方式如快捷支付、认证支付、扫码支付等等。快捷支付
- 最近需要对接支付宝的支付接口,官方文档写得内容有点分散,整理了一下发布出来,用作记录,同时也希望对不了解情况的人有所帮助,这里以电脑端的网页
- Java中的static关键字可以用于修饰变量、方法、代码块和类,还可以与import关键字联合使用,使用的方式不同赋予了static关键字
- 本文实例讲述了C#通过属性名字符串获取、设置对象属性值操作.分享给大家供大家参考,具体如下:#通过反射获取对象属性值并设置属性值0、定义一个
- 本文实例分析了java中成员变量与局部变量区别。分享给大家供大家参考。具体分析如下:成员变量:在这个类里定义的私有变量,属于这个类。创建以及
- 前言最近在参与一个银行项目-某银行安防系统-反洗钱需求的开发,银行项目的离不开身份证号码,身份证号码作为我国公民的唯一标识,有这非同寻常的意
- Filter过滤器中访问getSession()要进行转化public void doFilter(ServletRequest reque
- 前言OkHttp是目前非常火的网络库,支持HTTP/2,允许所有同一个主机地址的请求共享同一个socket连接,连接池减少请求延时,透明的G
- 前言在Android开发中我们可能会有延时执行某个操作的需求,例如我们启动应用的时候,一开始呈现的是一个引导页面,过了两三秒后,会自动跳转到
- Metro UI For JavaFX!这是一个Windows设计风格的UI库,使用非常简单,只要一行代码就可以实现整体UI风格的替换!ne
- 实现跨服务的远程调用(RestTemplate)业务场景:在返回订单信息数据中显示用户信息实现思路:基于RestTemplate发起的htt
- 引言最近在写一个 Mybatis 代码自动生成插件,用的是Mybatis来扩展,其中有一个需求就是 生成javaMapper文件和 xmlM