第一章 STL的简单应用

前言:在刷 PAT 乙级题目的过程中,深切感受到了 C++ 标准模板库(STL) 在编写代码中的方便。因此,想先记录一下该应用。当然,若只要求刷题的话,没有必要去过分深究 STL 的源码分析。若想去了解 STL 的实现过程,可以去参考侯捷老师的相关视频、著作。在这,只列举了比较常用的三种容器:vector、map、set。

STL的简单应用

1. 简述

C++ STL(标准模板库)提供了通用的模板类和函数,在这些类和函数之中,集成可多种常用的算法和数据结构。其主要由容器(container)、迭代器(iterator)、算法(algorithm)这三个部分组成。
容器:用来管理某一类对象的集合。其中包含了大部分的数据结构,可以直接应用该函数实现相关功能。
迭代器: 提供了访问容器中对象的方法。
算法: 用来操作容器中的模板函数。包括了常用的 快排(sort)、查找(find)、插入(inser)、末尾添加(push_back)、末尾删除(pop_back)等。
命名空间:其使用相同的命名空间 using namespace std;

2. vector

0、头文件:#include <vector>
1、定义:向量。也可以理解成 “变长数组”,即长度依据需要而自行发生更改的数组,可以有效的解决数组溢出问题。
2、变量声明:vector<typedef> name;
     (1)、说明:其中 typedef 可以是任何基本的数据类型,例如int、double、char 等;也可以是结构体类型,例如 vector<stuInfo> v (其中 stuInfo 是结构体变量);也可以是 vector 容器本身,例如:vector<vector<int> > 注:在符号 > > 之间要添加空格,否则会将其视为移位操作,造成编译错误。
     (2)、几种声明方式的区别:

vector<int> v;			// 声明了一个 int 类型的 vector 容器
vector<int> v(n);		// 声明了一个 int 类型、初始长度为 n 的 vector 容器,可以直接进行下标访问
vector<int> v(n, t);	// 声明了一个 int 类型、初始长度为 n ,数值为 t 的 vector 容器,可以直接进行下标访问
vector<int> v[n];		// 声明了一个 二维 、且其中一组长度已经固定的 int 类型 vector 容器 
vector<vector<int> > v;	// 声明了一个 二维、两组长度均可以进行更改的 int 类型 vector 容器  

3、元素的访问:一般有两种方式进行访问,通过下标进行访问、或通过迭代器进行访问。
     (1)、通过下标访问。和访问普通数组的方式一致,直接访问 v[index] 即可,当然,该访问方式不能超过元素的范围。

#include <iostream>
#include <vector>

using namespace std;

int main()
{
	vector<int> v(10, -1);		 
	
	for(int i=0;i<10;i++) {
		printf("%d ",v[i]);
	}
	
	return 0;
}

     (2)、通过迭代器的方式进行访问。迭代器(iterator) 可以理解为一种类似于指针的东西,其定义为:

vector<int>::iterator it = v.begin();				// 自己定义
auto it = v.begin();								// 或者通过编译器让其自动识别类型

    迭代器访问的方式,分为正向迭代器输出、反向迭代器输出。容器范围的表示方式为 [v.begin, v.end) 以左闭右开的方式进行范围限制。例如:

#include <iostream>
#include <vector>

using namespace std;

int main()
{
	vector<int> v;		 
	
	// 进行向尾部插值操作 
	for(int i=0;i<10;i++)
		v.push_back(i); 
	
	printf("\n正向迭代器输出:");
	for(auto it=v.begin();it!=v.end();it++) 
		printf("%d ",*it);
	
	printf("\n反向迭代器输出:");
	for(auto rit=v.rbegin();rit!=v.rend();rit++) 
		printf("%d ",*rit);
	
	return 0;
}

4、刷题中常用函数:
    (1)、push_back(x) - 向尾部添加一个元素 x
    (2)、empty() - 判断容器是否为空。
    (3)、size() - 获取容器的大小。(可以理解为容器中元素的个数)
    (4)、clear() - 清空容器中的所有元素。
    (5)、pop_back() - 删除尾部元素。

#include <iostream>
#include <vector>

using namespace std;

int main()
{
	vector<int> v;		 		
	
	// 进行向尾部插值操作 
	for(int i=0;i<10;i++)
		v.push_back(i); 
	
	// 获取容器的长度 
	int len = v.size();
		 
	printf("通过下标正序输出:");
	for(int i=0;i<len;i++) 
		printf("%d ",v[i]); 	
	
	// 判断容器是否为空 
	if( v.empty() )  		printf("\n当前容器为空!");
	else 					printf("\n当前容器不为空!");
		
	// 进行向尾部删除操作 
	for(int i=0;i<5;i++)
		v.pop_back(); 
	
	printf("\n反向迭代器输出:");
	for(auto rit=v.rbegin();rit!=v.rend();rit++) 
		printf("%d ",*rit);
		
	// 清空容器中的值 
	v.clear(); 

	if( v.empty() )  		printf("\n当前容器为空!");
	else 					printf("\n当前容器不为空!");
	
	return 0;
}

