【STL】STL函数总结,助你代码实用高逼格

STL可谓是C++的利器,深受算法竞赛选手所爱,今天我将常用函数总结了一下,他们是代码中的技巧,使用后代码层次直接提升一个档次。

废话不多说,直接开始

下文介绍常见STL函数,如要了解STL容器请访问
👉C++ STL 详解超全总结(快速入门)👈


以下出现的描述说明:(下面函数排序按字典序排列

beg为序列的初始地址

end为序列的尾地址

STL函数

accumulate

accumulate(beg, end, init)

复杂度: O ( N ) O(N) O(N)

作用:对一个序列的元素求和

init为对序列元素求和的初始值

返回值类型:与init 相同

  • 基础累加求和:
int a[]={1, 3, 5, 9, 10};

//对[0,2]区间求和,初始值为0,结果为0 + 1 + 3 + 5 = 9
int res1 = accumulate(a, a + 3, 0);

//对[0,3]区间求和,初始值为5,结果为5 + 1 + 3 + 5 + 9 = 23
int res2 = accumulate(a, a + 4, 5);
  • 自定义二元对象求和:

使用lambda表达式

typedef long long ll;
struct node {
    ll num;
} st[10];

for(int i = 1; i <= n; i++)
    st[i].num = i + 10000000000;
//返回值类型与init一致,同时注意参数类型(a)也要一样
//初始值为1,累加1+10000000001+10000000002+10000000003=30000000007
ll res = accumulate(st + 1, st + 4, 1ll, [](ll a,node b) {
    return a + b.num;
});

atoi

atoi(const char *)

将字符串转换为int类型

注意参数为char型数组,如果需要将string类型转换为int类型,可以使用stoi函数(参考下文),或者将string类型转换为const char *类型。

关于输出数字的范围:
atoi不做范围检查,如果超出上界,输出上界,超出下界,输出下界。
stoi会做范围检查,默认必须在int范围内,如果超出范围,会出现RE(Runtime Error)错误。

string s = "1234";
int a = atoi(s.c_str());
cout << a << "\n"; // 1234

或者

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

fill

fill(beg, end, num)

复杂度: O ( N ) O(N) O(N)

对一个序列进行初始化赋值

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

注意区分memset:

memset()是按字节进行赋值,对于初始化赋0-1有比较好的效果.

如果赋某个特定的数会出错,赋值特定的数建议使用fill()

is_sorted

is_sorted(beg, end)

复杂度: O ( N ) O(N) O(N)

判断序列是否有序(升序),返回bool

//如果序列有序,输出YES
if(is_sorted(a, a + n))
    cout << "YES\n";

iota

iota(beg, end)

让序列递增赋值

vector<int> a(10);
iota(a.begin(), a.end(), 0);
for(auto i : a)
	cout << i << " ";
// 0 1 2 3 4 5 6 7 8 9

lower_bound + upper_bound

复杂度: O ( l o g N ) O(logN) O(logN)

作用:二分查找

//在a数组中查找第一个大于等于x的元素,返回该元素的地址
lower_bound(a, a + n, x);
//在a数组中查找第一个大于x的元素,返回该元素的地址
upper_bound(a, a + n, x);

//如果未找到,返回尾地址的下一个位置的地址

max_element+min_element

复杂度: O ( N ) O(N) O(N)

找最大最小值

//函数都是返回地址,需要加*取值
int mx = *max_element(a, a + n);
int mn = *min_element(a, a + n);

max+min

复杂度: O ( 1 ) O(1) O(1)

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

//找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});

minmax

minmax(a, b)

复杂度: O ( 1 ) O(1) O(1)

返回一个pair类型,第一个元素是min(a, b), 第二个元素是max(a, b)

pair<int, int> t = minmax(4, 2);
// t.first = 2, t.second = 4

minmax_element

minmax_element(beg, end)

复杂度: O ( N ) O(N) O(N)

返回序列中的最小和最大值组成pair的对应的地址,返回类型为pair<vector<int>::iterator, vector<int>::iterator>

int n = 10;
vector<int> a(n);
iota(a.begin(), a.end(), 1);
auto t = minmax_element(a.begin(), a.end()); // 返回的是最小值和最大值对应的地址
// *t.first = 1, *t.second = 10 输出对应最小最大值时需要使用指针

nth_element

nth_element(beg, nth, end)

复杂度: 平均 O ( N ) O(N) O(N)

寻找第序列第n小的值

nth为一个迭代器,指向序列中的一个元素。第n小的值恰好在nth位置上。

执行nth_element()之后,序列中的元素会围绕nth进行划分:nth之前的元素都小于等于它,而之后的元素都大于等于它

实例:求序列中的第3小的元素

nth_element(a, a + 2, a + n);
cout << a[2] << '\n';

next_permutation

next_permutation(beg, end)

复杂度: O ( N ) O(N) O(N)

求序列的下一个排列,下一个排列是字典序大一号的排列

返回truefalse

  • next_permutation(beg, end)

    如果是最后一个排列,返回false,否则求出下一个序列后,返回true

//对a序列进行重排
next_permutation(a, a + n);

应用:求所有的排列

输出a的所有排列

// 数组a不一定是最小字典序序列,一定注意将它排序
sort(a, a + n);
do {
 	for(int i = 0; i < n; i++)
        printf("%d ", a[i]);
} while(next_permutation(a, a + n));
  • prev_permutation(beg, end)

求出前一个排列,如果序列为最小的排列,将其重排为最大的排列,返回false

partial_sort

partial_sort(beg, mid, end)

复杂度: 大概 O ( N l o g M ) O(N logM) O(NlogM) M为距离

部分排序,排序mid-beg个元素,mid为要排序区间元素的尾后的一个位置

从beg到mid的元素都排好序

对a数组前5个元素排序按从小到大排序

int a[] = {1,2,5,4,7,9,8,10,6,3};
partial_sort(a, a + 5, a + 10);
for(int i = 0; i < 10; i++) 
    cout << a[i] << ' ';
//1 2 3 4 5 9 8 10 7 6
//前五个元素都有序

也可以添加自定义排序规则:

partial_sort(beg,mid,end,cmp)

对a的前五个元素都是降序排列

int a[] = {1,2,5,4,7,9,8,10,6,3};
partial_sort(a, a + 5, a + 10, greater<int>());
for(int i = 0; i < 10; i++) 
    cout << a[i] << ' ';
//10 9 8 7 6 1 2 4 5 3
//前五个元素降序有序

random_shuffle

复杂度: O ( N ) O(N) O(N)

  1. 随机打乱序列的顺序
  2. random_shuffle 在 C++14 中被弃用,在 C++17 中被废除,C++11之后应尽量使用shuffle来代替。
vector<int> b(n);
iota(b.begin(), b.end(), 1);// 序列b递增赋值 1, 2, 3, 4,...
// 对a数组随机重排
random_shuffle(a, a + n);
// C++11之后尽量使用shuffle
shuffle(b.begin(), b.end());

reverse

reverse(beg,end)

复杂度: O ( N ) O(N) O(N)

对序列进行翻转

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

set_union, set_intersection,set_difference

复杂度: O ( N + M ) O(N+M) O(N+M)

求两个集合的并集,交集,差集。手动实现双指针就可以搞定,嫌麻烦可以使用该函数。

注意:两个集合必须为有序集合,所以下面演示代码使用了排序。vector容器可以替换成set容器,因为set自动会对元素进行排序。

函数的参数有五个,前两个为第一个容器的首尾迭代器,第三四个为第二个容器的首尾迭代器,最后一个为插入位置,即将结果插入到哪个地址之后。

vector<int> a = {4, 5, 2, 1, 8}, b = {5, 3, 8, 9, 2};
sort(a.begin(), a.end()); // 1 2 4 5 8
sort(b.begin(), b.end()); // 2 3 5 8 9
vector<int> c, d, e;
// a并b:1 2 3 4 5 8 9
set_union(a.begin(), a.end(), b.begin(), b.end(), inserter(c, c.begin()));
// a交b:2 5 8
set_intersection(a.begin(), a.end(), b.begin(), b.end(), inserter(d, d.begin()));
// a差b: 1 4
set_difference(a.begin(), a.end(), b.begin(), b.end(), inserter(e, e.begin()));

sort

复杂度: O ( N l o g N ) O(N logN) O(NlogN)

作用:对一个序列进行排序

//原型:
sort(beg, end);
sort(beg, end, cmp);

几种排序的常见操作:

  • 操作一:对数组正常升序排序
int a[N]; // 普通数组定义
// 对 a 数组的[1, n]位置进行从小到大排序
sort(a + 1, a + 1 + n);

vector<int> b(n + 1); // vector数组定义
sort(b.begin() + 1, b.end());
  • 操作二:使用第三个参数,进行降序排序
//对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>()); // 降序
  • 操作三:另外一种降序排序方法,针对 vector
vector<int> a(n);
sort(a.rbegin(), a.rend()); // 使用反向迭代器进行降序排序
  • 操作四:自定义排序规则
// 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;
});

