蓝桥杯备赛笔记(一)

发布于:2024-12-06 ⋅ 阅读:(131) ⋅ 点赞:(0)

这里的笔记是关于蓝桥杯关键知识点的记录,有别于基础语法,很多内容只要求会用就行,无需深入掌握。


前言

持续更新,千里之行始于足下


一、编程基础

1.1 C++基础格式和版本选择

这里只需要记住使用一个万能头文件即可:

#include <bits/stdc++.h> //什么都能用这个头文件
using namespace std;

基本数据类型:

int x = 3; //整数x
double d = 3.14; //浮点数(小数)
char ch = 'A'; //字符常量'A'
char s[] = "Hello"; //字符串
bool b = true; //布尔值,即真假值b。非0为真,0为假

1.2 输入输出

cin和cout
#include <bits/stdc++.h> //万能头文件
using namespace std; //全局引用std,std里面包含了cin,cout和endl等等东西
int main(){
	double a,b;
	cin >> a >> b;//cin会自动判断变量类型
	cout << fixed << setprecision(3) <<a << '' << b << '\n';
	//fixed << setprecision(3)的意思是保留浮点数后面3位
	return 0;//记住最后return 0
}

fixed << setprecision(3) 意思是保留浮点数后3位

在字符或字符串中直接使用cin:

#include <bits/stdc++.h>
using namespace std;
int main(){
	char ch;
	cin >> ch;
	cout << ch;
	return 0;
}

以上代码中: 输入:a b 输出:a

#include <bits/stdc++.h>
using namespace std;
int main(){
	char s[10];
	cin >> s;
	cout << s;
	return 0;
}

以上代码中: 输入:hi nihao 输出:hi
注意!!cin无论是在字符或字符串中输入空格或者换行符就会结束

#include <bits/stdc++.h>
using namespace std;
int main(){
	string s;
	getline(cin, s);
	cout << s;
	return 0;
}

以上代码中: 输入:hi nihao 输出:hi nihao
所以我们可以结合使用string和getline来消除掉这个cin的缺点

取消同步流:
由于cin和cout自动判断变量的关系,它们的读写效率要比scanf和printf更低。
当数据量大的时候,可能导致程序运行超时,我们可以通过取消同步流来加速cin和cout,加速后效率就差不多了。

ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); //取消同步流

1.3 string

使用string需要在头文件包含该库 #include<string>

字符串简介
  1. 字符串管理:string封装了字符串的存储和管理。它自动处理字符串的内存分配和释放,避免了手动管理内存的麻烦。
  2. 动态大小调整:string可以根据需要自动调整字符串的大小,在添加或删除字符时,string会自动调整内部的存储容量,确保足够的空间来容纳字符串。
  3. 安全性:它提供了越界访问检查,以避免访问超出字符串范围的字符。
  4. 迭代器支持:string支持迭代器,可以使用迭代器遍历字符串中的字符,进行字符级别的操作。
  5. 兼容性:string是C++标准库的一部分,因此广泛使用。

string的声明和初始化:

#include <bits/stdc++.h>
#include <string>
int main(){
	//声明并初始化一个字符串
	std::string str1;
	
	//使用字符串字面量初始化字符串
	std::string str2 = "hello, world!";

	//使用另一个std::string 对象来初始化字符串
	std::string str3 = str2;

	//使用部分字符串初始化字符串
	std::string str4 = str2.substr(0, 5);//substr(起始位置,长度)
	
	//使用字符数组初始化字符串
	const char* charArray = "Hello";
	std::string str5(charArray);

	//使用重复的字符初始化字符串
	std::string str6(5, 'A');//"AAAAA"重复5次A
}

在C++中,std::string类提供了一个成员函数c_str(),用于返回一个指向以空字符结尾的C风格字符串(即const char*类型)

字符串的基本操作

1、获取字符串长度:

