标准模板库

  • 概述

标准模板库STL包括容器、迭代器、算法

容器指包含数据的数据结构,容器中包含的对象是元素;

迭代器指用来访问容器中的元素对象,相当于元素对象的指针;

算法指一些能在各种容器中通用的标准算法,如排序、插入等;

算法使用迭代器在容器上进行操作。




  • 迭代器

一、迭代器是指针的抽象,是一般化的指针(泛型指针);

标准库中的迭代器以类模板方式定义,使得在不同的数据结构上体现统一的行为方式,即以基本相同的方式遍历容器中的元素,无需关心底层的数据结构是顺序存储的vector还是链式存储的list。

标准库中定义的迭代器分为五中,不同类别的迭代器有不同的功能,提供不同操作,见下表:


迭代器操作的含义基本类似于指针类型的相应操作。

二、

标准库中定义的不同容器类型中所定义的迭代期类型属于不同的迭代器类别:

1 vector容器和deque容器的迭代器是随机访问迭代器;

2 list容器的迭代器是双向迭代器;

3 所有关联容器的迭代器都是双向迭代器;

4 容器适配器不支持迭代器;




  • 容器

STL中的容器分为:顺序容器、关联容器、容器适配器;

顺序容器中的元素按照元素在容器中的相对位置进行存储,并通过位置顺序进行访问;

关联容器中的元素按键key排序;

容器适配器使某种容器以另一种抽象类型的方式工作;

注意:C++规定:容器元素所属的类型必须支持复制及赋值操作;引用类型不支持赋值操作,因此不能用作容器元素类型,I/O库类型不支持赋值和复制操作,因此不也不能用作容器元素类型。

一、顺序容器

标准库定义三种顺序容器类,如下表:


1 容器对象的定义及初始化

1.1 容器类是模板类,因此定义容器对象前需要包含相关头文件,再对相应的类模板进行实例化;

vector<int> iv;		// 定义vector对象iv,用以存放int型元素
list<double> dl;
deque<string> sd;

1.2 顺序容器类还提供一些其他构造函数,如下表:


说明:

a C为容器类模板的名字(如list),T为容器中元素的类型,c为被创建的容器对象;

b 前三个构造函数适用于所有容器,后两个仅适用于顺序容器;

c 值初始化是指在没有指定初始值的情况下,由标准库自动生成初始值进行元素的初始化;元素类型为内置类型时,标准库使用0值作为元素的初始值;元素类型为类类型,标准库使用该类的默认构造函数对元素进行初始化;

(注意:若元素类型为类类型,且该类有自定义的构造函数但没有默认构造函数,则不能使用上表中列出的最后一种构造函数来创建容器对象)

举例:

// 分配指定数目的元素,对这些元素进行值初始化
vector<int> iv1(10); // iv1包含10个0值元素
// 分配指定目数的元素,将这些元素初始化为指定值
vector<int> iv2(10,1); // iv2包含10个1值元素
// 将vector对象初始化为一段元素的副本
int ia[]={0,1,2,3,4,5,6,7,8,9};
vector<int> iv3(ia,ia+10); // iv3包含10个元素,值分别为0~9

注意:使用迭代器参数时,容器类型可以不同,且容器中元素的类型也只需兼容即可。


2 容器中定义的类型别名

为方便定义和使用,标准库中容器类型提供类型别名;

类型别名的定义一般与容器中的元素类型有关,主要用于在容器类中声明变量、成员函数的形参、成员函数的返回值等。


使用容器类中定义的类型别名时,需要在别名前加上容器类名限定;

如使用存放int型元素的vector容器中定义的类型别名iterator,应表示为vector<int>::iterator。


3 访问元素

访问容器中元素有两种方式:使用容器类所提供的访问操作;通过容器的迭代器。

3.1 顺序容器的元素访问操作


举例:

#include <iostream>
#include <vector>
using namespace std;
int main()
{
	int ia[]={0,1,2,3,4,5,6,7,8,9};
	vector<int> iv(ia,ia+10);
	
	iv.front()=10;
	iv[1]=11;
	iv.at(2)=12;
	iv.back()=19;
	
	cout<<"The first element: "<<iv[0]<<endl;
	cout<<"The second element: "<<iv.at(1)<<endl;
	cout<<"The third element: "<<iv[2]<<endl;
	cout<<"The last element: "<<iv.at(9)<<endl;
 
	system("pause");
	return 0;
}

执行结果:

The first element: 10

The second element: 11

The third element: 12

The last element: 19


3.2 通过容器迭代器访问容器元素


举例:

#include <iostream>
#include <vector>
using namespace std;
int main()
{
	vector<int> iv(10,2);				// 创建含10个值为2的元素的vector容器
	vector<int>::iterator it;			// 声明迭代器对象
	vector<int>::reverse_iterator rit;	// 声明逆向迭代器对象
	
	it=iv.begin();		//it指向第一个元素
	*it+=10;
	
	rit=iv.rend();		// rit指向第一个元素的前一个位置
	*rit+=10;			// 将第一个元素的值加10
	
	it=iv.end();		// it指向最后一个元素的下一个位置
	*(it-1)=100;		// 将最后一个元素的值改为100
	
	rit=iv.rbrgin();	// rit指向最后一个元素
	*rit-=20;			// 将最后一个元素值减20
	
	for(it=iv.begin();it!=iv.end();it++)
		cout<<*it<<" ";
 
	system("pause");
	return 0;
}