stable_sort

复杂度: O ( N l o g N ) O(N logN) O(NlogN)

功能和 sort() 基本一样

区别在于stable_sort()能够保证相等元素的相对位置,排序时不会改变相等元素的相对位置

使用用法和sort()一样,见上

stoi

stoi(const string*)

将对应string类型字符串转换为数字,记忆:s -> t 分别对应两个数据类型的某个字母

注意参数为string字符串类型。

关于输出数字的范围:

  • stoi会做范围检查,默认必须在int范围内,如果超出范围,会出现RE(Runtime Error)错误。

  • atoi不做范围检查,如果超出上界,输出上界,超出下界,输出下界。

string s = "1234";
int a = stoi(s);
cout << a << "\n"; // 1234

transform

复杂度: O ( N ) O(N) O(N)

作用:使用给定操作,将结果写到dest中

//原型:
transform(beg, end, dest, unaryOp);

一般不怎么使用,徒增记忆负担,不如手动实现。

//将序列开始地址beg到结束地址end大小写转换,把结果存到起始地址为dest的序列中
transform(beg, end, dest, ::tolower);
transform(beg, end, dest, ::toupper);

to_string

将数字转化为字符串,支持小数(double)

int a = 12345678;
cout << to_string(a) << '\n';

unique

unique(beg, end)

