STL算法
STL 算法是一些模板函数,提供了相当多的有用算法和操作,从简单如for_each(遍历)到复杂如stable_sort(稳定排序),头文件是:#include <algorithm>。常用STL 算法库包括:sort快速排序算法、二分查找算法、枚举排列算法等。
1、 sort排序系列
sort:对给定区间所有元素进行排序(全排)
stable_sort:对给定区间所有元素进行稳定排序,就是相等的元素位置不变,原来在前面的还在前面。
partial_sort:对给定区间所有元素部分排序,就是找出你指定的数目最小或最大的值放在最前面或最后面,比如说我只要找到1000000个数中最大的五个数,那你用这个函数是最好的,排序后最大的五个数就在最前面的五个位置,其他的元素位置分布不确定。
partial_sort_copy:对给定区间复制并排序,和上面的一样,只是这是指定区间进行复制然后排序的。
nth_element:找出给定区间的某个位置对应的元素,根据比较函数找到第n个最大(小)元素,适用于寻找“第n个元素”。
is_sorted:判断一个区间是否已经排好序(返回bool值判断是否已排序)
partition:使得符合某个条件的元素放在前面,划分区间函数,将 [first, last]中所有满足的元素置于不满足的元素前面,这个函数会返回迭代器,设返回的迭代器为 i,则对 [first, i]中的任意迭代器 j,*j满足给定的判断,对 [i, last] 中的任意迭代器 k,*k不满足。
stable_partition:相对稳定的使得符合某个条件的元素放在前面(和上面的一样,只是位置不变)
使用时根据需要选择合理的排序函数即可,所有的排序函数默认从小到大排序,可以定义自己的比较方式。
2、二分系列
二分检索,复杂度O(log(last-first))
itr =upper_bound(first, last, value, cmp);
//itr 指向大于value 的第一个值(或容器末尾)
itr = lower_bound(first, last, value, cmp);
//itr 指向不小于valude 的第一个值(或容器末尾)
pairequal_range(first, last, value, cmp);
//找出等于value的值的范围O(2*log(last–first))
Binary_search(first,last, value)返回bool值,找到则true,否则false。
二分经常会与其他算法结合。
例:HDU 1496
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int val[40010];
int main() {
pair <int*, int*> p;
int a, b, c, d;
while (cin >> a >> b >> c >> d) {
if( (a > 0 && b > 0 && c > 0 && d > 0) || (a < 0 && b < 0 && c < 0 && d < 0)){
cout << 0 << endl;
continue;
}
memset(val, 0, sizeof(val));
int k = 0;
for (int i = -100; i <= 100; i++){
if (i == 0) continue;
for (int j = -100; j <= 100; j++) {
if (j == 0) continue;
val[k++] = a*i*i + b*j*j;
}
}
sort(val, val+k);
int cnt = 0;
for (int j = -100; j <= 100; j++) {
if (j == 0) continue;
for (int i = -100; i <= 100; i++) {
if (i == 0) continue;
int sum = c*j*j + d*i*i;
p = equal_range(val, val+k, -sum);
cnt += p.second - p.first;
}
}
cout << cnt << endl;
}
return 0;
}
3、排列系列
next_permutation是一个求一个排序的下一个排列的函数,可以遍历全排列,要包含头文件<algorithm>,与之完全相反的函数还有prev_permutation。
int 类型的next_permutation
int main()
{
int a[3];
a[0]=1;a[1]=2;a[2]=3;
do
{
cout<<a[0]<<""<<a[1]<<" "<<a[2]<<endl;
} while (next_permutation(a,a+3));
}
输出:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
char 类型的next_permutation
int main()
{
char ch[205];
cin >> ch;
sort(ch, ch + strlen(ch) );
char *first = ch;
char *last = ch + strlen(ch);
do {
cout<< ch << endl;
}while(next_permutation(first, last));
return 0;
}
string 类型的next_permutation
int main()
{
string line;
while(cin>>line&&line!="#")
{
if(next_permutation(line.begin(),line.end()))
cout<<line<<endl;
else cout<<"Nosuccesor\n";
}
}
int main()
{
string line;
while(cin>>line&&line!="#")
{
sort(line.begin(),line.end());
cout<<line<<endl;
while(next_permutation(line.begin(),line.end()))
cout<<line<<endl;
}
}
4、常用函数
copy、copy_if:copy直接拷贝,比for循环高效,最坏为线性复杂度,而且这个可以说是一个copy族函数,还有类似的满足一定条件的copy_if等。
find、find_i:查找第一个匹配的值或第一个满足函数使其为true的值位置,没有返回指定区间的末尾,线性复杂度,还有一些不怎么常用的find族函数就不多介绍了。
count、count_if:返回匹配或使函数为true的值的个数,线性复杂度。
search:这是寻找序列是否存在于另一个序列中的函数,挺好用的,某些简单的寻找公共子串的题就可以这样写,时间复杂度二次。
reverse:翻转一个区间的值,我经常遇到需要这种题,直接reverse了,不需要for循环了,主要是方便。
for_each:直接对一个区间内的每个元素执行后面的函数操作,写起来简单。
max、min、max_element、min_element:寻找两个数或者一个区间的最大最小值,都可以添加比较函数参数。
集合操作函数:includes、set_union、set_difference、set_intersection、set_symmetric_difference、前面这些函数的最差复杂度为线性,另外附加一个序列的操作函数merge,相当于归并排序中的合并函数,时间复杂度为线性,注意这些函数的操作对象都必须是升序的。
例:
#include<cstdio>
#include<algorithm>
using namespace std;
void out(int a) { if (a != -1) printf("%d ",a); }
int main() {
int a[5] = {1, 8, 10, 52, 100};
int b[5] = {6, 8, 9, 10, 1000};
int c[20];
printf("a集合为:");
for_each(a, a+5, out);
puts("");
printf("b集合为:");
for_each(b, b+5, out);
puts("");
//判断b是否是a的子集。
if(includes(a, a+5, b, b+5)) printf("bis a sub set of a\n");
//合并两个有序序列,必须为合并后的序列分配空间,否则程序会崩溃。
printf("两个集合的合并序列为:");
merge(a, a+5, b, b+5, c);
for_each(c, c+10, out);
puts("");
//求两个集合的并集。
fill(c, c+20, -1);
set_union(a, a+5, b, b+5, c);
printf("两个集合的并集为:");
for_each(c, c+10, out);
puts("");
//求两个集合的交集。
fill(c, c+20, -1);
set_intersection(a, a+5, b, b+5, c);
printf("两个集合的交集为:");
for_each(c, c+10, out);
puts("");
//求两个集合的差集,这里为a-b。
fill(c, c+20, -1);
set_difference(a, a+5, b, b+5, c);
printf("a-b的差集为:");
for_each(c, c+10, out);
puts("");
//求两个集合的差集,这里为b-a。
fill(c, c+20, -1);
set_difference(b, b+5, a, a+5, c);
printf("b-a的差集为:");
for_each(c, c+10, out);
puts("");
//求两个集合的对称差
set_symmetric_difference(a, a+5, b, b+5,c);
printf("两个集合的对称差为:");
for_each(c, c+10, out);
puts("");
return 0;
}