【C++ STL】-- deque与vector相比的优势与劣势
创始人
2024-04-03 07:00:17

目录

deque容器

与stack相比deque的优缺点:

deque的迭代器

deque的成员函数


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 
struct __deque_iterator
{typedef __deque_iterator             iterator;typedef __deque_iterator 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() 的区别是,该函数直接在容器尾部构造元素,省去了复制移动元素的过程。

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...