基于C++11的Deque容器分析

Deque的基本概念

  1. 容器deque和vector非常相似,内部也实现为一个dynamic array来管理元素,提供随机访问,并有着和vector几乎一样的接口,不同的是deque的dynamic array头尾都开放,因此在首尾都能进行快速安插和删除

  1. deque通常实现为一组独立区块,第一区块朝某方向扩展,最末区块朝另一方向扩展

  1. 使用deque之前,必须包含头文件<deque>

#include<deque>

  1. deque类型定义于命名空间std内的一个class template

namespace std{

template<typename T,typename Allocator=allocator<T>>

class deque;

}

注:和vector相同,这里第一个template参数表示元素的类型,第二个template实参可有可无,用来指定内存模型,默认为allocator

Deque的能力

与vector相比,功能相比的差别如下

  1. deque在首位删除和添加元素都可以在常量时间完成

  1. 访问元素时deque内部会有一个间接的过程,所以元素的访问和迭代器的动作都会稍慢一些

  1. 迭代器需要在不同的区块内跳转,因此必须是个smart pointer ,而不是一个寻常pointer

  1. deque不支持对容量和内存重新分配时机的控制。不过,deque的内存分配优于vector,因为其内部结构显示,deque不必在内存重新分配时,复制所有的元素

  1. deque会释放不使用的内存区块

以下功能和vector基本相同

  1. 在中段安插,移除元素速度相对较慢(保持相对位置的原因)

  1. 迭代器属于random-access iterator

总之在以下情况下最好采用deque

  1. 你需要在两端安插或移除元素时(这是deque的拿手好戏)

  1. 无需指向(refer to)容器内的元素

  1. 要求”不再使用的元素必须释放“(不过C++11standard对此无任何保证)

Deque的操作函数

deque<T>c f  //default构造函数,产生一个空容器
deque<T>c(c2)  //copy构造函数,将c作为c2的一份拷贝
deque<T>c=c2    //copy构造函数,将c作为c2的一份拷贝
deque<T>c(rv)   //move构造函数,取rv的内容作为c的内容
deque<T>c=rv    //move构造函数,取rv的内容作为c的内容
deque<T>c(n)    //利用元素的default构造函数,初始化一个大小n的deque
deque<T>c(n,elem)  // 建立一个大小为n,每个元素都是elem的deque
deque<T>c(begin,end)//建立一个以[begin,end)内的内容为初值的deque
deque<T>c(initlist)// 建立一个以initlist内的内容为初值的deque
deque<T>c=initlist//  建立一个以initlist内的内容为初值的deque
c.~deque()// 销毁所有的元素,释放内存

Deque的各项操作只有以下两点和vector不同

  1. deque不提供容量操作

  1. deque直接提供函数完成头部元素的安插和删除(push_front(),pop_front())

其他操作这里不重复

对于shrink_to_fit()操作函数,你可能认为没有什么意义,因为deque本就会释放用不到的区块内存。然而,deque内部用来存放”指向独立区块“的所有pointer的空间,通常不会被缩小,如果用了这个函数就真可能被缩小

Deque的非更易型操作

c.empty()  //相当于size()==0,但也许较快
c.size()   //返回当前容器的元素个数
c.max_size()  //返回元素个数之最大可能量
c.shrink_ro_fit()  //要求降低容量,以符合元素个数
c1==c2  //  返回c1是否等于c2
c1!=c2  //  返回c1是否不等于c2
c1>c2   //  返回c1是否大于c2
c1<c2   //  返回c1是否小于c2
c1>=c2  //  返回c1是否大于等于c2
c1<=c2  //  返回c1是否小于等于c2
c[idx]  //  返回idx所指向的元素(不检查范围)
c.at(idx)  // 返回idx所指向的元素(不检查范围)
c.front()  // 返回第一元素
c.back()   // 返回最末元素
c.begin()  // 返回一个random-access iterator指向第一位元素
c.end()    // 返回一个random-access iterator指向末尾下一位元素
c.cbegin() // 返回一个const random-access iterator指向第一位元素
c.cend()   // 返回一个const random-access iterator指向末尾下一位元素
c.rbegin() // 返回一个reverse random-access iterator指向第一位元素
c.rend()   // 返回一个reverse random-access iterator指向末尾下一位元素
c.crbegin()// 返回一个const reverse random-access iterator指向第一位元素
c.crend()  // 返回一个cosst reverse random-access iterator指向末尾下一位元素