std::string str = "Hello, world!";
int length = str.length(); //或者 int length = str.size();
std::cout << "Length: " << length << std::endl;

2、拼接字符串(+或append):

std::string str1 = "Hello";
std::string str2 = "world";
std::string result1 = str1 + "," + str2;//使用+运算符
std::string result2 = str1.append(",").append(str2);//使用append函数
std::cout << "Result1 = " << result1 << std::endl;
std::cout << "Result2 = " << result2 << std::endl;

3、字符串查找(find):

std::string str = "Hello, world";
size_t pos = str.find("world"); //查找子字符串位置
if(pos != std::string::npos){ //判断是否不等于-1
	std::cout << "Substring found at position: " << pos << std::endl;
}
else{
	std::cout << "Substring not found." << std::endl;
}

4、字符串替换(replace):

std::string str = "Hello, world";
str.replace(7,5, "Universe"); //替换子字符串
//7是子串起始位置,5是要替换掉的长度
std::cout << "Result: " << str << std::endl;

5、提取子字符串(substr):

std::string str = "Hello, world";
std::string subStr = str.substr(7,5); //提取子字符串
std::cout << "Substring: " << subStr << std::endl;

6、字符串比较(compare):

std::string str1 = "Hello";
std::string str2 = "World";
int result = str1.compare(str2);//比较字符串
if(result == 0){
	std::cout << "String are equal." << std::endl;
} else if(result < 0){
	std::cout << "String 1 is less than String 2." << std::endl;
} else{
	std::cout << "String 1 is greater than String 2." << std::endl;
}

string重载了不等号,所以也可以直接使用s1 < s2的方式来比较string的大小,比较的规则是按照字典序大小进行比较。

字典序排序

字典序的比较方法是从小到大一个一个比较,一旦遇到不相等的字符就确定大小关系。

例如:
aaaa < bbbb
azz < baaa

常用的遍历string方法一共有两种:

  1. 循环枚举下标
  2. auto枚举(其中&表示取引用类型,如果对i修改将会改变原来的值)
string s = "Hello";

for(int i = 0; i < s.length(); ++i) cout << s[i];//枚举循环遍历一遍string的对象s
cout << '\n';
for(auto i : s)
{
	cout << i;
	i = 'a';//此处的修改无效,因为这个i是拷贝出来的,而不是引用s的
	//所以这里只是赋值到拷贝出来的i里面,而这个i是在局部变量内,这个for循环结束就消亡了
}
cout << '\n';
//此时s = "Hello"
for(auto &i : s)
{
	cout << i;//此时再遍历输出s字符串还是Hello
	i = 'a';//此处修改会改变s的字符值
}
cout << '\n';
//此时s= "aaaaa"
cout << s << '\n';

二、竞赛常用库函数

2.1 排序

sort函数

sort函数包含在头文件<algorithm>中
在使用前需要使用#include <algorithm>或万能头文件#include <bits/stdc++.h>
sort是C++标准库中的一个函数模板,用于对指定范围内的元素进行排序。
sort算法使用的是快速排序或者类似快速排序的改进算法,具有较好的平均时间复杂度,一般为O(nlogn)。
sort的用法:
sort(起始地址, 结束地址的下一位, *比较函数);
比较函数一般默认用的小于号(<)

#include <bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int a[1000];
int n;
//读取数组大小
cin >> n;
//读取元素
for(int i = 1; i <= n; ++i) cin >> a[i];

//对数组进行排序
sort(a+1, a+n+1); //[1, n+1) 左闭右开
//   a[1], a[n+1]

//输出
for(int i = 1; i <= n; ++i) cout << a[i] << ' ';
return 0;
}

sort(起始地址, 结束地址的下一位, *比较函数);

#include<bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
//初始化v
//这里是模板类vector,需要使用万能头文件或#include <vector>
vector<int> v = {5, 1, 3, 9, 11};

//对数组进行排序
sort(v.begin(), v.end());

