C++ deque与vector对比的优缺点

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

到此这篇关于C++ deque与vector对比的优缺点的文章就介绍到这了,更多相关C++ deque与vector内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++ 基础函数的介绍及使用(Vector+deque)

    目录 一.Vector的基础函数 1. 构造函数 2. 增加元素 3. 删除元素 4. 遍历vector 5. 判断函数 6. 大小函数 7. 其他函数 二.deque的介绍及使用 三.deque 和 vector的差别 1.构造函数 2.常用成员函数 3.特点 一.Vector的基础函数 之前有学习过 vector.set.map等容器,都是需要什么搜什么,没有详细的了解其中的内容.最近在看 STL 的相关内容,就顺手整理一些基础性内容,避免以后遇到的时候再临时抱佛脚. 1. 构造函数 vec

  • C++顺序容器(vector、deque、list)的使用详解

    目录 一:STL(Standard Template Library),即标准模板库,是一个高效的C++程序库 二:STL组件 三:容器 四:类型成员 五:迭代器 六:顺序容器 七:顺序容器--向量(vector) 八:顺序容器--双端队列--deque 九:顺序容器 --列表--list 一:STL(Standard Template Library),即标准模板库,是一个高效的C++程序库 1.从实现层次看,整个STL是以一种类型参数化(type parameterized)的方式实现的,基

  • C++ STL入门教程(3) deque双向队列使用方法

    一.简介 deque(Double Ended Queues,双向队列)和向量很相似,但是它允许在容器头部快速插入和删除(就像在尾部一样). 二.完整程序代码 /*请务必运行以下程序后对照阅读*/ #include <deque> #include <iostream> #include <algorithm> #include <stdexcept> using namespace std; void print(int num) { cout <&

  • 深入分析C++中deque的使用

    首先,当考虑到内存分配和执行性能的时候,使用std::deque要比std::vector好. Deque总览 deque和vector一样都是标准模板库中的内容,deque是双端队列,在接口上和vector非常相似,在许多操作的地方可以直接替换.假如读者已经能够有效地使用vector容器,下面提供deque的成员函数和操作,进行对比参考. 函数 描述 c.assign(beg,end)c.assign(n,elem)  将[beg; end)区间中的数据赋值给c.将n个elem的拷贝赋值给c.

  • C++ deque容器的具体使用

    deque 是 double-ended queue 的缩写,又称双端队列容器. 和 vector 不同的是,deque 还擅长在序列头部添加或删除元素,所耗费的时间复杂度也为常数阶O(1).并且更重要的一点是,deque 容器中存储元素并不能保证所有元素都存储到连续的内存空间中. 当需要向序列两端频繁的添加或删除元素时,应首选 deque 容器. deque容器的构造函数 //deque和vector的区别 //deque对于头部的插入和删除效率低,数据量越大,效率越低 //deque相对而言

  • C++ deque容器的用法详解

    deque(双端队列)是由一段一段的定量连续空间构成,可以向两端发展,因此不论在尾部或头部安插元素都十分迅速. 在中间部分安插元素则比较费时,因为必须移动其它元素. deque容器的构造函数 //deque和vector的区别 //deque对于头部的插入和删除效率低,数据量越大,效率越低 //deque相对而言,对于头部的插入和删除比vector快 //deque访问元素时的速度比vector要慢,和两者的内部实现有关 #include <iostream> #include <deq

  • C++之vector容器的的声明初始化和增删改查

    C++vector容器 C++中有两种类型的容器:顺序容器和关联容器. 顺序容器主要有vector.list.deque等.其中vector表示一段连续的内存,基于数组实现,list表示非连续的内存,基于链表实现,deque与vector类似,但是对首元素提供插入和删除的双向支持. 关联容器主要有map和set.map是key-value形式,set是单值.map和set只能存放唯一的key,multimap和multiset可以存放多个相同的key. 容器类自动申请和释放内存,因此无需new和

  • C++ STL容器适配器使用指南

    目录 适配器 stack容器适配器 ️stack的介绍 ️stack的使用 ️stack的模拟实现 queue ️queue的介绍 ️queue的使用 ️queue的模拟实现 deque容器 priority-queue ️priority-queue的使用 ️priority-queue的模拟实现 适配器 适配器是一种设计模式(设计模式是一套被反复使用的.多数人知晓的.经过分类编目的.代码设计经验的总结),该种模式是将一个类的接口转换成客户希望的另外一个接口.例如: 容器适配器让一种已存在的容

  • C++中list的使用与模拟实现

    目录 一.list的介绍以及使用 1.1 list的介绍 1.2 list的使用 1.2.1 list的构造 1.2.2 list iterator的使用 1.2.3 list capacity 1.2.4 list element access 1.2.5 list modifiers 1.2.6 list的迭代器失效 二.list的模拟实现 2.1 模拟实现list 总结 一.list的介绍以及使用 1.1 list的介绍 1.list是可以在常数范围内在任意位置进行插入和删除的序列式容器,

  • STL常用容器详细解析

    STL是C/C++开发中一个非常重要的模板,而其中定义的各种容器也是非常方便我们大家使用.下面,我们就浅谈某些常用的容器.这里我们不涉及容器的基本操作之类,只是要讨论一下各个容器其各自的特点.STL中的常用容器包括:顺序性容器(vector.deque.list).关联容器(map.set).容器适配器(queue.stac). 1.顺序性容器 (1)vectorvector是一种动态数组,在内存中具有连续的存储空间,支持快速随机访问.由于具有连续的存储空间,所以在插入和删除操作方面,效率比较慢

  • 深入解析C++ STL中的常用容器

    STL是C/C++开发中一个非常重要的模板,而其中定义的各种容器也是非常方便我们大家使用.下面,我们就浅谈某些常用的容器.这里我们不涉及容器的基本操作之类,只是要讨论一下各个容器其各自的特点.STL中的常用容器包括:顺序性容器(vector.deque.list).关联容器(map.set).容器适配器(queue.stac). 1.顺序性容器 (1)vectorvector是一种动态数组,在内存中具有连续的存储空间,支持快速随机访问.由于具有连续的存储空间,所以在插入和删除操作方面,效率比较慢

随机推荐