3. map

0、头文件:#include <map> / #include <unordered_map>
1、定义:映射。一种关联容器,可以实现 Key - Value 的键值匹配。
    (1)、数组,就是一种映射,由 int 到 基本数据类型 int、char、double... 的映射,例如:int arr[4] = {1, 2, 3, 4}; 其就是由 int 类型到 int 类型的映射。下标始终对应着 int 类型,其中0、1、2、3... 下标值,就对应着映射中的 Key,而数组中存储的值 1, 2, 3, 4,就对应着映射中的 Value。而数组中的 Key 必须是 int 类型,而当 Key 是字符串等非整数类型的时候,其数组就不在适用。例如当存储学生成绩的时候,其键值对应为 name - score,其中 name 的数据类型在通常情况下应当为 string 数据类型,这时就无法通过直接使用数组实现。因此,提出了 map 这种关联容器,从而实现任意的键值匹配。
    (2)、map 可以将任何基本数据类型(包括 STL 容器)映射到任何基本数据类型(包括 STL 容器),如 stringint 类型的映射。
    (3)、map 的本身是一种有序映射,其内部会实现自动排序的过程,当在进行类型定义的时候,若只需要实现映射即可,不需要按键排序的时候,可以使用 unordered_map 无序映射,其相比于有序映射而言,其查找的速度要更快一些,可节省些时间。
2、变量声明:map<typedef1, typedef2> mp;
     说明:其中 typedef1、typedef2 可以是任何基本的数据类型,例如int、double、char 等;也可以是 STL 容器本身,例如:map<int, vector<int> >; 注:在符号 > > 之间要添加空格,否则会将其视为移位操作,造成编译错误。
3、元素的访问:
    (1)、通过下标访问。和访问普通数组的方式一致,直接使用 mp[index] 的形式即可。注:当访问没有定义的键时,其不会出现报错,而是会自动生成该 Key,并且 Value = 0。例如:

#include <iostream>
#include <map>

using namespace std;
  
int main()
{
	map<char, int> mp;
	
	mp['c'] = 10;
	printf("c 的值为:%d\n",mp['c']); 

	// 在出现值更改的时候,其会进行覆盖 
	mp['c'] = 20;			
	printf("c 的值为:%d\n",mp['c']); 
	
	// 当访问没有定义的键时,其不会出现报错,而是会自动生成该 Key,并且 Value = 0 
	printf("a 的值为:%d\n",mp['a']); 
    
	return 0;
}

运行结果如下所示:

c 的值为:10
c 的值为:20
a 的值为:0

    (2)、通过迭代器的方式进行访问。

#include <iostream>
#include <map>

using namespace std;
  
int main()
{
	map<char, int> mp;
	
	mp['m'] = 20;
	mp['a'] = 30;
    mp['p'] = 10;
    
    // 正向迭代:
    printf("正向迭代输出:\n");
	for(auto it=mp.begin();it!=mp.end();it++)
		printf("Key - %c, Value - %d\n",it->first, it->second);
		
	// 反向迭代:
    printf("反向迭代输出:\n");
	for(auto rit=mp.rbegin();rit!=mp.rend();rit++)
		printf("Key - %c, Value - %d\n",rit->first, rit->second);
		 
	return 0;
}

运行结果如下所示:

正向迭代输出:
Key - a, Value - 30
Key - m, Value - 20
Key - p, Value - 10
反向迭代输出:
Key - p, Value - 10
Key - m, Value - 20
Key - a, Value - 30

说明:从其输出结果之中,可以看出 map 会按 Key 从小到大的顺序进行自动排序。

    (3)、当需要进行 一键多值 Key - Values 映射的时候,可以将 Value 的数据类型由基本数据类型,更改为 vector 容器,较为方便操作。也可以利用结构体的方式,将对应的 Values 结构体化。例如:

#include <iostream>
#include <map>
#include <vector>
#include <string>

using namespace std;
  
typedef struct {
	int id, ser;
}stuInfo; 

