从C语言到C++/STL(五):STL常用函数

目录

原文章:

所学习文章:

一、accumulate——求和函数:

二、atoi——字符串转int类型の函数:

三、fill和memset——初始化赋值函数:

1.memset所初始化的数组若为int类型,则只能赋值为-1或0,赋其他值时会出现错误:

2.memset的若为char类型,则可以为任意值,但是赋值的数字为ASCII的值:

3.fill:

四、lower_bound 和 upper_bound:

1.先讲lower_bound普通数组的:

2.接着就是vector数组的:

3.可以直接用作数组下标:

五、max_element 和 min_element:

六、max 和 min:

七、reverse:

八、sort:

另外,根据数组结构体里面的某个元素对所有结构体进行排序:

九、nth_element:

十、find查找:

十一、__gcd()求最大公约数:


原文章:

从C语言到C++/STL(五):STL常用函数 - 知乎

此文章为作者本人搬运至该网站。

所学习文章:

C++ STL总结 | 行码棋

在此向原作者表示感谢!!!


本来想先学一下map和set再来开这章的,不过set的内容除了复制粘贴感觉没什么可以讲的,并且还有一点就是:如果不做题的话,再怎么讲怎么复制粘贴都没啥用

所以在这篇文章之后,我也该着手开始刷题了,第一个目标就是蓝桥杯!


一、accumulate——求和函数:

accumulate(beg, end, init)

其中init为求和的初始值,即最终结果为 init的数值+beg的位置的数值直至end的位置的数值的和。

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

int main(){
	vector<int> a{1, 2, 3, 4, 5};
	int b = accumulate(a.begin(), a.end(), 0); 
	cout << b << endl;
	//对于vector的a,从首位置到末位置求和,初始值为0,结果为:15 
	
	int a2[] = {1, 1, 1, 1, 1};
	int b2 = accumulate(a2, a2 + 3, 10);
	cout << b2;
	//对于数组的a2,从首位置到首位置后面三位 的区间求和,初始值为10,结果为 13
	return 0;
}

beg和end理所当然为迭代器。

反正就经验来看,对于使用vector的任意函数,操作里面的元素都要用到begin()和end(),而如果是普通数组就只需要数组名了。


二、atoi——字符串转int类型の函数:

string s = "1234";
int a = atoi(s.c_str());
printf("%d", a);

char s[] = "1234";
int a = atoi(s);
cout << a << "\n";

感觉没什么多说的。


三、fill和memset——初始化赋值函数:

我最开始学习的初始化数组时所用的就是memset,不过如今才发现其有诸多限制,如:

memset()函数的用法详解-优快云博客

1.memset所初始化的数组若为int类型,则只能赋值为-1或0,赋其他值时会出现错误:

int a2[5];
	
memset(a2, 0, sizeof(a2));
for(int i = 0; i < 5; i++)
	cout << a2[i] << " ";
cout << endl;
		
memset(a2, -1, sizeof(a2));
for(int i = 0; i < 5; i++)
	cout << a2[i] << " ";
cout << endl;

memset(a2, 1, sizeof(a2));
for(int i = 0; i < 5; i++)
	cout << a2[i] << " ";
cout << endl;

比如这里,我定义了一个长度为5的普通数组a2,分别用memset赋值为0,-1,1:

在赋值为1的时候会出现乱码,其余赋值,如-2,2也是一样的乱码。

原因似乎挺复杂,咱就不用了解了。

2.memset的若为char类型,则可以为任意值,但是赋值的数字为ASCII的值:

char a2[5];
	
memset(a2, 1, sizeof(a2));
for(int i = 0; i < 5; i++)
	cout << a2[i] << " ";
cout << endl;
	
memset(a2, '1', sizeof(a2));
for(int i = 0; i < 5; i++)
	cout << a2[i] << " ";
cout << endl;

这里第一行看似没有输出,其实输出的是ASCII码值为1的字符,也就是空白字符。

而下面那个,就是把memset中的1换成了'1',其实就是1字符对应的ASCII码值,如果把'1'换成49,那么结果也一样。


而memset不仅有以上两个限制,还有:

C++踩坑——用memset对vector进行初始化 - Peyton_Li - 博客园

memset似乎不支持vector类型的数组。。。。。

所以还是建议不使用memset了。

3.fill:

fill(beg, end, num)

//对a数组的所有元素赋1
int a[5];
fill(a, a + 5, 1);
for(int i = 0; i < 5; i++)
	cout << a[i] << " ";
