顺序容器的操作

每种容器都提供一组有用的类型定义以及如下操作

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操作只会交换两个容器内部数据结构,即交换容器中各元素的内存地址,并不是交换各个元素变量所存储的值。

原文地址:https://www.cnblogs.com/gaochaochao/p/11890694.html