算法竞赛中C++常用的stl库函数
引言
我们都知道,C++中有许多内置的库函数,我们可以直接调用它们,在蓝桥杯,ACM等比赛中,通过使用这些常用的库函数可以大大提高我们的效率,而不用自己去再重新去手写一些函数,那么本篇文章就为大家盘点了一些比较常用的库函数,并附带了例题帮助大家运用理解。
swap()
也就是我们熟悉的交换函数,将传进去的两个值进行交换
swap(a,b);
reverse()
reverse是一个用于反转容器中元素顺序的函数,reverse(start,end)
传入范围内地址或迭代器
vector<int> numbers = { 1,2,3,4,5 };
reverse(numbers.begin(),numbers.end());
for (int i = 0; i < numbers.size(); i++) {
cout << numbers[i] << " ";
}
经过反转后,输出结果就变为了 5 4 3 2 1
unique()
unique用于去除相邻两个重复两个元素 ,返回的是但并不是真正意义上的删除,可以理解为挪到了后边,所以就需要配合erase去删除
vector<int> v = { 1,1,2,3,3,4,5,6 };
auto it = unique(v.begin(), v.end());
v.erase(it, v.end());
for (int i = 0; i < v.size(); i++) {
cout << v[i] << " ";
}
返回的就是箭头处的迭代器
还记得我们之前提到的相邻重复元素吗,那如果是不相邻呢,不相邻就不去重了呗
如图所示,因为最后一个3不是相邻重复元素,就没有被去重,想去重的话,就需要搭配sort()来进行操作了
sort()
首先要讲的就是sort函数,这个函数的功能可谓是真的很香,是一个快速排序的时间复杂度,所以非常的快
使用方法:sort(要排序元素的起始地址,要排序元素的结束地址,比较函数),这个比较函数也可以不写,默认为从小到大的顺序
默认的话是从小到大来写的,可以自己定义比较函数来改变排序方式。
下面用代码解释一下
#include <bits/stdc++.h>
using namespace std;
bool cmp(int x, int y) {
return x > y;
}
int main(){
vector<int> v = { 3,6,1,5,8 };
sort(v.begin(), v.end()); //默认升序
for (int i = 0; i < v.size(); i++) {
cout << v[i] << " ";
}//运行结果 : 1 3 5 6 8
cout << "\n";
sort(v.begin(), v.end(), cmp); //降序
for (int i = 0; i < v.size(); i++) {
cout << v[i] << " ";
}//运行结果 : 8 6 5 3 1
cout << "\n";
return 0;
}
如果是数组的话就是:
int arr[5] = { 5,1,2,4,3 };
sort(arr, arr + 5);
int size = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < size; i++) {
cout << arr[i] << " ";
}
binary_search
这是一个二分查找的库函数,用于在已排序的序列(数组,容器等)中查找元素,返回值为 bool 类型
使用时需要传入查找范围以及查找目标
如果需要获取找到的元素的位置,可以使用下面的两个函数
lower_bound()
使用格式:lower_bound(start,end,x),即传入起始地址(或迭代器)及结束地址(或迭代器)以及查找目标。
这个函数有一个使用前提就是,必须是升序的数组,如果要在降序数组中使用就需要自定义函数,和sort()类似,同时,返回值返回的是 lower_bound(start,end,x)第一个大于等于x的元素的地址,这一点需要注意一下。
等会儿我们用一道例题来实现一下
upper_bound()
和上述函数差不多,不过这里返回的是第一个大于x的元素的地址,不同的是,这里没有等于,用图来解释一下就是:
这样就比较直观了
接下来看道例题:
题目是蓝桥杯题库中的,题号是1389
非常的直观,就是查找数组中的某个元素,我们用刚刚的lower_bound()函数直接秒了
#include <bits/stdc++.h>
using namespace std;
int main()
{
int target = 0;
int data[200];
for(int i = 0 ; i < 200 ; i ++)data[i] = 4 * i + 6;
cin >> target;
//因为返回的是地址,所以减去首地址就是数组下标
cout << (lower_bound(data,data + 200,target) - data) << "\n";
return 0;
}
减去首地址那里需要注意一下
min() 和 max()
这两个函数比较简单,就是传入两个数 或列表 ,返回它们的最大和最小的值
cout << min(2, 5) << "\n"; //返回2
cout << max({ 1,2,3,4 }) << "\n";//返回4
min_element() 和 max_element()
这两个函数也是求最大和最小值的,使用规则就是min_element(start,end)
这里传入的是起始地址(或迭代器)和结束地址(或迭代器)返回的也是地址
vector<int> numbers = { 1,3,4,5,6,7,9 };
cout << *min_element(numbers.begin(), numbers.end()) << "\n"; //通过解引用返回1
cout << *max_element(numbers.begin(), numbers.end()) << "\n";//返回9
nth_element()
nth_element(start , k ,end)
这个函数的作用就是进行部分排序,返回值为void,传入的是3个地址或迭代器,排序之后, k 的处于正确的位置,其他元素可能是任意的,也就是不一定有序,但是k前面都是比k小的,后面都是比k大的
vector<int> numbers = { 4,3,1,10,5,6,9,7,2 };
nth_element(numbers.begin(), numbers.begin() + 4, numbers.end());
for (int i = 0; i < numbers.size(); i++) {
cout << numbers[i] << " ";
}
接下来我们再用一道例题来理解一下
依旧是蓝桥杯里的,题号是497
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e4 + 5;
int a[N];
int main() {
//取消同步流
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n = 0;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
//最大
cout << *max_element(a, a + n) << "\n";
//最小
cout << *min_element(a, a + n) << "\n";
ll sum = 0;
for (int i = 0; i < n; i++) {
sum += a[i];
}
//保留两位小数
cout << fixed << setprecision(2) << 1.0 * sum / n;
return 0;
}
memset()
这是一个设置内存块值的函数,包含在< cstring >头文件中
memset(要设置内存块值的指针,要设置的值,要设置的字节数)
#include <bits/stdc++.h>
using namespace std;
int main(){
int a[5];
memset(a,1,sizeof(a));
for(int i = 0;i< 5;i++){
cout<<a[i]<<"\n";
cout<<bitset<32>(a[i])<<"\n";
}
return 0;
}
通过输出结果发现,修改的是二进制存储中的值,所以第一行并不是我们想象中输出的1
islower()和isupper()
这两个函数就是检查判断一个字符是否为小写字母和大写字母,返回值也就是bool类型,lower为小写,upper为大写
char ch = 'A';
if (islower(ch)) cout << "是小写字母" << "\n";
else cout << "是大写字母" << "\n";
if(isupper(ch)) cout << "是大写字母" << "\n";
else cout << "是小写字母" << "\n";
有了这两个函数,我们就不用去根据ASCII码减来减去了
tolower()和toupper()
toupper和tolower就是将一个小写字母或一个大写字母转化为对应的大写字母或小写字母,返回值是一个字符类型,可以定义一个字符变量来接收
char ch = 'A';
char c = tolower(ch);
cout << c << "\n";
toupper也是一样的用法
next_permutation()和prev_permutation()
next_permutation()用于生成当前序列的写一个序列,按照字典序对序列重新进行排列,如果存在下一个序列,就将当前序列改为下一个序列,并返回true,如果当前序列就是最后一个序列,就将序列改为第一个序列,并返回false
vector<int> v = { 1,2,3 };
while (next_permutation(v.begin(), v.end())) {
for (int i = 0; i < v.size(); i++) {
cout <<v[i]<< " ";
}
cout << "\n";
}
以上代码就可以生成当前序列往后进行全排列的序列,例如 1 2 3,下一个根据字典序排列的序列就是 1 3 2 接着是 2 1 3,以此类推
prev_permutation()和上面那一个相反,生成的是当前序列的上一个序列,例如 3 2 1 上一个就是 3 1 2
vector<int> v = { 3,2,1 };
while(prev_permutation(v.begin(), v.end())) {
for (int i = 0; i < v.size(); i++) {
cout << v[i] << " ";
}
cout << "\n";
}
那么本次分享就到这里了,有其他的之后再补充。