cout << endl;
//1 1 1 1 1

vector<int> b(5);
fill(b.begin(), b.end(), 5);
for(int i = 0; i < 5; i++)
	cout << b[i] << " ";
cout << endl;
//5 5 5 5 5

fill的使用格式和上面的acculamtate,就不多讲了。


四、lower_bound 和 upper_bound:

关于lower_bound( )和upper_bound( )的常见用法_lowerbound和upperbound-优快云博客

这两个函数的目的是在某一序列中 查找 第一个比一个指定元素大或者小的位置。

而其原理也就是二分查找,故而可以用于需要二分查找的题目。

1.先讲lower_bound普通数组的:

int a[] = {1, 2, 3, 4, 5};
cout << *(lower_bound(a, a + 5, 3)) << endl;

lower_bound是在a数组中查找第一个大于等于3的元素,并返回该元素的地址,

由于返回的是地址,所以我们要输出内容就先要加个星号(*),

上面输出的结果是3,我就不赘述了。

而如果把上面代码换成这个:

int a[] = {1, 2, 3, 4, 5};
cout << *(lower_bound(a, a + 2, 4)) << endl;

lower_bound函数中,a指的是1,a+2指的就是3,在1到3里面找不到4这个元素,那么!

这里有个很让人脑阔疼的原理:

我们先回归lower_bound的一般式:

lower_bound( begin, end, num);

这里要看好:

lower_bound的原理是:

从数组的begin位置到end - 1位置(包括这俩)进行查找第一个大于等于num的元素

也就是说,查找区间的右端其实是end-1(end函数的老毛病。。。),但是函数里面写的还是end,然后,

如果找不到的话,那就返回end

我们结合那个例子来看:(我把代码搬下来了)

int a[] = {1, 2, 3, 4, 5};
cout << *(lower_bound(a, a + 2, 4)) << endl;

这里查找范围是a到a+2,也就是从1到3,查找不到比4大的数,那么就返回end下标。

在这里,end 就等于 a + 2,也就是3,最后输出的结果就是3。

这一点感觉还是挺绕的。。。


2.接着就是vector数组的:

vector<int> b{1, 2, 3, 4, 5};
cout << *(lower_bound(b.begin(), b.end(), 4)) << endl;

其实vector的lower_bound和上面的类似,不过还是一如既往的用到begin和end,

(在这里别忘了end其实指的是数组最后一位  再往后一位的 这一位,也就是为什么上面要有end - 1了)

upper_bound也类似,只要记得lower是找第一个大于等于指定元素的位置,

而upper是找第一个小于等于的。


3.可以直接用作数组下标:

【深基13.例1】查找 - 洛谷

这个题,就是典型的二分查找的题,当然也可以用lower_bound做出来,

lower_bound要找的是第一个小于这个元素的位置,那么也正好规避了这个元素在数组里面重复的情况。

毕竟找到小于这个元素的话,那么往右挪一格不就是第一次出现这个元素了吗?

另外就是,lower_bound输出的是这个数的位置的地址,但是如果我们再直接减去这个数组(相当于减去它的首地址),地址减去地址,最后得出来的不就是这个数在数组中的位置了吗!!!

附上AC代码:

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

int arr[1000005];

int main() {
	int n, m;
	cin >> n >> m;
	for (int i = 0; i < n; i++) {
		cin >> arr[i];
	}
	int qus;	//要找的数字 
	for (int i = 0; i < m; i++) {
		cin >> qus;
		int ans = lower_bound(arr, arr + n, qus) - arr; //这个是最核心之处
		//找出第一个比qus小的数的位置 
		if (arr[ans] != qus) cout << "-1 ";
		else cout << ans + 1 << " ";
	}
	return 0;
}

五、max_element 和 min_element:

在区间内找最大最小值,应该不用多说,看代码就行:

int a[] = {1, 2, 3, 4, 5};
int mx = *max_element(a, a + 3);
cout << mx << endl;
//输出结果:3 
	
vector<int> a2{1, 2, 114514, 4, 5};
int mx2 = *max_element(a2.begin(), a2.end());
cout << mx2;
//输出结果:114514 

六、max 和 min:

找多个元素的最大值最小值:

//找a,b的最大值和最小值
mx = max(a, b);
mn = min(a, b);

//找到a,b,c,d的最大值和最小值
mx = max({a, b, c, d});
mn = min({a, b, c, d});