//输出
for(int i = 0; i < v.size(); ++i) cout << v[i] << ' ';
//for (auto i : v)cout << i << ' ';//使用auto进行排序也可以
return 0;
}

由于sort默认用小于号进行排序,如果想要自定义比较规则,可以传入第三个参数,这个参数可以是函数或者lambda表达式。

使用传入第三个参数自定义比较函数
#include <bits/stdc++.h>
using namespace std;
bool cmp(const int &u, const int &v)
{
	return u > v;
}
int main(){
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);

	//初始化v
	vector<int> v = {5, 1, 3, 9, 11};

	//对数组进行排序,降序排序
	sort(v.begin(), v.end(), cmp);
	//						传入函数名
	
	//输出
	for(int i = 0; i<v.size(); ++i) cout << v[i] << ' ';
	return 0;
}
使用lambda自定义比较函数
#include <bits/stdc++.h>
using namespace std;
int main(){
	//初始化v
	vector<int> v = {5, 1, 3, 9, 11};

	//对数组进行排序,降序排序,这里使用lambda表达式
	sort(v.begin(), v.end(), [](const int &u, const int &v)
	{
		return u > v;
	});
	for(int i = 0; i<v.size(); ++i) cout << v[i] << ' ';
	return 0;
}

在[ ]里面不写东西代表把数组内的东西以拷贝的形式放进去,如果在[ ]内加上&后( [&] )就会变成把v里面的变量都以引用(&)类型的格式放进去。

下面是一个本人觉得很妙的操作:

for(int i = 1; i <= n; ++i) cout << a[i] << " \n"[i == n];

首先,这里我们需要意识到字符串其实就是一个字符数组。在这段代码行中的" \n"[i == n]巧妙的利用了判断符号来确认for循环是否到结尾了,如果到结尾了此时判断会返回1(真),就会自动输出\n换行。如果没到结尾,即i不等于n,此时返回的是0(假),则输出空格。
在这个字符串中下标为0对应的是" “(空格),下标为1对应的是”\n"(回车换行符)

以下是使用了这个操作的题目:
在这里插入图片描述

2.2 最值查找

min和max函数

min(3, 5) = 3
min({1, 2, 3, 4}) = 1
max(a, b)返回a和b中较大的那个值,只能传入两个值,或传入一个列表。
例如:
max(7, 5) = 7
max({1, 2, 3, 4}) = 4
时间复杂度为O(1),传入参数为数组时时间复杂度为O(n),n为数组大小。
min和max函数是在最值操作时最常用的操作。

min_element和max_element

min_element(st, ed)返回地址[st, ed)中最小的那个值的下标(迭代器),传入参数为两个地址或迭代器。
max_element(st, ed)返回地址[st, ed)中最大的那个值的下标(迭代器),传入参数为两个地址或迭代器。

时间复杂度均为O(n),n为数组大小(由传入的参数决定)

//初始化v
vector<int> v = {5, 1, 3, 9, 11};

//输出最大的元素,*表示解引用,即通过地址(迭代器)得到值
cout << *max_element(v.begin(), v.end()) << '\n';
nth_element函数

nth_element(st, k, ed)
进行部分排序,返回值为void()
传入参数为三个地址或迭代器。其中第二个参数位置的元素将处于正确位置,其他位置元素的位置可能是任意的,但前面的都比它小,后面的后比它大。时间复杂度O(n)。

//初始化v
vector<int> v = {5, 1, 7, 3, 10, 18, 9};

//输出最大的元素,*表示解引用,即通过地址(迭代器)得到值
nth_element(v.begin(), v.begin() + 3, v.end());
//这里v[3]的位置将会位于排序后的位置,其他的任意
for(auto &i : v) cout << i << ' ';

课后题目:
在这里插入图片描述

2.3 二分查找

