顺序容器的操作
每种容器都提供一组有用的类型定义以及如下操作
1. 在容器中添加元素
2. 在容器中删除元素
3. 设置容器大小
4. 获取容器内第一个和最后一个元素
1. 容器定义的类型别名
逆序迭代器从后向前遍历容器,并翻转某些相关的迭代器操作。如++rverse_iter 相当于指向前一个元素而不是后一个元素
需要使用容器元素时,用value_type即可,如果要引用,则可以通过reference和const_reference类型实现。在编程泛型时,这些元素相关定义非常有用。
容器定义的类型别名 | 说明 |
---|---|
size_type | 容器容量 unsigned int型,最大可能容器长度 |
iterator | 迭代器 |
const_iterator | 元素的只读迭代器 |
reverse_iterator | 逆序迭代器 |
const_reverse_iterator | 只读的元素逆序迭代器 |
difference_type | 两个迭代器差值 有符号型 |
value_type | 容器元素类型 |
reference | 容器元素的引用 |
const_reference | 常量引用 |
2. begin和end成员
操作 | 说明 |
---|---|
c.begin() | 返回指向容器c的第一个元素的迭代器 |
c.end() | 返回指向容器c的最后一个元素的下一位置的迭代器 |
c.rbegin() | 逆序迭代器 c.rbegin()== (--c.end()) |
c.rend() | (--c.rend())==c.begin() |
3. 在顺序容器中添加元素
所有顺序容器都支持push_back 操作在容器尾部插入一个元素,并使容器长度+1.
string text_word;
while(){
container.push_back(text_word);
}
关键概念
容器中添加元素,试讲元素值复制到容器中,类似,使用一段元素初始化容器时,存放的是元素副本。
容器中添加元素的操作
操作 | 说明 |
---|---|
c.push_back(t) | 返回void ,在容器尾部插入一个元素,均摊时间复杂度:O(1) |
c.push_front(t) | 返回void,在容器c前段插入一个元素,适用deque和list |
c.insert(p,t) | 返回指向新插入元素的迭代器位置,在p之前插入,考虑p为end()情况,因此插入都是在p之前插入 |
c.insert(p,n,t) | 返回void,在p之前重复插入n个t |
c.insert(p,b,e) | 返回void,在p之前插入[b,e)范围内的元素 |
虽然vector没有push_front 函数,但是用insert(vec.begin(),t)即可实现。
insert操作时间复杂度与p位置有关,涉及到已有元素的移动,平均时间复杂度是O(n)
4. 关系操作符
所有容器都支持用关系操作符来实现两个容器的比较。比较容器必须具有相同容器类型和相同元素类型。
容器比较是基于容器内元素的比较。因此,容器元素如果不支持某种关系运算符,则该容器也不支持。
如果c1,c2都是容器,且表达式c1 < c2
合法,那么两个容器类型相同,并且元素类型也相同,并且元素支持 < 运算符。
5. 容器大小操作
操作 | 说明 |
---|---|
c.size() | 返回c中元素个数 |
c.empty() | 返回bool判断容器是否空 |
c.resize(n) | 调整容器大小,使其能容纳n个元素。若n<c.size(),删除多余元素;若n>c.size(),采用值初始化添加的新元素 |
c.resize(n,t) | 若n>c.size(),用t初始化添加的元素值 |
resize操作失效问题
在vector和deque上操作resize操作可能会使所有的迭代器失效,realloc重新分配
如果resize压缩了容器,则指向已经删除的元素的迭代器失效
6. 访问元素
如果元素非空,那么front返回第一个元素的引用,back返回最后一个元素的引用。
操作 | 说明 |
---|---|
c.front() | 返回第一个元素引用 |
c.back() | 返回最后一个元素的引用 |
c[n] | 只适用于vector和deque,n值编译器不检查 |
c.at(n) | 只适用vector和的确,n值编译器不检查,会抛出out_of_range运行时错误 |
7. 删除元素
操作 | 说明 |
---|---|
c.erase(p) | 删除迭代器p所指向的元素,返回一个迭代器,指向删除元素后面的元素,如果p指向最后一个元素,则返回容器末尾下一位置 |
c.erase(b,e) | 删除迭代范围[b,e),返回e位置,如果e本身为容器末尾下一位置,则返回e也为容器末尾下一位置 |
c.clear() | 删除容器中所有元素,返回void |
c.pop_back() | 删除容器c最后一个元素,返回void |
c.pop_front() | 删除容器第一个元素,返回void |
注意容器删除操作要检查容器是否为空,以及所给迭代器是否合法,编译器不负责检查。
pop_front和front操作配套使用,实现以栈方式处理容器。
pop_front只有deque和list才有的操作,vector没有
#include <iostream>
#include <vector>
#include <list>
using namespace std;
#define ArrayLength(X) ((sizeof(X))/(sizeof(X[0])))
int main()
{
int ia[]={1,2,3,4,5,6,7,8,9,10};
vector<int> ivec(ia,ia+ArrayLength(ia));
list<int> ilist(ia,ia+ArrayLength(ia));
for (vector<int>::const_iterator beg=ivec.begin();beg!=ivec.end();++beg)
{
cout<<*beg<<" ";
}
cout<<endl;
for (list<int>::const_iterator beg=ilist.begin();beg!=ilist.end();)
{
//清除list中所有奇数
if (*beg & 0x01)
{
cout<<"清除"<<*beg <<" ";
beg = ilist.erase(beg);
cout<<"之后 beg指向元素"<<*beg<<endl;
}
else
{
++beg;
}
}
cout<<"iList:";
for (list<int>::const_iterator beg=ilist.begin();beg!=ilist.end();++beg)
{
cout<<*beg<<" ";
}
cout<<endl;
cout<<"vector:";
for(vector<int>::const_iterator beg=ivec.begin();beg!=ivec.end();)
{
//清除vector中所有偶数
if (*beg & 0x01)
++beg;
else
beg=ivec.erase(beg);
}
for (vector<int>::const_iterator beg=ivec.begin();beg!=ivec.end();++beg)
{
cout<<*beg<<" ";
}
cout<<endl;
system("pause");
return 0;
}
8. 赋值与swap
与赋值相关的操作符都作用于整个容器。除swap操作外,其他操作都可以用erase和insert操作实现。赋值操作符首先删除其左操作数容器内的所有元素,然后将右操作数容器内的所有元素都插入到左边容器
c1=c2;
c1.erase(c1.begin(),c1.end());
c1.insert(c1.begin(),c2.begin(),c2.end());
赋值和assign操作都使左操作数容器的所有迭代器失效。
swap操作则不会使迭代器失效。完成swap操作后,尽管被交换元素已经存放在另外一个容器,但是迭代器仍然指向相同元素。
操作 | 说明 |
---|---|
c1=c2 | 删除容器c1内元素,将c2内元素复制给c1,c1和c2类型相同(容器类型,元素类型) |
c1.swap(c2) | 交换内容:调用完该函数,c1存放的是c2内的元素;c2存放的是c1内的元素。c1和c2必须类型相同。 |
c.assign(b,e) | 重置c元素,将[b,e)内的元素复制到c,b和e必须是不指向c中元素的迭代器 |
c.assign(n,t) | 将容器c重置为n个t值 |
使用assign
assign首先删除容器内元素,然后将新元素插入容器。赋值操作符仅适合类型相同(容器类型,元素类型)assign适合容器类型相同/不相同,容器元素类型相同/兼容。如可以通过将char * 类型转换成string类型
//容器类型不相同,元素类型相同都是int
ivec.assign(ilist.begin(),ilist.end());
vector<char *> svec(4,"china tea");
//访问元素返回引用可以作为左值进行修改
svec.front()="chinese";
svec.back()="comedy";
svec.at(1)="one";
for (vector<char*>::iterator beg=svec.begin();beg!=svec.end();++beg)
{
cout<<*beg<<" ";
}
cout<<endl;
list<string> slist;
//容器类型不相同,元素类型相互兼容
slist.assign(svec.begin(),svec.end());
for (list<string>::iterator beg=slist.begin();beg!=slist.end();++beg)
{
cout<<beg->c_str()<<" ";
}
cout<<endl;
//重置元素,和容器初始化相似
ivec.assign(10,1);
使用swap操作节省删除元素成本
swap操作实现交换两个容器内所有元素功能。待交换容器必须完全匹配。该操作不会插入或删除任何元素,保证在常量时间内实现交换。由于没有移动任何元素,迭代器不失效。
vector<string> svec1(10);
vector<string> svec2(20);
svec1.swap(svec2);
执行交换后,svec1内有24个string元素,svec2内有10个string元素。如果交换前svec_beg迭代器指向svec1[0],那么交换后svec_beg指向svec2[0](这是同一个元素只是存储在不同容器中了,迭代器并未失效)。swap操作只会交换两个容器内部数据结构,即交换容器中各元素的内存地址,并不是交换各个元素变量所存储的值。