mx = max({1, 2, 114514, 3});
//结果:114514

pass。


七、reverse:

反转某个数组或字符串,可以用来判断回文串啥的:

reverse(beg,end);

string s = "abcde";
reverse(s.begin(), s.end());//对s进行翻转
cout << s << '\n';//edcba

//对a数组进行翻转
int a[] = {1, 2, 3, 4};
reverse(a, a + 4);
cout << a[0] << a[1] << a[2] << a[3];
//4321

八、sort:

最重量级的一个!

sort简单排序我就不讲了,想看的话可以看一下我前面的文章:

从C语言到C++/STL(二):vector动态数组-优快云博客

在这里讲一下一个新东西:更换排序规则

也就是原先是从小到大排序的,

//对a数组的[0, n-1]位置从大到小排序
sort(a, a + n, greater<int>());
//对a数组的[0, n-1]位置从小到大排序
sort(a, a + n, less<int>());

vector<int> b(n + 1);
sort(b.begin() + 1, b.end()); // 升序
sort(b.begin() + 1, b.end(), greater<int>()); // 降序

在下面这里就实现了从大到小排序。

另外,根据数组结构体里面的某个元素对所有结构体进行排序:

间隔这么长时间,我才发现我还有个sort的问题没解决:

那就是sort不能直接对存放结构体的数组进行排序啊!

原因毕竟很简单,结构体内部有多个元素,如果不指定是哪个元素,那么又如何排序呢?

因此需要如下代码:

struct node {
    elemtype x;
}node[N];

// 1. 使用函数自定义排序,定义比较函数
bool cmp(node a, node b) {
    //按结构体里面的x值降序排列
    return a.x > b.x;
}
sort(node, node + n, cmp); // 只能接受 以函数为形式的自定义排序规则,无法接受以结构体为形式的自定义排序规则

// 2. 或者使用匿名函数自定义排序规则
sort(node, node + n, [](node a, node b) {
    return a.x > b.x;
});

这个我建议用上面哪个,毕竟好记嘛。

在这里面,a.x就成为了结构体中的某个元素。

就通过这个元素对数组中所有的结构体进行排序。


九、nth_element:

STL 之 nth_element详解_nthelement-优快云博客

一句话解释:找出某区间第k(位置)小的数值。

用法:nth_element(a,a+k,a+n),k为所求的位置,n为右边界。

但是要注意的是!函数只是把下标为k的元素放在了正确位置,对其它元素并没有排序,

不过可以确定的是,k左边元素都小于等于它,右边元素都大于等于它,所以可以利用这个函数快速定位某个元素。

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

int main() {
	int a[9] = {4,7,6,9,1,8,2,3,5};
	
	nth_element(a, a + 2, a + 9);
	//将下标为2,也就是第3个数放在正确的位置
	//也就是求的是第3小
	
	cout <<"第3小是:"<< a[2] << endl;
	
	//输出调整后的数组 
	for(int i = 0; i < 9; i++)
		cout << a[i] << " ";
	return 0;
}


十、find查找:

[C++] 基础教程 - std::find函数介绍和使用场景-优快云博客

c++STL中的find()函数 有两种使用方法_stl find函数返回值-优快云博客

原先我以为find只在string有,如今才发现vector,queue,甚至一般的数组都能用!

find返回的是一个迭代器,用法就是find (a.begin(), a.end(), x),

不过需要说明的是,vector似乎不能直接用 int *it 的指针来指向,要么用auto,要么用迭代器指针:

C++ find()函数用法(一般用于vector的查找)_c++ vector find-优快云博客

而对于普通数组,则是可以用int *it 的:

int res[5] = { 0,1,2,3,4 };
	int *pos = find(res, res + 5, 5);
	//这里的查找范围是指针
	//res+5不在查找范围内
	if (pos == (res + 5))
		cout << "Couldn't find it";
	else
		cout << "Find it!";

其他可以看上面那几个文章。


十一、__gcd()求最大公约数:

我都没想到连求最大公约数都有方便函数!!!

用法很简单:

int answer = __gcd(a, b); //注意是两个下划线

//__gcd(12,15) = 3
//__gcd(21,0) = 21

然后没了,

就这么简单!!!

另外,求了最大公约数就一定绕不开最小公倍数:

求法就是用两个数相乘再除以这个最大公约数:

int mingbs = (a * b) / __gcd(a, b);

其他基本上要么比较复杂要么目前还没用上,先不讲了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值