二分法是一种高效的查找方法,它通过将问题的搜索范围一分为二(两边有明显的区别),迭代地缩小搜索范围,直到找到目标或确定目标不存在。
二分法适用于有序数据集合,并且每次迭代可以将搜索范围缩小一半。
二分法本质也是枚举,但和暴力枚举不同,二分法利用数据结构的单调性减少了很多不必要的枚举,从而极大的提高了效率,一般可以将O(n)的枚举优化到O(logn)。
常见的二分类型有:

  1. 整数二分
  2. 浮点二分
  3. 二分答案(最常见)
整数二分查找模板
//找到升序数组a中的x第一次出现的位置
int l = 0, r = 1e9;
//注意这里的判断条件,这样可以保证l,r最终一定收敛到分界点
while(l + 1 != r)//l,r相邻的话退出
{
	int mid = (l + r) / 2;

	//如果a为升序,说明mid偏大了,需要减小mid,就只能将r变小,即r = mid
	if(a[mid] >= x) r = mid;
	else l = mid;//否则l = mid,始终保持在所属区域
}
cout << r << '\n';
浮点二分查找模板
//计算单调函数f(x)的零点
double l = 0, r = 1e9, eps = 1e-6;
//注意这里的判断条件,这样可以保证l,r最终一定收敛到分界点
while(r - l >= eps)//eps是一个极小量,设置为1e-6比较适合
{
	double mid = (l + r) / 2;

	//f(x)单调递增,f(mid) >= 0,说明mid偏大了,需要减小mid,就只能将r变小,即r = mid
	if(f(mid) >= 0) r = mid;
	else l = mid;
}
//最后返回l,r差别不大
cout << r << '\n';
二分答案模板
bool check(int mid)
{
	bool res = true;
	//其他内容
	return res;
}
int main()
{
	int l = 0, r = 1e9;
	while(l + 1 != r)
	{
		int mid = (l + r) / 2;
		//具体写法需要根据题意修改
		if(check[mid] >= x) l = mid;
		else r = mid;
}
cout << l << '\n';//具体输出的内容需要根据题意判断
跳石头题目

在这里插入图片描述
代码如下:

#include <bits/stdc++.h>
using namespace std;
const int N = 5e4 + 9;
int a[N];
int L,n,m;
int check(int mid){
  int res = 0,lst = 0;
  for(int i = 1; i <= n; ++i)
  {
    //将i移除
    if(a[i] - a[lst] < mid) res++;
    else lst = i;
  }
  //将lst移除
  if(L - a[lst] < mid) res++;//用起点到终点的总距离减去此时经过for循环后的lst下标的距离
  return res;
}
int main()
{
  ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);  
  cin >> L >> n >> m;
  for(int i = 1; i <= n; i++) cin >> a[i];
  int l = 0,r = 1e9 + 5;
  while(l + 1 != r)
  {
    int mid = (l + r) >> 1;// >> 1等价于/2。使用这个的原因是因为位运算比除法运算更快,且可以避免溢出
    if(check(mid) <= m) l = mid;
    else r = mid;
  }
  cout << l << '\n';
  return 0;
}

解题思路:

这里我们要先假设最短跳跃距离的最大值是从0~L,给出变量mid来做二分答案查找最短跳跃距离。
把if里面的值传到函数check里获取搬走石头的数量是否小于用户输入。如果里面的判断正确就把mid赋值给l,否则把mid赋值给r。
check内算出搬走了多少块石头,遍历从第一块石头到终点的第N块岩石。然后用第一块石头下标对应的距离减去lst[0]即初始石头的距离得出的距离做判断,看是否小于二分查找的mid。如果小于则res+1(即搬走一块石头)。否则就把此时遍历到的i的值赋值给lst,然后继续减。用起点到终点的总距离减去此时lst下标的距离如果小于二分查找的mid则计数器+1。直到最后一块石头为止,最后返回一共拿走多少块石头。

2.4 大小写转换

islower/isupper函数