执行结果:

22 2 2 2 2 2 2 2 2 80


4 增加元素

一个容器对象创建后,应该允许向其中增加元素;


说明:c表示容器对象;vector容器不提供push_front操作。

举例:

#include <iostream>
#include <vector>
#include <deque>
#include <string>
using namespace std;
int main(){
	vector<int> iv;
	deque<string> sd;
	int ia[]={100,100,100};
	
	for(int i=1;i<11;i++){	// 在尾端增加10个元素1~10
		iv.push_back(i);
	}
	
	iv.insert(iv.begin(),20);	// 在vector容器头端增加一个元素
	
	iv.insert(iv.begin()+4,2,30);	// 在vector容器的第四个元素后增加两个元素
	
	iv.insert(iv.end(),ia,ia+3);	// 在vector容器的尾端增加数组ia的前三个元素
	
	sd.push_back("is");
	sd.push_front("this");
	sd.insert(sd.end(),"an");
	sd.insert(sd.end(),"example");
	
	for(vector<int>::iterator it=iv.begin();it!=iv.end();it++)
		cout<<*it<<" ";
	cout<<endl;
	
	for(deque<string>::iterator it=sd.begin();it!=sd.end();it++)
		cout<<*it<<" ";
	cout<<endl;
 
	system("pause");
	return 0;
}

执行结果:

20 1 2 3 30 30 4 5 6 7 8 9 10 100 100 100

this is an example

补充:容器类型与操作效率

vector容器基于数组实现,其元素在内存中连续存放,因此元素的随机访问效率很高;同事因为元素连续存放,vector容器除容器尾部,在其他任意位置插入或删除元素时,都需要移动该元素后面的所有元素,效率较低;

list容器采用双向链表结构实现,其元素不是连续存放的,因此进行元素的插入和删除时无需移动其他元素,只需修改链表指针即可。因此list容器在任意位置进行插入和删除操作非常高效;同时因为元素不连续存放,list容器不支持快速随机访问,要访问某个特定元素需要正向或逆向遍历所涉及的其他元素,效率较低;

deque容器基于数组实现,但采用更为复杂的数据结构,在容器的两端插入和删除元素的效率都很高,但在容器的中间位置进行插入或删除操作效率不如list容器,因为deque容器基于数组实现,一次对元素进行随机访问的效率也较高。

在利用容器编程时,应根据应用特点选用不同类型的容器,提高程序的执行速度。


5 删除元素

对于已经建立并包含元素的容器,允许删除其中元素。


举例:

<pre name="code" class="cpp">#include <iostream>
#include <deque>
using namespace std;
int main(){
	int ia[]={1,2,3,4,5,6,7,8,9,10};
	deque<int> id(ia,ia+10);
	deque<int>::iterator it;
	
	for(it=id.begin();it!=id.end();it++)
		cout<<*it<<" ";
	
	id.pop_front();
	id.pop_back();
	for(it=id.begin();it!=id.end();it++)
		cout<<*it<<" ";
	
	it=id.begin();
	id.erase(id.erase(it+1));	// 删除第二、三个元素
	for(it=id.begin();it!=id.end();it++)
		cout<<*it<<" ";
	
	id.erase(id.begin(),id.begin()+3);	// 删除前三个元素
	for(it=id.begin();it!=id.end();it++)
		cout<<*it<<" ";
	
	id.clear();
	if(id.empty())
		cout<<"No element in double-ended queue"<<endl;
 
	system("pause");
	return 0;
}

 

注意:不是所有容器的迭代器都支持+操作,如list容器;


6 容器的比较

每一种容器都支持比较操作,比较操作使用关系操作符:== != < <= > >=;

两个容器对象可进行比较的前提是容器类型相同,容器中元素的类型相同;

若容器的元素类型不支持某个关系操作符,则此类容器不能进行相应的比较;



7 有关容器大小的操作

容器大小指容器中当前存放元素的数目;



8 容器的赋值与交换

容器的赋值与交换作用于整个容器;


注意:swap操作不会进行删除和插入元素的操作,只是交换两个容器的名字;

某些容器操作会对元素的数量或位置产生影响,有可能使得容器中的某些迭代器失效;因此不要对begin、end等操作所返回的迭代器进行存储然后重复利用,应在每次需要这些迭代器时都利用相关操作来获取。


二、关联容器

关联容器不是通过位置顺序存储和访问元素,而是通过键key对元素进行存储和访问;

关联容器支持大部分操作,包括:前三个构造函数;所有获取迭代器的容器操作;insert操作;clear和erase操作;关系操作;有关容器大小的操作(除resize操作);赋值和交换操作(除assign操作);

标准库中提供四种关联容器:


1 pair类型

map和multimap容器类中使用pair类型作为元素类型,是一个模板类,在头文件utility中定义;

