STL之容器、迭代器及算法知识总结

STL的关键组件包括容器(container)、迭代器(iterator)及算法(algorithm),本文就这3部分内容进行总结。

容器按照类型分为序列式容器和关联式容器,其中序列式容器包括vector、deque、list等可序群集,关联式容器包括set、multiset、map、multimap等。

vector实现采用动态数组方式,可以直接存取任意元素,支持在尾部插入和删除元素且实现速度快,在数组前端和内部插入和删除元素效率较低,因为涉及到修改元素后面的所有元素位置发生改变,具体使用实例如下所示:

#include 
#include 
using namespace std;
int main(){	
	vector a;
	for(int i=0;i<5;i++){
		a.push_back('a'+i);
	}
	for(int i=0;i<5;i++){
		cout< b(5,19);
	b.insert(b.begin(),17);
	for(int i=0;i<6;i++){
		cout<
STL之容器、迭代器及算法知识总结_第1张图片

deque是double-ended queue的缩写,表示双端队列,也是采用动态数组实现,支持随机存取任何元素,可以在前端和尾部插入元素且效率高,在内部插入元素需要移动其他元素效率较低,具体使用实例如下所示:

#include 
#include 
using namespace std;
int main(){	
	deque a;
	for(int i=0;i<5;i++){
		a.push_back('a'+i);
		a.push_front('H'+i);
	}
	for(int i=0;i<10;i++){
		cout< b(5,19);
	b.insert(b.begin()+2,17);
	b.insert(b.end()-3,16);
	for(int i=0;i<7;i++){
		cout<
STL之容器、迭代器及算法知识总结_第2张图片

list为双向链表,每个元素内存保存有数据及前后元素指针,不支持随机存取,只能通过遍历的方式访问元素,其优点在于在list内部插入或删除元素效率较高,只需改变前节点的next和后节点的prev,其他元素不受影响,因此效率较高,具体使用实例如下:

#include 
#include 
using namespace std;
int main(){	
	list a;
	for(int i=0;i<5;i++){
		a.push_back('a'+i);
		a.push_front('H'+i);
	}
	for(list::iterator it=a.begin();it!=a.end();it++){
		cout<<*it<<" ";
		
	}
	a.erase(a.begin(),a.end());
	cout< b(5,19);
	b.insert(++b.begin(),17);
	b.insert(--b.end(),16);
	for(list::iterator it=b.begin();it!=b.end();it++){
		cout<<*b.begin()<<" ";
		b.pop_front();	
		b.pop_back();	
	}
	cout<
STL之容器、迭代器及算法知识总结_第3张图片

此外,string和array虽然不是容器类,但是也可以视为STL容器来使用STL算法。

关联式容器依据特定的排序准则,自动为其元素排序,排序准则以函数形式实现,比较值或者键,缺省情况下采用operator<来比较,通常采用二叉树结构存储,节点的左子树小于该元素,右子树大于该元素。关联式容器不支持push_back、push_front、pop_front、pop_back等操作,因为其是已序序列,程序员不能自己给其设定位置,插入只需使用insert,删除使用erase。set中每个元素存储一个变量,而map存储一个pair对组(2个变量),multi-前缀主要用来说明元素是可以重复的。具体的使用实例如下所示:

#include 
#include 
//#include 
#include 
//#include 
using namespace std;
int main(){	
	set a;
	for(int i=0;i<5;i++){
		a.insert('a'-i);
		a.insert('a'-i);
	}
	for(set::iterator it=a.begin();it!=a.end();it++){
		cout<<*it<<" ";
	}
	cout< b;
	
		b.insert('s');
		b.insert('a');
		b.insert('s');
		b.insert('h');
		b.insert('e');
	
	for(set::iterator it=b.begin();it!=b.end();it++){
		cout<<*it<<" ";
	}
	cout< c;
	
		c.insert(make_pair(5,"hello"));		
		c.insert(make_pair(4,"nihao"));
		c[3]="good afternoon";
		c[5]="hello!";
		c[3]="good afternoon";
		c[3]="good";
		c[6]="nihao";
		for(map::iterator it=c.begin();it!=c.end();it++){
			cout<first<<" "<second< e;
		e["haha"]=78;
	multimap d;
	d.insert(make_pair("alex",111));
	d.insert(make_pair("alex",111));
	d.insert(make_pair("alex",101));
	d.insert(make_pair("ace",111));
	//d["James"]=23;
	//d["alex"]=111;
	//d["alex"]=123;
	for(multimap::const_iterator it=d.begin();it!=d.end();it++){
			cout<first<<" "<second<::const_iterator it=d.begin();it!=d.end();it++){
			cout<first<<" "<second<
STL之容器、迭代器及算法知识总结_第4张图片

由以上可以测试得知,不存在multimap与multiset头文件,使用它们时只需包含map与set头文件即可,map描述了一对一的关系,键不能重复,multimap描述了多对多的关系,键可以重复。map支持operator[]操作符,而multimap因为其键不唯一,由于不确定性所以不支持operator[]操作,可以看出关联式容器给自动排序,erase函数可以根据键和迭代器。

迭代器分为两类:双向迭代器和随机存取迭代器,list、map、multimap、set、multiset等提供的是双向迭代器,可以双向前进即operator++、operator--,但不能随机访问即operator+、operator-。vector、deque、string等提供的是随机存取迭代器,支持随机访问。

为了处理容器内的元素,STL提供了一些标准算法,包括搜寻、排序、拷贝、重新排序、修改、数值运算等,算法并非容器的成员函数,而是一种搭配迭代器使用的全局函数,因此只需提供一份算法,可应用于所有容器类,因此降低了代码的数量,这也是泛型编程的思想即数据结构与函数分离。

#include 
#include 
#include 
using namespace std;
int main(){	
	vector x;
	x.push_back(2);
	x.push_back(5);
	x.push_back(3);
	x.push_back(6);
	x.push_back(1);
	x.push_back(4);
	vector::iterator it;
	it=min_element(x.begin(),x.end());
	cout<<*it<
从以上程序可以看出,min_element和max_element通过传入两个迭代器指针,获得迭代器之间的最小和最大元素的迭代器指针,使用sort对选定的两个迭代器之间的元素进行排序,find函数在指定的区间查找某个元素并返回其所在迭代器指针,reverse函数翻转指定迭代器范围内的所有元素。STL函数规定采用相同的接口表示范围,这种范围使用前闭后开区间表示,且前后顺序不能颠倒。当处理两个区间时,只需一个区间前后两端迭代器,另一个区间只需前端迭代器。

if(equal(x.begin(),x.end(),y.begin())){
		cout<<"true"<
以上程序为equal、copy、resize等函数的测试实例。迭代器配接器包括安插性迭代器(Insert iterator)、流迭代器(Stream iterator)、逆向迭代器(Reverse iterator)。

首先介绍3种安插性迭代器back_inserter、front_inserter、inserter,如下图所示:

STL之容器、迭代器及算法知识总结_第5张图片

#include 
#include 
#include 
using namespace std;
int main(){	
	deque x;
	x.push_back(2);
	x.push_back(5);
	x.push_back(3);
	x.push_back(6);
	x.push_back(1);
	x.push_back(4);
	deque y;
	deque::iterator it;
	cout<<"x: ";
	for(it=x.begin();it!=x.end();it++){
		cout<<*it<<" ";
	}
	cout<	y.resize(x.size());
	copy(x.begin(),x.end(),y.begin());
	cout<<"y: ";
	for(it=y.begin();it!=y.end();it++){
		cout<<*it<<" ";
	}
	cout<	y.push_back(0);
	cout<<"push(0) y: ";
	for(it=y.begin();it!=y.end();it++){
		cout<<*it<<" ";
	}
	cout<	copy(x.begin(),x.end(),inserter(y,y.begin()+1));
	cout<<"inserter: ";
	for(it=y.begin();it!=y.end();it++){
		cout<<*it<<" ";
	}
	cout<	copy(x.begin(),x.end(),back_inserter(y));
	cout<<"back_inserter: ";
	for(it=y.begin();it!=y.end();it++){
		cout<<*it<<" ";
	}
	cout<	copy(x.begin(),x.end(),front_inserter(y));
	cout<<"front_inserter: ";
	for(it=y.begin();it!=y.end();it++){
		cout<<*it<<" ";
	}
	cout<	
	return 0;	
}
STL之容器、迭代器及算法知识总结_第6张图片

以上的测试实例可以看出,copy容器时,需resize容器的大小,否则拷贝失败,调用copy函数时,若第三个参数不直接选择目标容器的迭代器指针,也可使用安插性迭代器,使用inserter时,即调用insert函数,所以还需给出插入位置迭代器指针,使用back_inserter时,即调用push_back,同理使用front_inserter时,即调用push_front。不过要注意,map、set等关联性容器不支持push_back和push_front操作,所以只能使用inserter,vector不能使用push_front,所以。。

流迭代器包括istream_iterator和ostream_iterator两种,具体使用实例如下所示:

#include 
#include 
#include 
#include 
#include 
using namespace std;
int main(){	
	vector coll;
	copy(istream_iterator (cin),istream_iterator (),back_inserter(coll));
	sort(coll.begin(),coll.end());
	unique_copy(coll.begin(),coll.end(),ostream_iterator (cout,"\n"));
	return 0;	
}
STL之容器、迭代器及算法知识总结_第7张图片
注意,使用流迭代器时需要包含头文件,这点与安插性迭代器不同,此外,unique_copy函数去除了相邻的相同元素,因此一般搭配sort函数一起使用。

除了安插性迭代器和流迭代器,还有一个逆向迭代器,主要是容器内预定义的rbegin和rend函数,注意rbegin和end-1相等,rend和begin-1相等。

下面介绍更易型算法,remove函数的程序实例如下:

#include 
#include 
#include 
#include 
#include 
using namespace std;
int main(){	
	vector coll;
	coll.push_back("nihao");
	coll.push_back("hello");
	coll.push_back("how are you");
	vector::iterator end=remove(coll.begin(),coll.end(),"hello");
	cout<(cout,"\n"));
	cout<(cout,"\n"));
	coll.erase(end,coll.end());
	for(vector::iterator it=coll.begin();it!=coll.end();it++){
		cout<<*it<
STL之容器、迭代器及算法知识总结_第8张图片
remove函数将移除的元素放到了容器的尾部,并不改变容器的大小和begin及end迭代器指针,返回一个新的end迭代器,可以利用distance函数计算随机访问迭代器的距离,若想彻底删除元素可使用容器的erase成员函数。关联式容器是已序的,所以不能使用remove,删除只能用erase函数。基本容器类都定义了自己的更易型成员函数如erase,所以尽量使用容器类定义的成员函数,防止出现意外情况。

一天的时间,STL正式入门阶段,加油。。。

你可能感兴趣的:(STL之容器、迭代器及算法知识总结)