islower和isupper函数返回类型为bool类型,函数需要包含头文件<cctype>
用于检查一个字符是否为小写字母或大写字母。

tolower/toupper函数

tolower(char ch)可以将ch转换为小写字母,如果ch不是大写字母则不进行操作。
toupper()同理。

ascii码

了解了ascii码后,我们可以通过直接对英文字母进行加减运算计算出其大小写的字符。
在ascii码表中,大写字母的编码范围是65(‘A’)到90(‘Z’),而小写字母的编码范围是97(‘a’)到122(‘z’)。根据这个规则,可以使用ASCII码表进行大小写转换。

2.5 全排列

next_permutation()函数

next_permutation函数用于生成当前序列的下一个排列。它按照字典序对序列进行重新排序,如果存在下一个排列,则将当前序列更改为下一个排列,并返回true;如果当前序列已经是最后一个排列,则将序列更改为第一个排列,并返回false。

prev_permutation()函数

prev_permutation函数与next_permutation函数相反,用于生成当前序列的上一个排列。它按照字典序对序列进行重新排序,如果存在上一个排列,则将当前序列更改为上一个排列,并返回true;如果当前序列已经是第一个排列,则将序列更改为最后一个排列,并返回false。

代码示例:

#include <bits/stdc++.h>
using namespace std;
int a[10];

int main(){
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	for(int i = 1;i <= 4; ++i)a[i] = i;
	
	bool tag = true;

	while(tag){
		for(int i = 1; i <= 4; ++ i)cout << a[i] << ' ';
		cout << '\n';
		tag = next_permutation(a + 1, a + 1 + 4);
	}
}

2.6 其他库函数

memset()

memset()是一个用于设置内存块值的函数。它的原型定义在<cstring>头文件中,函数的声明如下:

void* memset(void* ptr, int value, size_t num);
//				  指针		值			重置的大小

memset()函数接受三个函数:

  1. ptr:指向要设置值的内存块的指针。
  2. value:要设置的值,通常是一个整数。(这里要注意的是value只能设置8个bit位,即1byte)
  3. num:要设置的字节数。

memset()函数将ptr指向的内存块的前num个字节设置为value的值。它返回一个指向ptr的指针。
memset()函数通常用于初始化内存块,将其设置为特定的值。
例如,如果要将一个整型数组的所有元素设置为0,可以使用memset()函数如下:

int arr[10];
memset(arr, 0, sizeof(arr));

在上述示例中:memset(arr, 0, sizeof(arr))将数组arr的所有元素设置为0.
需要注意的是,memset()函数对于非字符类型的数组可能会产生未定义行为。
比如以下代码:

#include <btis/stdc++.h>
using namespace std;

int main(){
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int a[5];
	memset(a, 1, sizeof a);
	for(int i = 0; i < 5; ++ i) cout << a[i] << '\n';
	return 0;
}

这里输出结果就会变成一个很大的数:
在这里插入图片描述
我们先把cout那行代码做一下修改:

for(int i = 0; i < 5; ++ i) cout << biteset<32>(a[i]) << '\n';

转换成32位后我们会发现,其实是把每个字节变成了1,加起来就成了很大的数:
在这里插入图片描述

swap()

swap(T &a, T&b)函数接受两个参数:

  1. a:要交换值的第一个变量的引用。
  2. b:要交换值的第二个变量的引用。

swap()函数通过将第一个变量的值存储到临时变量中,然后将第二个变量的值赋给第一个变量,最后将临时变量的值赋给第二个变量,实现两个变量值的交换。
== swap()函数可以用于交换任意类型的变量,包括基本类型(如整数、浮点数等)和自定义类型(如结构体、类对象等)。==
以下是一个示例,展示如何使用swap()函数交换两个整数的值:

int a = 10;
int b = 20;
std::swap(a, b);
reverse()