复杂度: O ( N ) O(N) O(N)

消除重复元素,返回消除完重复元素的下一个位置的地址

如:a[] = {1, 3, 2, 3, 6};

unique 之后 a 数组为{1, 2, 3, 6, 3}前面为无重复元素的数组,后面则是重复元素移到后面,返回a[4]位置的地址(不重复元素的尾后地址)

消除重复元素一般需要原序列是有序序列

应用:离散化

  • 方法一:利用数组离散化
for(int i = 0; i < n; i++) {
    cin >> a[i];
    b[i] = a[i];//将a数组复制到b数组
}
// 排序后 b:{1, 2, 3, 3, 6}
sort(b, b + n);//对b数组排序
// 消除重复元素b:{1, 2, 3, 6, 3} 返回的地址为最后一个元素3的地址 
int len = unique(b, b + n) - b;//消除 b 的重复元素,并获取长度
for(int i = 0; i < n; i++) {
    //因为b有序,查找到的下标就是对应的 相对大小(离散化后的值)
    int pos = lower_bound(b, b + len, a[i]) - b;//在b数组中二分查找第一个大于等于a[i]的下标
    a[i] = pos; // 离散化赋值
}
  • 方法二:利用 vector 进行离散化
vector<int> a(n);
for (int i = 0; i < n; ++i) {
    cin >> a[i];
}
vector<int> b = a;
sort(b.begin(), b.end());
b.erase(unique(b.begin(), b.end()), b.end());
for (int i = 0; i < n; ++i) {
	a[i] = lower_bound(b.begin(), b.end(), a[i]) - b.begin() + 1; // 离散后的数据从1开始   
}

__gcd

__gcd(a, b)

求a和b的最大公约数

__gcd(12,15) = 3

__gcd(21,0) = 21

__lg

__lg(a)
  1. 求一个数二进制下最高位位于第几位(从第0位开始)(或二进制数下有几位)
  2. __lg(x)相当于返回 ⌊ l o g 2 x ⌋ \lfloor log_2 x \rfloor ⌊log2​x⌋
  3. 复杂度 O ( 1 ) O(1) O(1)

__lg(8) = 3

__lg(15) = 3

_builtin 内置位运算函数

需要注意:内置函数有相应的unsigned lntunsigned long long版本,unsigned long long只需要在函数名后面加上ll就可以了,比如__builtin_clzll(x) ,默认是32位unsigned int

很多题目和 long long 数据类型有关,如有需要注意添加 ll

__builtin_ffs
__builtin_ffs(x)

二进制中对应最后一位1的位数,比如4会返回3(100)

__builtin_popcount
__builtin_popcount(x)

x1的个数

__builtin_ctz
__builtin_ctz(x)

x末尾0的个数(count tail zero

__builtin_clz
__builtin_clz(x)

x前导0的个数(count leading zero

cout << __builtin_clz(32); // 26
//因为共有6位,默认数据范围为32位,32 - 6 = 26
__builtin_parity
__builtin_parity(x)

x中1的个数的奇偶性, 奇数输出1,偶数输出0

可参考链接:

  1. C++语法糖 https://www.luogu.com.cn/blog/AccRobin/grammar-candies

如果你有任何想要补充的函数,欢迎评论留言补充呀!

如要获取所有内容的PDF文件,请在公众号【行码棋】回复【STL】获取,非常抱歉了。
Update:2023-12-11更新PDF文件

【STL】STL函数总结,助你代码实用高逼格-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值