NOIP大纲整理:(八)STL函数算法

29 篇文章 1 订阅
26 篇文章 6 订阅

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;   
}

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值