reverse()是一个用于反转容器中元素顺序的函数。它的原型定义在<algorithm>头文件中,函数的声明如下:

template<class BidirIt>
void reverse(BidirIt first, BidirIt last);

reverse()函数接受两个参数:

  1. first:指向容器中要反转的第一个元素的迭代器。
  2. last:指向容器中要反转的最后一个元素的下一个位置的迭代器。

reverse()函数将[fist,last)范围内的元素顺序进行反转。
也就是说,它会将[fist,last)范围内的元素按相反的顺序重新排列。
reverse()函数可用于反转各种类型的容器,包括数组、向量、链表等。
以下是一个示例,展示如何使用reverse()函数反转一个整型向量的元素顺序:

#include <bits/stdc++.h>
using namespace std;

int main(){
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	std::vertor<int> vec = {1, 2, 3, 4, 5};
	std::reverse(vec.begin(), vec.end());

	for(int num : vec){
		std::cout << num << " ";
	}
	std::cout << std::endl;
	return 0;
}

在上述示例中,std::reverse(vec.begin()) , vec.end())将整型向量vec中的元素顺序进行反转。最终输出的结果是 5 4 3 2 1。
需要注意的是,reverse()函数只能支持双向迭代器的容器,因为它需要能够向前和向后遍历容器中的元素。对于只支持单向迭代器的容器(如前向链表),无法使用reverse()函数进行反转。

unique()

unique()是一个用于去除容器中相邻重复元素的函数。
它的原型定义在<algorithm>头文件中,函数的声明如下

template<class ForwardIt>
ForwardIt unique(ForwardIt first, ForwardIt last);

unique(first, last)函数接受两个参数:
1、first:指向容器中要去重的第一个元素的迭代器。
2、last:指向容器中要去重的最后一个元素的下一个位置的迭代器。
unique()函数将[first, last)范围内的相邻重复元素去除,并返回一个指向去重后范围的尾后迭代器。去重后的范围中只保留了第一个出现的元素,后续重复的元素都被移除。
unique()函数可用于去除各种类型的容器中的相邻重复元素,包括数组、向量、链表等。
以下是一个示例,展示如何使用unique()函数去除一个整型向量中的相邻重复元素

int main(){
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	std::vector<int> vec = {1, 1, 2, 2, 3, 3, 3, 4, 4, 5};
	auto it = std::unique(vec.begin(), vec.end());
	vec.erase(it, vec.end());//这行代码的意思是删除掉去重多余的元素

	for(int num : vec){
		std::cout << num << " ";
	}
	std::cout << std::endl;
	return 0;
}

使用unique去重的数据如果没有使用vec.erase是不会删掉的,下图解释了unique函数去重后数据放的位置。
在这里插入图片描述
在上述示例中,std::unique(vec.begin(), vec.end())将整型向量vec中的相邻重复元素去除。最终输出的结果是1 2 3 4 5。
需要注意的是,unique()函数只能去除相邻的重复元素,如果容器中存在非相邻的重复元素,则无法去除。
如果需要去除所有重复元素,而不仅仅是相邻的重复元素,可以先对容器进行排序,然后再使用unique()函数。
unique()时间复杂度为O(n)。
以下代码就说明以上几点:

#include<bits/stdc++.h>
using namespace std;

int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int a[] = {3, 1, 2, 2, 3};
	int n = unique(a, a + 5) - a;
	for (int i = 0; i < n; ++i)cout << a[i] << ' ';
	return 0;
}

下面的输出结果:
在这里插入图片描述
这里只需要使用我们之前学过的sort()函数给数组按顺序排序后再进行unique()就没问题了:

sort(a, a + 5);

结果如下:
在这里插入图片描述

三、STL

3.1 pair

pair的定义和结构

在C++中,pair是一个模板类,用于表示一对值的组合,它位于<utility>头文件中。
pair类的定义如下:

template<class T1, class T2>
struct pair{
	T1 first; //第一个值
	T2 second; //第二个值

