• ACM/ICPC竞赛


    09篇 ACM/ICPC竞赛之STL--algorithm


    <algorithm>无疑是STL中最大的一个头文件,它是由一大堆模板函数组成的。

    下面列举出<algorithm>中的模板函数:

     adjacent_find / binary_search / copy / copy_backward / count / count_if / equal / equal_range / fill / fill_n / find / find_end / find_first_of / find_if / for_each / generate / generate_n / includes / inplace_merge / iter_swap / lexicographical_compare / lower_bound / make_heap / max / max_element / merge / min / min_element / mismatch / next_permutation / nth_element / partial_sort / partial_sort_copy / partition / pop_heap / prev_permutation / push_heap / random_shuffle / remove / remove_copy / remove_copy_if / remove_if / replace / replace_copy / replace_copy_if / replace_if / reverse / reverse_copy / rotate / rotate_copy / search / search_n / set_difference / set_intersection / set_symmetric_difference / set_union / sort / sort_heap / stable_partition / stable_sort / swap / swap_ranges / transform / unique / unique_copy / upper_bound



    如果详细叙述每一个模板函数的使用,足够写一本书的了。还是来看几个简单的示例程序吧。

    示例程序之一,for_each遍历容器:

     1 #include <iostream>
     2 #include <vector>
     3 #include <algorithm>
     4 using namespace std;
     5 
     6 int Visit(int v) // 遍历算子函数
     7 {
     8 cout << v << " ";
     9 return 1;
    10 }
    11 
    12 class MultInt // 定义遍历算子类
    13 {
    14 private:
    15 int factor;
    16 public:
    17 MultInt(int f) : factor(f)
    18 {
    19 }
    20 void operator()(int &elem) const
    21 {
    22 elem *= factor;
    23 }
    24 };
    25 
    26 main()
    27 {
    28 vector<int> L;
    29 for (int i=0; i<10; i++) L.push_back(i);
    30 for_each(L.begin(), L.end(), Visit);
    31 cout << endl;
    32 for_each(L.begin(), L.end(), MultInt(2));
    33 for_each(L.begin(), L.end(), Visit);
    34 cout << endl;
    35 return 1;
    36 }
    37 
    38 程序的输出结果为:
    39 
    40 0 1 2 3 4 5 6 7 8 9
    41 0 2 4 6 8 10 12 14 16 18



    示例程序之二,min_element/max_element,找出容器中的最小/最大值:

     1 #include <iostream>
     2 #include <vector>
     3 #include <algorithm>
     4 using namespace std;
     5 
     6 main()
     7 {
     8 vector<int> L;
     9 for (int i=0; i<10; i++) L.push_back(i);
    10 vector<int>::iterator min_it = min_element(L.begin(), L.end());
    11 vector<int>::iterator max_it = max_element(L.begin(), L.end());
    12 cout << "Min is " << *min_it << endl;
    13 cout << "Max is " << *max_it << endl;
    14 return 1;
    15 }
    16 
    17 程序的输出结果为:
    18 
    19 Min is 0
    20 Max is 9



    示例程序之三,sort对容器进行排序:

     1 #include <iostream>
     2 #include <vector>
     3 #include <algorithm>
     4 using namespace std;
     5 void Print(vector<int> &L)
     6 {
     7 for (vector<int>::iterator it=L.begin(); it!=L.end(); it++)
     8 cout << *it << " ";
     9 cout << endl;
    10 }
    11 main()
    12 {
    13 vector<int> L;
    14 for (int i=0; i<5; i++) L.push_back(i);
    15 for (int i=9; i>=5; i--) L.push_back(i);
    16 Print(L);
    17 sort(L.begin(), L.end());
    18 Print(L);
    19 sort(L.begin(), L.end(), greater<int>()); // 按降序排序
    20 Print(L);
    21 return 1;
    22 }
    23 
    24 程序的输出结果为:
    25 
    26 0 1 2 3 4 9 8 7 6 5
    27 0 1 2 3 4 5 6 7 8 9
    28 9 8 7 6 5 4 3 2 1 0



    示例程序之四,copy在容器间复制元素:

     1 #include <vector>
     2 #include <algorithm>
     3 #include <iostream>
     4 using namespace std;
     5 main( )
     6 {
     7 // 先初始化两个向量v1和v2
     8 vector <int> v1, v2;
     9 for (int i=0; i<=5; i++) v1.push_back(10*i);
    10 for (int i=0; i<=10; i++) v2.push_back(3*i);
    11 
    12 cout << "v1 = ( " ;
    13 for (vector <int>::iterator it=v1.begin(); it!=v1.end(); it++)
    14 cout << *it << " ";
    15 cout << ")" << endl;
    16 
    17 cout << "v2 = ( " ;
    18 for (vector <int>::iterator it=v2.begin(); it!=v2.end(); it++)
    19 cout << *it << " ";
    20 cout << ")" << endl;
    21 
    22 // 将v1的前三个元素复制到v2的中间
    23 copy(v1.begin(), v1.begin()+3, v2.begin()+4);
    24 
    25 cout << "v2 with v1 insert = ( " ;
    26 for (vector <int>::iterator it=v2.begin(); it!=v2.end(); it++)
    27 cout << *it << " ";
    28 cout << ")" << endl;
    29 
    30 // 在v2内部进行复制,注意参数2表示结束位置,结束位置不参与复制
    31 copy(v2.begin()+4, v2.begin()+7, v2.begin()+2);
    32 
    33 cout << "v2 with shifted insert = ( " ;
    34 for (vector <int>::iterator it=v2.begin(); it!=v2.end(); it++)
    35 cout << *it << " ";
    36 cout << ")" << endl;
    37 return 1;
    38 }
    39 
    40 程序的输出结果为:
    41 
    42 v1 = ( 0 10 20 30 40 50 )
    43 v2 = ( 0 3 6 9 12 15 18 21 24 27 30 )
    44 v2 with v1 insert = ( 0 3 6 9 0 10 20 21 24 27 30 )
    45 v2 with shifted insert = ( 0 3 0 10 20 10 20 21 24 27 30 )

    STL in ACM

    容器(container):

    迭代器(iterator): 指针

    内部实现: 数组 // 就是没有固定大小的数组,vector 直接翻译是向量vector // T 就是数据类型,Alloc 是关于内存的一个什么东西,一般是使用默认参数。

    支持操作:

    begin(), //取首个元素,返回一个iterator

    end(), //取末尾(最后一个元素的下一个存储空间的地址)

    size(), //就是数组大小的意思

    clear(), //清空

    empty(), //判断vector 是否为空

    [ ] //很神奇的东东,可以和数组一样操作

    //举例: vector a; //定义了一个vector

    //然后我们就可以用a[i]来直接访问a 中的第i + 1 个元素!和数组的下标一模一样!

    push_back(), pop_back() //从末尾插入或弹出

    insert() O(N) //插入元素,O(n)的复杂度

    erase() O(N) //删除某个元素,O(n)的复杂度

    可以用于数组大小不定且空间紧张的情况

    Iterator 用法举例:

    int main(){

    int n,i;

    vector vi; //类似于我们定义一个数组,同 int vi[1000]; 但vector的大小是自动调整的

    vector ::iterator itr; //两个冒号

    while (scanf("%d",&n) != EOF) vi.push_back(n);

    for (i = 0 ; i < vi.size() ; i++) printf("%d ",vi[i]);

    for (itr = vi.begin() ; itr != vi.end() ; itr++)

    printf("%d ",*itr);

    return 0;

    }

    类似:双端队列,两头都支持进出

    支持push_front()和pop_front()

    是的精简版:) //栈,只支持从末尾进出

    支持push(), pop(), top()

    是的精简版 //单端队列,就是我们平时所说的队列,一头进,另一头出

    支持push(), pop(), front(), back()

    内部实现: 双向链表 //作用和vector 差不多,但内部是用链表实现

    list

    支持操作:

    begin(), end(), size(), clear(), empty()

    push_back(), pop_back() //从末尾插入或删除元素

    push_front(), pop_front()

    insert() O(1) //链表实现,所以插入和删除的复杂度的O(1)

    erase() O(1)

    sort() O(nlogn),不同于中的sort

    //不支持[ ]操作!

    内部实现: 红黑树 //Red-Black Tree,一种平衡的二叉排序树

    set //又是一个Compare 函数,类似于qsort 函数里的那个Compare 函数,

    作为红黑树在内部实现的比较方式

    insert() O(logn)

    erase() O(logn)

    find() O(logn) 找不到返回a.end()

    lower_bound() O(logn) 查找第一个不小于k 的元素

    upper_bound() O(logn) 查找第一个大于k 的元素

    equal_range() O(logn) 返回pair

    42

    允许重复元素的

    的用法及Compare 函数示例:

    struct SS {int x,y;};

    struct ltstr {

    bool operator() (SS a, SS b)

    {return a.x < b.x;} //注意,按C 语言习惯,double 型要写成这样:

    return a.x < b.x ? 1 : 0;

    };

    int main() {

    set st;

    }

    内部实现: pair 组成的红黑树 //map 中文意思:映射!!

    map //就是很多pair 组成一个红黑树

    insert() O(logn)

    erase() O(logn)

    find() O(logn) 找不到返回a.end()

    lower_bound() O(logn) 查找第一个不小于k 的元素

    upper_bound() O(logn) 查找第一个大于k 的元素

    equal_range() O(logn) 返回pair

    [key]运算符 O(logn) *** //这个..太猛了,怎么说呢,数组有一个下标,如a[i],这里i 是int 型的。数组可以认为是从int 印射到另一个类型的印射,而map 是一个任意的印射,所以i 可以是任何类型的!允许重复元素, 没有[]运算符

    内部实现: 堆 //优先队列,听RoBa 讲得,似乎知道原理了,但不明白干什么用的

    priority_queue

    支持操作:

    push() O(n)

    pop() O(n)

    top() O(1)

    See also: push_heap(), pop_heap() … in

    用法举例:

    priority_queue maxheap; //int 最大堆

    struct ltstr { //又是这么个Compare 函数,重载运算符???不明白为什么要这么写...反正这个Compare 函数对我来说是相当之神奇。RoBa

    说了,照着这么写就是了。

    bool operator()(int a,int b)

    {return a > b;}

    };

    priority_queue <INT,VECTOR,ltstr> minheap; //int 最小堆

    1.sort()

    void sort(RandomAccessIterator first, RandomAccessIterator

    last);

    void sort(RandomAccessIterator first, RandomAccessIterator

    last, StrictWeakOrdering comp);

    区间[first,last)

    Quicksort,复杂度O(nlogn)

    (n=last-first,平均情况和最坏情况)

    用法举例:

    1.从小到大排序(int, double, char, string, etc)

    const int N = 5;

    int main()

    {

    int a[N] = {4,3,2,6,1};

    string str[N] = {“TJU”,”ACM”,”ICPC”,”abc”,”kkkkk”};

    sort(a,a+N);

    sort(str,str+N);

    return 0;

    }

    2.从大到小排序(需要自己写comp 函数)

    const int N = 5;

    int cmp(int a,int b) {return a > b;}

    int main()

    {

    int a[N] = {4,3,2,6,1};

    sort(a,a+N,cmp);

    return 0;

    }

    3. 对结构体排序

    struct SS {int first,second;};

    int cmp(SS a,SS b) {

    if (a.first != b.first) return a.first < b.first;

    return a.second < b.second;

    }

    v.s. qsort() in C (平均情况O(nlogn),最坏情况

    O(n^2)) //qsort 中的cmp 函数写起来就麻烦多了!

    int cmp(const void *a,const void *b) {

    if (((SS*)a)->first != ((SS*)b)->first)

    return ((SS*)a)->first – ((SS*)b)->first;

    return ((SS*)a)->second – ((SS*)b)->second;

    }

    qsort(array,n,sizeof(array[0]),cmp);

    sort()系列:

    stable_sort(first,last,cmp); //稳定排序

    partial_sort(first,middle,last,cmp);//部分排序

    将前(middle-first)个元素放在[first,middle)中,其余元素位置不定

    e.g.

    int A[12] = {7, 2, 6, 11, 9, 3, 12, 10, 8, 4, 1, 5};

    partial_sort(A, A + 5, A + 12);

    // 结果是 "1 2 3 4 5 11 12 10 9 8 7 6".

    Detail: Heapsort ,

    O((last-first)*log(middle-first))

    sort()系列:

    partial_sort_copy(first, last, result_first, result_last,

    cmp);

    //输入到另一个容器,不破坏原有序列

    bool is_sorted(first, last, cmp);

    //判断是否已经有序

    nth_element(first, nth, last, cmp);

    //使[first,nth)的元素不大于[nth,last), O(N)

    e.g. input: 7, 2, 6, 11, 9, 3, 12, 10, 8, 4, 1, 5

    nth_element(A,A+6,A+12);

    Output: 5 2 6 1 4 3 7 8 9 10 11 12

    2. binary_search()

    bool binary_search(ForwardIterator first, ForwardIterator

    last, const LessThanComparable& value);

    bool binary_search(ForwardIterator first, ForwardIterator

    last, const T& value, StrictWeakOrdering comp);

    [first,last)中查找value,如果找到返回Ture,否则返回False

    二分检索,复杂度O(log(last-first))

    v.s. bsearch() in C

    Binary_search()系列

    itr upper_bound(first, last, value, cmp);

    //itr 指向大于value 的第一个值(或容器末尾)

    itr lower_bound(first, last, value, cmp);

    //itr 指向不小于valude 的第一个值(或容器末尾)

    pair equal_range(first, last, value, cmp);

    //找出等于value 的值的范围 O(2*log(last – first))

    int A[N] = {1,2,3,3,3,5,8}

    *upper_bound(A,A+N,3) == 5

    *lower_bound(A,A+N,3) == 3

    make_heap(first,last,cmp) O(n)

    push_heap(first,last,cmp) O(logn)

    pop_heap(first,last,cmp) O(logn)

    is_heap(first,last,cmp) O(n)

    e.g:

    vector vi;

    while (scanf(“%d”,&n) != EOF) {

    vi.push_back(n);

    push_heap(vi.begin(),vi.end());

    }

    Others interesting:

    next_permutation(first, last, cmp)

    prev_permutation(first, last, cmp)

    //both O(N)

    min(a,b);

    max(a,b);

    min_element(first, last, cmp);

    max_element(first, last, cmp);

    Others interesting:

    fill(first, last, value)

    reverse(first, last)

    rotate(first,middle,last);

    itr unique(first, last);

    //返回指针指向合并后的末尾处

    random_shuffle(first, last, rand)

    头文件

    #include <vector>

    #include <list>

    #include <map>

    #include <set>

    #include <deque>

    #include <stack>

    #include <bitset>

    43

    #include <algorithm>

    #include <functional>

    #include <numeric>

    #include <utility>

    #include <sstream>

    #include <iostream>

    #include <iomanip>

    #include <cstdio>

    #include <cmath>

    #include <cstdlib>

    #include <ctime>

    using namespace std;

    未完待续……

     

     

     

  • 相关阅读:
    clean code
    jenkins
    获取目录下的文件名称
    bootstrap-select 下拉互斥
    supervisord
    正则表达式
    Docker
    git
    goland工具
    小程序 swiper 轮播图滚动图片 + 视频
  • 原文地址:https://www.cnblogs.com/jeff-wgc/p/4480343.html
Copyright © 2020-2023  润新知