1、序容器类型和特点
顺序容器类型 | 特点 |
vector | 可变长度数组。支持快速随机访问。在尾部外的位置插入或删除元素速度很慢 |
deque | 双端队列。支持快速随机访问。在头尾位置插入和删除速度很快 |
list | 双向链表。只支持双向的顺序访问。在list的任何位置插入和删除速度都很快 |
forward_list | 单向链表。只支持单向顺序访问。在任何位置插入和删除速度都很快 |
array | 固定大小数组。支持快速随机访问。不能添加或删除元素。 |
string | 专门用来保存字符的容器。支持快速随机访问。在尾部插入和删除速度快 |
string和vector将元素保存在连续内存空间,用下标计算其地址很快,添加或删除元素会很耗时。
list和forward_list在任何位置插入和删除速度都很快,与vector、deque和array比内存开销大。
array对象的大小固定。forward_list没有size操作。
2、范围由一对迭代器表示,通常称为begin和end,分别指向同一容器的元素和尾元素之后的位置,容器中的元素范围是左闭右开区间,即[begin, end)。
vector<string> vec;
auto beg1=vec.begin(); // iterator
auto beg2=vec.rbegin(); // reverse_Piterator
auto cbeg1=vec.begin(); // const_iterator
auto cbeg2=vec.crbegin(); // const_reverse_iterator
3、容器定义和初始化
C c; | 默认构造函数。如果C是array,则c中的元素是默认初始化,否则c为空 |
C c1(c2) C c1=c2 | c1初始化为c2的拷贝。c1和c2必须是相同类型(必须是相同类型的容器,且其中的元素类型也相同;对于array,必须具有相同大小) |
C c{a,b,c...} C c={a,b,c...} | c初始化为列表中元素的拷贝。列表中元素的类型必须与C中元素类型相容。对于array类型,列表中元素的个数必须小于或等于array的大小,遗漏的元素用值初始化 |
C c(b,e) | c初始化为迭代器b和e指定范围中的元素的拷贝。元素类型必须和C的元素类型相容(array不适用于) |
只有顺序容器(不包括array)的构造函数才能接受大小参数 | |
C seq(n) | seq包含n个进行了值初始化的元素,此构造函数是explicit的(string不适用) |
C seq(n,t) | seq包含n个初始化为t的元素 |
list<string> li={"aa","bb","cc"}; //正确,在VS2013中支持
vector<const char*> vec={"aa","bb","cc"}; //正确,在VS2013中支持
list<string> li2(li); //正确,类型匹配
deque<string> de(li); //错误,类型不匹配
forward_list<string> fl(vec.begin(),vec.end()); //正确,可以将const char*转换为string
4、容器赋值和swap
c1=c2 | c1中的元素替换为c2中元素的拷贝,c1和c2必须有相同的类型 |
c={a,b,c…} | c1中的元素替换为初始化列表中元素的拷贝(array不适用) |
swap(c1,c2) c1.swap(c2) | 交换c1和c2中的元素,c1和c2必须具有相同的类型。swap通常比c2向c1拷贝元素快得多 |
seq.assign(b,e) | 将seq的元素替换为b和e表示范围的元素为,b和e不能指向seq中元素 |
seq.assign(il) | 将seq的元素替换为初始化列表il中的元素 |
seq.assign(n, t) | 将seq的元素替换为n个值为t的元素 |
assign操作不适用于关联容器和array。
赋值相关运算会导致指向左边容器内部的迭代器、引用和指针失效,但是swap操作不会使迭代器、引用和指针失效(array和string情况除外)。
5、向顺序容器添加元素
c.push_back(t) c.emplace_back(args) | 在容器c的尾部创建一个值为t的元素或根据args构建一个元素。返回void |
c.push_front(t) c.emplace_front(args) | 在容器c的头部创建一个值为t的元素或根据args构建一个元素。返回void |
c.insert(p,t) c.emplace(p,args) | 在迭代器p所指元素之前插入一个值为t的元素,或根据args构建一个元素。返回指向插入元素的迭代器 |
c.inesrt(p, n, t) | 在迭代器p所指元素之前插入n个值为t的元素。返回指向插入的第一个元素的迭代器,如果n为0,返回p |
c.insert(p, b, e) | 在迭代器p所指元素之前插入迭代器指向范围为[b,e)的元素,b,e不能指向c本身。 返回指向插入的第一个元素的迭代器,如果范围为空,返回p |
c.insert(p, il) | il是花括号包围的元素值列表。在迭代器p指向的元素之前插入该序列。返回指向插入的第一个元素的迭代器,如果序列为空,返回p |
array不支持上述操作。在vector, string,deque中插入元素会使现有的迭代器,引用和指针无效。forward_list不支持push_back和emplace_back。vector和string不支持push_front和emplace_front。
6、 访问元素
c.back() | 返回容器c的尾元素的引用。如果c为空,函数行为未定义 |
c.front() | 返回容器c的首元素的引用。如果c为空,函数行为未定义 |
c[n] | 返回c中下标n所在位置的元素的引用。如果n>=c.size(),函数行为未定义 |
c.at(n) | 返回c中下标n所在位置的元素的引用。如果n超出范围,则抛出out_of_range异常 |
7、 删除元素
c.pop_back() | 删除容器c尾元素。如果c为空,则未定义。返回void |
c.pop_front() | 删除容器c首元素。如果c为空,则未定义。返回void |
c.erase(p) | 删除迭代器p指向的元素,返回指向被删除元素后一位的迭代器 |
c.erase(b,e) | 删除迭代器范围为[b,e)的元素,返回指向被删除元素后一位的迭代器 |
c.clear() | 删除c的所有元素,返回void |
删除deque中除首尾元素外的任何元素会导致其所有的迭代器、引用和指针失效。在vector或string中删除元素,指向被删除元素后面位置的迭代器、引用和指针会失效。
#include<iostream>
#include<list>
using namespace std;
int main(){
list<int> li{ 1, 9, 7, 6, 4, 8, 5, 4 };//删除list中的奇数
auto it = li.begin();
while (it != li.end())
if (*it % 2)
it = li.erase(it);
else
++it;
for (auto c : li)
cout << c << " ";
cout << endl;
system("pause");
return 0;
}
8、 特殊的forward_list操作
lst.before_begin() lst.cbefore_begin() | 返回指向链表首元素之前不存在的元素的的迭代器,不能解引用。cbefore_begin()返回const_iterator |
lst.insert_after(p,t) lst.insert_after(p,n,t) lst.insert_after(p,b,e) lst.insert_after(p,il) | 在迭代器p所指元素的后面插入相应的元素,返回一个指向最后一个插入元素的迭代器 |
emplace_after(p,args) | 在迭代器p所指元素的后面根据args构造一个新的元素。返回一个指向这个新元素的迭代器 |
lst.erase_after(p) lst.erase_after(b,e) | 删除在迭代器p所指的,或范围为[b,e)的元素。返回被删除元素的后继的迭代器。 |
9、 改变容器大小
c.resize(n) | 调整c的大小为n。如果n < c.size(),删除多余的元素。 若必须添加新元素,对新元素进行值初始化 |
c.resize(n,t) | 调整c的大小为n。任何添加的新元素进行值初始化 |
array不支持resize,如果resize缩小容器,指向被删除元素的迭代器、引用和指针会失效;resize会使vector、string、deque的所以迭代器、引用和指针失效。
如果容器保存的是类类型元素,当resize使得增加元素时,会调用该类的默认构造函数,如果没有默认构造函数,则必须提供与构造函数相应的初始化值。
10、 vector对象如何增长
vector中的元素在内存中连续存储。当不得不获取新的内存时,vector和string通常会分配比新的空间需求更大的内存空间以减少容器空间重新分配次数。
#include<iostream>
#include<vector>
using namespace std;
int main(){
vector<int> vec;
cout<<"size: "<<vec.size()<<" capacity: "<<vec.capacity()<<endl; //size为0,capacity的值依赖具体实现
for(vector<int>::size_type i=0;i!=10;++i)
vec.push_back(i);
cout<<"size: "<<vec.size()<<" capacity: "<<vec.capacity()<<endl;//size为10,capacity的值大于等于10,依赖具体实现
vec.reserve(20);
cout<<"size: "<<vec.size()<<" capacity: "<<vec.capacity()<<endl;//size为10,capacity的值至少为20,依赖具体实现
vec.resize(5);
cout<<"size: "<<vec.size()<<" capacity: "<<vec.capacity()<<endl;//size为5,capacity的值至少为20,依赖具体实现
while(vec.size()!=vec.capacity())
vec.push_back(0);
cout<<"size: "<<vec.size()<<" capacity: "<<vec.capacity()<<endl;//size的值等于capacity的值
vec.push_back(1); //添加了一个新元素,vector重新分配空间,size为21,capacity的值至少为21,依赖具体实现
cout<<"size: "<<vec.size()<<" capacity: "<<vec.capacity()<<endl;
vec.shrink_to_fit(); //要求归还内存,size的值等于capacity的值,为21
cout<<"size: "<<vec.size()<<" capacity: "<<vec.capacity()<<endl;
system("pause");
return 0;
}
11、
额外的
string
操作
string搜索操作 | |
s.find(args) | 查找args第一次出现的位置 |
s.rfind(args) | 查找args最后一次出现的位置 |
s.find_first_of(args) | 在s中查找args任何一个字符第一次出现的位置 |
s.find_last_of(args) | 在s中查找args任何一个字符最后一次出现的位置 |
s.find_first_not_of(args) | 在s中查找第一个不在args中的字符 |
s.find_last_not_of(args) | 在s中查找最后一个不再args中的字符 |
12、容器适配器
标准库定义了三个顺序容器适配器:stack、queue和priority_que。默认情况下,stack和queue在deque上实现,priority_queue在vector上实现。
stack操作 | |
s.empty() | 如果栈空返回true,否则false |
s.size() | 返回栈中元素个数 |
s.pop() | 删除站定元素,不返回其值 |
s.top() | 返回栈顶元素值,不删除 |
s.push(item) | 在栈顶压入新元素 |
queue和priority_que操作 | |
q.empty() | 如果q空,返回true,否则false |
q.size() | 返回队列中元素的个数 |
q.pop() | 删除队首元素或priority_que的最高优先级的元素,但不返回其值 |
q.front() | 返回队首元素的值,但不删除,只用于queue |
q.back() | 返回队尾元素的值,但不删除,只用于queue |
q.top() | 返回具有最高优先级的元素值,但不删除,只用于priority_queue |
q.push(item) q.emplace(args) | 对于queue,在队尾压入新元素;对于priority_queue,在基于优先级的适当位置插入新元素 |