	//构造函数
	pair();
	pair(const T1& x, const T2& y);

	//比较运算符重载
	bool operator==(const pair& rhs) const;
	bool operator!=(const pair& rhs) const;

	//其他成员函数和特性
	//...
}

pair类模板有两个模板参数,T1和T2,分别表示第一个值和第二个值的类型。

pair类有两个成员变量,first和second,分别表示第一个值和第二个值。

pair类还有一些成员函数和特性,例如默认构造函数、带参数的构造函数、比较运算符重载等。

使用pair类,可以方便地将两个值组合在一起,并进行传递、存储和操作。

例如,可以将两个整数组合在一起作为函数的返回值,或者将一对值存储在容器中。
下面是一些使用pair的示例:

#include <bits/stdc++.h>
using namespace std;

int main(){
	std::pair<int, double> p1(1, 3.14);
	std::pair<char, std::string> p2('a', "hello");

	std::cout << p1.frist << "," << p1.second << std::endl;
	std::cout << p2.frist << "," << p2.second << std::endl;
	return 0;
}

以上代码创建了两个pair对象,分别包含不同类型的值。然后,通过访问first和second成员变量,输出了这些值。

pair的嵌套

pair可以进行嵌套,也就是说可以将一个pair对象作为另一个pair对象的成员。通过嵌套pair,可以方便地组合多个值,并形成更复杂的数据结构。

下面是一个示例代码,演示了如何嵌套使用pair:

#include <bits/stdc++.h>
using namespace std;

int main(){
	std::pair<int, int> p1(1, 2);
	std::pair<int, std::pair<int, int>> p2(3, std::make_pair(4, 5));
	std::pair<std::pair<int, int>, std::pair<int, int>> p3(std::make_pair(6, 7), std::make_mair(3, 4));

	std::cout << p1.first << "," << p1.second << std::endl;
	std::cout << p2.first << "," << p2.second.frist << "," << p2.second.second << std::endl;
	std::cout << p3.first.frist << "," << p3.first.second << "," << p3.second.first <<  "," << std::endl;
	return 0;

在这个示例中,我们创建了三个pair对象,p1、p2和p3.

  • p1是一个简单的pair,包含两个整数。
  • p2是一个嵌套的pair,其中一个值是一个整数,第二个值是一个pair,其中包含两个整数值。
  • p3是一个嵌套的pair,其中每个值都是一个pair,每个pair包含两个整数值。
    通过访问嵌套的pair对象的成员变量,我们可以获取到相应的值。
pair自带排序规则

pair自带的排序规则是按照frist成员进行升序排序的。
如果first成员相等,则按照second成员进行升序排序。

这意味着当你使用标准库中的排序算法(如std::sort)对包含pair对象的容器进行排序时,会根据pair对象的first成员进行排序。
下面是示例代码,演示了如果使用pair进行排序:

#include <bits/stdc++.h>
using namespace std;

int main(){
	std::vector<std::pair<int, int>> vec;
	vec.push_back(std::make_pair(3, 2));
	vec.push_back(std::make_pair(1, 4));
	vec.push_back(std::make_pair(2, 1));

	std::sort(vec.begin(), vec.end());

	for(const auto& p : vec){
		std::cout << p.first << ", " << p.second << std::endl;
	}
	return 0;
}

结果如下:
在这里插入图片描述在这个示例中,我们创建了一个存储pair对象的向量vec,其中包含三个pair对象。
然后,我们使用std::sort函数对vec进行排序。由于pair对象的排序规则是按照first成员进行升序排序,所以得出了以上结果。
最后,我们通过遍历vec并输出每个pair对象的成员,验证了排序结果。
需要注意的是,如果你想按照其他排序规则对pair进行排序,可以自定义比较函数或使用lamabda表达式来传递给排序算法。这样,你可以根据自己的需求定义排序规则。


总结