一个pair对象包含两个数据成员:first和second,这两个成员都是公有成员,因此可直接通过pair对象访问。

创建pair对象的操作:


pair对象的比较操作:



2 map容器

map容器是键-值对的集合,通常称为关联数组,所谓“关联”是指元素的值与键之间的关联通过键来访问值;

2.1 map对象的定义及初始化

map容器类提供三个构造函数:

2.2 map类中定义的类型别名

除顺序容器类中定义的类型别名外,map类还定义一下类型别名:


注意:

map类中的value_type是pair类型,其first成员是const类型,即map容器中元素的键不能修改;

若要修改容器中某元素的键,只能用间接方式:首先删除该元素,再插入一个新元素,新元素的键设置为所需的键;

2.3 访问map容器中的元素

使用元素下标指向元素的迭代器访问map容器中的元素;

其中,使用下标操作时,需注意:

a 容器的元素下标可以是整型,也可以是其他类型(如string);

b 使用下标访问元素时,若该元素存在,则返回元素中的值;若指定的元素不存在,将会导致在容器中增加一个新元素,该元素中”键“的取值是所给定的下标值,该元素中的”值“采用值初始化;

c map容器下标操作的返回值类型是map容器中定义的mapped_type类型,容器的迭代器的解引用*操作的返回值类型是容器中定义的value_type类型;

2.4 在map容器中增加元素

使用insert操作使用下标获取元素,再给获取的元素的值赋值

其中,map容器提供insert操作:


注意:map容器不提供push_back和push_front操作,且若插入的元素所对应的键已在容器中存在,则insert将不做任何操作;

2.5 在map容器中查找元素

map容器的下标操作有副作用:若指定键(下标)对应的元素在map容器中不存在,则下标操作会导致在map容器中插入新元素;

若仅想检查某个键在map容器中是否存在,不希望插入元素,可使用find和count操作:


2.6 从map容器中删除元素

使用erase操作从map容器中删除元素:



3 multimap容器

multimap容器与map容器类似,唯一区别是:multimap容器中的键可以重复,即可以有多个元素中包含相同的键;

因为multimap容器中一个键可能与多个值相关联,因此multimap类不支持下标操作;

下面列出multimap操作不同于map操作的地方:

insert操作每调用一次都会增加新的元素(multimap容器中,键相同的元素相邻存放);

以键值为参数的erase操作删除该键所关联的所有元素,并返回被删除元素的数目;

count操作返回指定键的出现次数;

find操作返回的迭代器指向与被查找键相关的第一个元素;

获取与指定键关联的元素迭代器的操作:



4 set容器

set容器用于集合,该集合中的元素不能重复;set容器的元素就是键本身,即只存储键;

map容器所支持的操作,set容器基本上都支持;仅有以下区别:

set容器不支持下标操作;

set容器类中没有定义mapped_type类型;

set容器中定义的value_type类型不是pair类型,而是与key_type相同,指的都是set中元素的类型;


5 multiset容器

multiset容器与set容器类似,唯一区别在于:multiset容器中的键可以重复,即可以存放重复的元素;




三、容器适配器

所谓”适配器“是指,使某一事物的行为类似于另一事物的行为的一种机制;

标准库中提供三种容器适配器:


省略。。。


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一份讲解全面的标准模板STL学习资料 标准模板STL主要由6大组件组成: (1)容器(Containers)。包括各种基本数据结构的类模板。 STL容器部分主要由头文件<vector>、<list>、<deque>、<set>、< map>、<stack>和<queue>组成。 (2)算法(Algorithms)。包括各种基本算法,如比较、交换、查找、排序、遍历操作、复制、修改、移除、反转、合并等等。 STL算法部分主要由头文件<algorithm>和<numeric>组成。 (3)迭代器(Iterators)。迭代器是面向对象版本的指针,如同指针可以指向内存中的一个地址,迭代器可以指向容器中的一个位置。 STL的每一个容器类模板中,都定义了一组对应的迭代器类,用以存取容器中的元素。这样,在STL中迭代器就将算法和容器联系起来了,通过迭代器,算法函数可以访问容器中指定位置的元素,而无需关心元素的具体类型。 STL迭代器部分主要由头文件<utility>和<iterator>组成。 (4)函数对象(Function Objects)。一种行为类似于函数的class,实现技术上是一个改写了“call operator()”的class。 STL 提供 15 个预定义的 Function objects。头文件<functional>中定义了一些类模板,用以声明函数对象。 (5)适配器(Adaptors)。简单地说就是一种接口类,专门用来修改现有类的接口,提供一种新的接口;或调用现有的函数来实现所需要的功能。 主要包括3种适配器Container Adaptors、Iterator Adaptors与Function Adaptors。其中迭代器适配器的定义在头文件<iterator>中,函数适配器的定义在头文件<functional>中。 (6)内存配置器(Allocators)。为STL提供空间配置的系统。 头文件<memory>中的主要部分是模板类allocator,它负责产生所有容器中的默认分配器。容器使用allocator完成对内存的操作,allocator提供内存原语以对内存进行统一的存取。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值