int main()
{
	// 一、通过容器的方式进行 一键多值 的映射 
	printf("通过容器的方式:"); 
	map<char, vector<int> > mp;
	
	for(int i=0;i<3;i++)
		mp['a'].push_back(i);
	
	// 方式一:特定值的查找、输出 
	printf("\n\n通过下标方式输出:");	
	for(int i=0;i<mp['a'].size();i++) {
		printf("%d ",mp['a'][i]);
	}	
	
	// 方式二:通过迭代器的方式进行输出	
	printf("\n通过迭代器的方式输出:");	 	 
	for(auto it=mp.begin();it!=mp.end();it++)  
		for(int i=0;i<it->second.size();i++)
			printf("%d ",it->second[i]); 
			
	// 二、通过结构体方式,进行存储
	printf("\n\n通过结构体方式:"); 
	map<string, stuInfo> stu;
	
	stu["李明"] = stuInfo{1001, 98}; 
	stu["汤姆"] = stuInfo{1002, 86};
	
	// 方式一:特定值的查找、输出 
	printf("\n\n通过下标方式输出:");	
	printf("\n李明的学号:%d、成绩:%d",stu["李明"].id, stu["李明"].ser); 
	printf("\n汤姆的学号:%d、成绩:%d",stu["汤姆"].id, stu["汤姆"].ser); 
			
	// 方式二:通过迭代器的方式进行输出	 
	printf("\n\n通过迭代器的方式输出:");	 	  
	for(auto it=stu.begin();it!=stu.end();it++)  
		printf("\n%s的学号:%d、成绩:%d",it->first.c_str(), it->second.id, it->second.ser); 
						 
	return 0;
}

运行结果如下所示:

通过容器的方式:

通过下标方式输出:0 1 2
通过迭代器的方式输出:0 1 2

通过结构体方式:

通过下标方式输出:
李明的学号:1001、成绩:98
汤姆的学号:1002、成绩:86

通过迭代器的方式输出:
李明的学号:1001、成绩:98
汤姆的学号:1002、成绩:86

4、刷题中常用函数:
    (1)、size() - 获取 map 映射的对数。
    (2)、clear() - 清空 map 中的所有元素。
    (3)、find() - 查找 map 中是否存在键为 Key 的映射。

#include <iostream>
#include <map>
#include <vector>
#include <string>

using namespace std;
  
typedef struct {
	int id, ser;
}stuInfo; 

int main()
{
	map<string, stuInfo> stu;
	
	stu["李明"] = stuInfo{1001, 98}; 
	stu["汤姆"] = stuInfo{1002, 86};

	printf("当前已存储学生信息人数:%d\n",stu.size());	
	
	auto it = stu.find("李明");				// 返回映射的迭代器
	if(it != stu.end())  					// 当不为 end 的时候,说明该映射中存在该键 
		printf("%s的学号:%d、成绩:%d\n",it->first.c_str(), it->second.id, it->second.ser); 
	else									// 否则,不存在该键 
		printf("不存在该学生!\n");
		
	stu.clear();
	printf("当前已存储学生信息人数:%d\n",stu.size());	
	
	it = stu.find("李明");					// 返回映射的迭代器
	if(it != stu.end())  					// 当不为 end 的时候,说明该映射中存在该键 
		printf("%s的学号:%d、成绩:%d\n",it->first.c_str(), it->second.id, it->second.ser); 
	else									// 否则,不存在该键 
		printf("不存在该学生!\n");
						 
	return 0;
}

运行结果如下所示:

当前已存储学生信息人数:2
李明的学号:1001、成绩:98
当前已存储学生信息人数:0
不存在该学生!

4. set

0、头文件:#include<set>
1、定义:集合。也是一种关联容器,是一个内部自动有序且不含重复元素的容器。其适用于需要去除重复元素的情况。
2、变量声明:set<typedef> name;
    说明:其中 typedef 的类型和绝大部分容器一致,其可以是任何基本数据类型,也可以是 STL 容器,而一般为 int 基本数据类型,用于整形数据结果值的去重操作。
3、元素的访问:
    (1)、在 set 容器中, 只能使用迭代器的方式进行访问。其迭代器的访问方式,和上述情况一致。

#include <iostream>
#include <set>

using namespace std;

int main()
{
	set<int> st;
	for(int i=0;i<5;i++) {
		// 向容器中插入值 
		st.insert(1);					
	}
	
	printf("容器大小为:%d\n",st.size());
	printf("迭代输出:");
	for(auto it=st.begin();it!=st.end();it++) 
		printf("%d ",*it);
		
	for(int i=0;i<5;i++) {
		// 向容器中插入值 
		st.insert(i);					
	}
	
	printf("\n容器大小为:%d\n",st.size());
	printf("迭代输出:");
	for(auto it=st.begin();it!=st.end();it++) 
		printf("%d ",*it);
	
	return 0;
}

运行结果:

容器大小为:1
迭代输出:1
容器大小为:5
迭代输出:0 1 2 3 4

4、刷题中常用函数:
       (1)、insert(x) - 将 x 插入到 set 容器中,并自动递增排序和去重。
       (2)、find() - 查找对应值。

#include <iostream>
#include <set>

using namespace std;

int main()
{
	set<int> st;
	for(int i=0;i<5;i++) {
		// 向容器中插入值 
		st.insert(i);					
	}
	
	auto it=st.find(6);							// 返回值类型:迭代器 
	if( it!=st.end() )
		printf("该容器中存在该值!\n");
	else
		printf("该容器中不存在该值!\n");
	
	return 0;
}

运行结果:

该容器中不存在该值!
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值