容器是一种容纳特定类型对象的集合。C++的容器能够分为两类:顺序容器和关联容器。顺序容器的元素排列和元素值大小无关,而是由元素添加到容器中的次序决定的。标准库定义了三种顺序容器的类型:vector、list和deque(双端队列)。此外,标准库还提供了三种容器适配器:stack、queue和prioroty_queue类型。适配器是根据原始的容器类型所提供的操做,经过定义新的操做接口,来适应基础的容器类型。见下表前端
顺序容器 vector 支持快速随机访问 list 支持快速插入/删除 deque 双端队列 顺序容器适配器 stack 后进先出(LIFO)栈 queue 先进先出(FIFO)队列 priority_queue 有优先级管理的队列
定义一个容器类型的对象以前,必须包含相关的头文件。以下:数组
#include<list> #include<vector> #include<deque>
全部容器都定义了默认构造函数,能够用默认构造函数来初始化一个空的容器对象,以下:函数
list<int> ilist;
此外,容器还有几种构造函数,能够用来初始化容器对象,以下:spa
C<T> c 建立一个名为c的空容器。C是容器名,T是元素类型。适用于全部容器 C c(c2) 建立容器c2的副本c。二者必须是相同类型的容器和元素。适用于全部容器 C c(b,e) 建立c,其元素是迭代器b和e标记范围内元素的副本。适用于全部容器 C c(n,t) 用n个值为t的元素建立c,其中t必须是容器类型C的元素类型的值或者是能够转化为该类型的值。只适用于顺序容器 C c(n) 建立n个初始化元素的容器c。只适用于顺序容器
值得注意到是,接受容器大小作形参的构造函数只适用于顺序容器,不适用于关联容器。因为指针就是迭代器,所以咱们还能够经过使用内置数组中的一对指针初始化容器:指针
char *words[]={"Hi","How","Are","You“}; size_t words_size=sizeof(words)/sizeof(char *); // 使用整个数组初始化words list<string> words2(words,words+words_size);
前面咱们说过,容器是存储某中类型元素的集合,因此能够定义元素是容器类型的容器。例如,能够定义vector类型的容器ivec,其元素为string类型的vector。可是注意,在指定容器元素为容器类型时,必须使用以下空格:code
vector< vector<string> > ivec; //合法。在两个>之间有空格 vector<vector<string>> ivec; //错误。在两个>之间没有空格,>>会致使歧义
顺序容器内置了一些有用的操做:(1)在容器中添加元素;(2)在容器中删除元素;(3)设置容器大小;(4)(若是有的话)获取容器内的第一个和最后一个元素。对象
begin和end操做产生指向容器内第一个元素和最后一个元素的下一位置的迭代器。此外还有逆序迭代器(逆序迭代器从后向前遍历容器,并反转了某些相关的迭代器操做)rbegin和rend。以下:blog
c.begin() 返回一个迭代器,它指向容器c的第一个元素
c.end() 返回一个迭代器,它指向容器c的最后一个元素的下一个位置
c.rbegin() 返回一个逆序迭代器,它指向容器c的最后一个元素
c.rend() 返回一个逆序迭代器,它指向容器c的第一个元素的前一个位置
下表为在顺序表中添加元素的操做。注意其中的适用范围和返回类型。接口
c.push_back() 在容器c的尾部添加值为t的元素。返回void类型
c.push_front(t) 在容器c的前端添加值为t的元素。返回void类型。只适用于list和deque容器类型
c.insert(p,t) 在迭代器p所指向的元素前面插入值为t的新元素。返回指向新添加元素的迭代器
c.insert(p,n,t) 在迭代器p所指向的元素前面插入n个值为t的新元素。返回void类型
c.insert(p,b,e) 在迭代器p所指向的元素前面插入由迭代器b和e标记的范围内的元素。返回void类型
其中push_front只适用于list和deque容器类型,这个操做实如今首部插入新元素的功能。队列
//用push_front在容器尾部依次添加0,1,2,3 list<int> ilist; for(size_t i=0;i!=4;++i) ilist.push_front(i); //ilist内元素序列为:3,2,1,0
须要注意的是,任何insert或push操做均可以致使迭代器失效。因此在编写循环将元素插入到vector和deque容器中时,程序必须确保迭代器在每次循环后都的到更新。
vector<string> ivec; vector<string>::iterator iter=ivec.begin(); while(cin>>word) iter=ivec.insert(iter,word); //效果和push_back同样 //如下是错误的,由于此时iter已经失效 vector<string> ivec; vector<string>::iterator iter=ivec.begin(); while(cin>>word) ivec.insert(iter,word); //错误,通过一轮的insert后iter即失效,不能再调用
全部容器都提供如下与容器大小相关的操做。注意resize操做可能会使迭代器失效。
c.size() 返回容器c中元素的个数。返回类型为c::size_type c.max_size() 返回容器c能够容纳的最多的元素个数.返回类型为c::size_type c.empty() 返回标记容器大小是否为0的布尔值 c.resize(n) 调整容器c的长度大小,使其能容纳n个元素。若是n<c.size(),则删除多出来的元素 c.resize(n,t) 调整容器c的大小,使其能容纳n个元素。全部新添加的元素值为t
在vector和deque容器上作resize操做有可能会使其全部迭代器都失效。对于全部的容器类型,若是resize操做压缩了容器,则指向已删除的元素的迭代器会失效。
如下为访问容器元素的操做。注意·使用越界的下标,或调用空容器的front或back函数,都会致使程序出现严重的错误。
c.back() 返回容器c的最后一个元素的引用。若是c为空,则该操做未定义 c.front() 返回容器c的第一个元素的引用。若是c为空,则该操做未定义 c[n] 返回下标为n的元素的引用。若是n<0或n>=c.size(),则该操做未定义。只适用于vector和deque容器 c.at(n) 返回下标为n的元素的引用。若是下标越界,则该操做未定义。只适用于vector和deque容器
如下为删除容器元素的操做。删除操做会使一些迭代器失效,须要特别注意。下表第一个操做在删除元素前,必须保证迭代器不是指向end的迭代器。
c.erase(p) 删除迭代器p指向的元素。返回一个迭代器,它指向被删除元素后面的元素。若是p指向容器内最后一个元素,则返回的迭代器指向容器的超出末端的下一位置。
若是p自己就是超出容器末端的下一个位置,则该函数未定义
c.erase(b,e) 删除迭代器b和e所标记的范围内全部元素。返回一个迭代器,它指向被删除元素段后面的元素。若是e自己就是指向超出容器末端的下一个位置,
则返回的迭代器也指向容器末端的下一个位置
c.clear() 删除容器c内的全部元素。返回void
c.pop_back() 删除容器c的最后一个元素。返回void。若是容器为空,则该函数未定义
c.pop_front() 删除容器c的第一个元素。妇女会void。若是容器为空,则该函数未定义。只适用于list和deque容器
下表为顺序容器的赋值操做。赋值后左右两边容器相等,尽管赋值以前两个容器的大小不一样,但赋值以后两个容器的长度都为右操做数的长度。
c1=c2 删除容器c1的全部元素,而后将c2的元素复制给c1。c1和c2的类型必须相同
c1.swap(c2) 交换c1和c2的内容,c1和c2的类型必须相同。其效率比把c2元素复制到c1中要高
c.assign(b,e) 从新设置c的元素:将迭代器b和e标记范围内的元素复制到c中。b和e必须不是指向c中元素的迭代器
c.assign(n,t) 将容器c从新设置为存储n个值为t的元素
参考文献
《C++ PRIMER》 中文版