有一些特殊事项

  1. 处理at(),没有任何成员函数会”检查索引或迭代器是否有效“

  1. 元素的插入或删除可能导致内存重新分配,所以任何插入或删除动作都会使所以指向deque元素的pointer,reference和iterator失效。唯一例外的是在头部或尾部插入元素,在哪那动作之后pointer和reference仍然有效(但iterator就没有那么幸运)

Deque的更易型操作

c=c2    //将c2的全部元素赋值给c
c=rv    //通过move assign的方式赋予c
c=initlist   //将initlist的所有元素赋值给c
c.assign(n,elem)//复制n个elem赋给c
c.assign(beg,end)//将区间[begin,end)的元素赋给c
c.assign(initlist)//将initlist中的所有元素赋给c
c1.swap(c2)//置换c1和c2的数据
swap(c1,c2)//置换c1和c2的数据
c.push_back(elem)//附加elem的拷贝于容器的末尾
c.pop_back()//移除最后一个元素,但是不返回它
c.push_front()//附加elem的拷贝于容器的首处
c.pop_front()//移除第一个元素,但是不返回它
c.insert(pos,elem)//在pos的前方插入elem的一个拷贝,并且返回新元素的位置
c.insert(pos,n,elem)//在pos的前方插入elem的n个拷贝,并且返回第一个新元素的位置
c.insert(pos,beg,end)//在pos的前方插入elem的一个拷贝,并且返回第一个新元素的位置
c.insert(pos,initlist)//在pos的前方插入elem的一个拷贝,并且返回第一个新元素的位置
c.emplace(pos,args...)//在pos的前方插入以args作为初值的元素,并且返回新元素的位置
c.emplace_back(args...)//末尾插入以args作为初值的元素,并且返回新元素的位置
c.emplace_front(args...)//首处插入以args作为初值的元素,并且返回新元素的位置
c.erase(pos)//移除pos位置上的元素,并返回下一元素的位置
c.erase(beg,end)//移除[begin,end)区间内的元素,并返回下一元素的位置
c.resize(num)//将元素数量改为num,如果size()变大,则以元素default构造函数完成初始化
c.resize(num,elem)//将元素数量改为num,如果size()变大,则以elem的拷贝作为新元素的值
c.clear()//移除所有元素,将容器清空

异常处理

原则上deque提供的异常处理和vector提供的一样。新增的操作函数push_front(),pop_front()分别对应push_back()和pop_front()。C++标准库保证以下行为

  1. 如果push_back()和push_front()在安插元素时,发生异常,则该操作不会有任何作用

  1. pop_back()和poo_front()不会抛出任何的异常

Deque运用演示

下面程序以简单的例子说明deque的功效

#include<iostream>
#include<deque>
#include<string>
#include<algorithm>
#include<iterator>
using namespace std;

int main(){
deque<string>coll;
coll.assign(3,string{"string"});
coll.push_back("last string");
coll.push_front("first string");

copy(coll.cbegin(),coll.cend(),ostream_iterator(cout,"\n"));
cout<<endl;

coll.pop_front();
coll.pop_back();

for(size_t i=1;i<coll.size();++i){
      coll[i]="another "+coll[i];
}

coll.resize(4,"resized string ");

copy(coll.cbegin(),coll.cend(),ostream_iterator<string>(cout,"\n"));
}

输出结果如下

first string
string
string
last string

string
another string
another string
resized string
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Reol520

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值