zoukankan      html  css  js  c++  java
  • STL介绍与习题

    内容参考书籍《算法笔记》

    1.vector

      在一些用普通数组可能会超内存的情况下,可以选择用vector来存储数据,vector可以理解为“长度可以根据需要改变的数组”。并且用vector比较节省空间。

      使用vector,需要添加头文件#include<vector> , 而且还得在头文件下面加上using namespace std;

      (1). vector的定义

      vector<typename> name;   //单独定义一个vector ,相当于一维数组name[SIZE].  typename表示数据类型

      vector<vector<int> >     //如果typename也是一个STL容器,定义的时候记得在>>符号之间加上空格,因为c++11之前标准的编译器会把它视为移位操作。

      vector<typename> v[SIZE];   //vector数组的定义,v[0]~v[SIZE - 1]中每一个都是一个vector容器

      (2).元素的访问

      一般有两种访问方式 :通过下标访问或者通过迭代器访问。

      通过下标访问 : 和普通数组一样。

      通过迭代器访问 : 迭代器(iterator)可以理解为一种类似指针的东西。其定义是:vector<typename>::iterator it;

         这样it就是迭代器,并且可以用*it来访问vector里的元素

       如:

        for(int i = 0 ; i < 5 ;i ++ )  printf("%d", *(it + i));

      (3).vector 的常用函数分析

      push_back()  //在vector后面添加一个元素,如push_back(x);   时间复杂度是O(1)。

      pop_back()   //删除vector的尾元素。 时间复杂度是O(1)。

      size()       //获取vector中元素个数,时间复杂度O(1)。

      clear()   //清空vector中的所有元素,时间复杂度是O(N),N是vector中元素的个数。

         如:

        #include<iostream>

        using namespace std;

        int main(){

        vector<int>v;

        for(int i = 1 ; i <= 3 ; i++) vi.push_back(i);

        vi.clear();

        cout << vi.size();

        return 0;

        }

          输出结果:0

      insert()  //  insert(it , x) 用来向vector的任意迭代器it处插入一个元素x,时间复杂度O(N)。

      erase()  //有两种用法:删除单个元素、删除一个区间内的所有元素。时间复杂度都为O(N)。

        erase  (it)      //  删除迭代器为it处的元素。

        erase  (first , last) // 删除[first , last)内的所有元素

      (4).vector常见用途

        1.作为数组

        2.用邻接表存储图

    例题:http://acm.hdu.edu.cn/showproblem.php?pid=4841

    AC代码:

    #include<iostream>

    #include<vector>

    using namespace std;

    int n , m ;

    vector<int>v;

    const int N = 1e6 + 10;

    int res[N];

    int main(){

        while(cin >> n >> m){


            memset(res,1,sizeof(res));
            v.clear();
            for(int i = 0 ; i < 2*n ; i++)
                v.push_back(i);

            for(int i = 0 ,pos = 0 , num = 2 * n ; i< n ;i++){

                pos = (pos + m - 1) % num ;

                num --;

                res[v[pos]] = 0;

                v.erase(v.begin() + pos);
            }

            for(int i = 0 ; i< 2 * n;i++){

                if((i%50 == 0) && (i != 0)) printf(" ");

                if(res[i]) printf("G");

                else printf("B");

            }
           printf(" ");
        }
        return 0;
    }

    2.stack

      后进先出。#include<stack>并且用using namespace std;

    (1)在STL中栈只能通过top()来访问栈顶元素

    (2)常用函数

      push(x) //将x入栈,时间复杂度O(1)

      top()  //获得栈顶元素,时间复杂度O(1)

      pop() //弹出栈顶元素,时间复杂度O(1)

      empty() //检测栈是否为空,返回true为空,返回false为非空,时间复杂度O(1)

      size() //返回栈中元素个数,时间复杂度O(1)

    (3)常见用途

      可以用栈来模拟实现一些递归算法,应用于DFS

    例题:http://acm.hdu.edu.cn/showproblem.php?pid=1237

    AC代码:

    #include<iostream>

    #include<stack>

    using namespace std;

    int n;

    char c;

    int main(){

        scanf("%d",&n);

        getchar();

        while(n --){

            stack<char>s;
            while(1){
                c = getchar();
                if(c==' '||c==' '||c==EOF){
                    while(!s.empty()){
                        printf("%c",s.top());
                        s.pop();
                    }
                    if(c==' '||c==EOF)break;
                    printf(" ");
                }
                else
                    s.push(c);
            }
            printf(" ");
        }
        return 0;
    }

    3.queue   先进先出

    (1)在STL中只能通过front()来访问队首元素,或是通过back()来访问队尾元素。

    (2)常用函数

      push(x) //将x进行入队,时间复杂度为O(1)

      front()、 back() //分别获得队首元素和队尾元素,时间复杂度为O(1)

      pop() //令队首元素出队,时间复杂度为O(1)

      empty() //检测队列是否为空,返回true为空,返回false为非空,时间复杂度O(1)

      size() //返回栈中元素个数,时间复杂度O(1)

    (3)常见用途

      当需要实现BFS时,可以不用自己动手实现一个队列,而是用queue代替。

    例题:http://acm.hdu.edu.cn/showproblem.php?pid=1702

    #include<iostream>
    #include<stack>
    #include<queue>
    #include<string>
    using namespace std;
    int t;  //次数
    int main(){
        cin >> t;
        while(t --){
            stack<int> P;
            queue<int> Q;
            string s , s1;
            int n;
            int d;
            scanf("%d",&n);
            cin >> s ;
            if(s == "FIFO"){
                for(int i = 0; i<n;i++){
                    cin >> s1;
                    if(s1 == "IN"){
                        scanf("%d",&d);
                        Q.push(d);
                    }
                    if(s1 == "OUT"){
                        if(Q.empty())  printf("None ");
                        else{
                            cout << Q.front() << endl;
                            Q.pop();
                        }
                    }
                }
            }
            if(s == "FILO"){
                for(int i = 0; i<n;i++){
                    cin >> s1;
                    if(s1 == "IN"){
                        scanf("%d",&d);
                        P.push(d);
                    }
                    if(s1 == "OUT"){
                        if(P.empty())  printf("None ");
                        else{
                            cout << P.top() << endl;
                            P.pop();
                        }
                    }
                }
            }
        }
        return 0 ;
    }
    4.priority_queue 优先队列
      队首元素一定是当前队列中优先级最高的那个。和队列不一样的是优先队列没有front()和back()函数,只能通过top()函数来访问队首元素。
     
    (1)常用函数
      push(x)   //将x入队,时间复杂度为O(logN),N为当前优先队列中的元素个数。
      top()  //获得队首元素,时间复杂度O(1)
      pop()  //令队首元素出队,时间复杂度为O(logN),N为当前优先队列中的元素个数。
      empty() //检测优先队列是否为空,返回true则空,返回false则非空,时间复杂度O(1)。
      size()  //返回队列中元素的个数,时间复杂度O(1)。
     
    (2)priority_queue内元素优先级设置
      1.基本数据类型的优先级设置
           优先队列对它们的优先级设置一般是数字大的优先级越高。如果是char型,则是字典序最大的。对基本数据类型来说下面两种是等价的:
        1.priority_queue<int> q;
        2.priority_queue<int , vector<int> , less<int > > q;  //less<int>表示数字大的优先级越大,而greater<int>表示数字小的优先级越大。
      2.结构体优先级设置
           如:     struct fruit{
            string name;
            int price;
            
            friend bool operator < (fruit f1 , fruit f2){
              return f1.price < f2.price;
            }
           }
        表示对操作符“<”进行了重载(重载大于号会编译错误,因为从数学上来说只需要重载小于号,即f1 > f2 等价于判断f2 < f1 , 而f1 == f2 等价于判断!(f1 < f2) && !(f2 < f1) )
        重载后小于号还是小于号的作用,此时内部就是以价格高的水果优先级高。
        
        同理,如果想以价格低的水果优先级高,只需要把return中的小于号改为大于号,即:
        
          struct fruit{
            string name;
            int price;
            
            friend bool operator < (fruit f1 , fruit f2){
              return f1.price > f2.price;   //把小于号重载为大于号
            }
           }
        最后,如果结构体内数据较为庞大,建议使用引用来提高效率,此时比较类的参数中需要加上“const”和“&”如:
        
          struct fruit{
            string name;
            int price;
            
            friend bool operator < (const fruit &f1 ,const fruit &f2){
              return f1.price > f2.price;   //把小于号重载为大于号
            }
           }
      3.priority_queue的常见用途
        可以解决一些贪心问题,也可以对Dijkstra算法进行优化(因为优先队列的本质是堆)。
        有一点需要注意,使用top()函数前,必须要empty()判断队列是否为空,否则可能因为队空而出现错误。
    例题:http://acm.hdu.edu.cn/showproblem.php?pid=1873
    AC代码:
    #include<iostream>
    #include<queue>
    #include<string>
    using namespace std;
    struct node{
        int id ;
        int yxj ;
        friend bool operator < (const node &a,const node &b){  //保证B的优先级大于A
            if(a.yxj == b.yxj)  return a.id > b.id;
            return a.yxj < b.yxj;
        }
    }N[1010];
    priority_queue<node> doctor1;
    priority_queue<node> doctor2;
    priority_queue<node> doctor3;
    int main(){
        int t , n , i , k;
        string s;
        while(scanf("%d",&n) != EOF){
            k = 1 ;
            for( i = 0 ; i < n ;i++){
                cin >> s;
                if(s == "IN"){
                    N[i].id = k++;
                    scanf("%d%d",&t,&N[i].yxj) ;
                    if(t == 1) doctor1.push(N[i]);
                    else if(t == 2)doctor2.push(N[i]);
                    else if(t == 3)doctor3.push(N[i]);
                }
                else if(s == "OUT"){
                    scanf("%d",&t);
                    if(t == 1){
                        if(doctor1.empty()) cout<<"EMPTY"<<endl;
                        else{
                            cout << doctor1.top().id << endl;
                            doctor1.pop();
                        }
                    }
                    else if(t == 2){
                        if(doctor2.empty()) cout<<"EMPTY"<<endl;
                        else{
                            cout << doctor2.top().id << endl;
                            doctor2.pop();
                        }
                    }
                    else if(t == 3){
                        if(doctor3.empty()) cout<<"EMPTY"<<endl;
                        else{
                            cout << doctor3.top().id << endl;
                            doctor3.pop();
                        }
                    }
                }
            }
        }
        return 0;
    }
    5.list

    链表,高效率地在任意地方删除和插入,常数时间。

      常用操作与vector类似。

    例题:http://acm.hdu.edu.cn/showproblem.php?pid=1276

    AC代码:

    #include<iostream>
    #include<list>
    using namespace std;
    int main()
    {
        int t,n;
        cin>>t;
        while(t --)
        {
            cin >> n;
            int k = 2;
            list<int> l;
            list<int>::iterator it;
            for (int i = 1; i <= n; ++ i) l.push_back(i);
            while(l.size() > 3)
            {
                int num = 1;
                for (it = l.begin();it != l.end();)
                {
                    if(num++ % k == 0) it = l.erase(it);   //该试结束后返回的是被删除元素的下一个元素的迭代器
                    else it++;
                }
                k == 2?k = 3:k = 2;
            }
            for (it = l.begin();it != l.end();it++){
                if(it != l.begin()) cout<<" ";
                cout<<*it;
            }
            cout<<endl;
        }
        return 0;
    }
    6.set
      1.set的定义
        翻译为集合,是一个内部自动有序且不含重复元素的容器。set自动递增排序且自动去除了重复元素。需要用头文件#include<set> 和using namespace std;
      2.元素的访问
        set只能通过迭代器iterator访问
      3.常用函数
        1.insert(x)   //将x插入到set中,并自动递增排序和去重,时间复杂度为O(logN)
        2.find(value)  //返回set中对应值为value的迭代器,时间复杂度O(logN)
        3.erase()  //同vector 1.s.erase(it) //it为删除元素的迭代器,时间复杂度O(1)
             2.s.erase(value) //value是删除元素的值。时间复杂度O(logN)   
        4.size()
        5.clear() //时间复杂度O(N)  N为元素个数
    例题:http://acm.hdu.edu.cn/showproblem.php?pid=2094
    AC代码:
    #include <iostream>
    #include<set>
    using namespace std;
    int main()
    {
        set<string>a,b; //a存比赛人名,b存失败人名
        string s1,s2;
        int n;
        while(cin >> n && n)
        {
            for (int i = 0; i < n; ++i)
            {
                cin>>s1>>s2;
                a.insert(s1);
                a.insert(s2);
                b.insert(s2);
            }
            if (a.size()-b.size()==1) cout<<"Yes"<<endl;  //如果参赛人数比失败人数多一,那么比赛有一个人没失败,则必然是冠军
            else cout<<"No"<<endl;
            a.clear();b.clear();
        }
        return 0;
    }
    7.map
      map翻译为映射,定义int a[100]数组时,实际上是定义了一个int型到int型的数组,如a[0] = 25,是将0映射到25.
      
      如果要用数组来表示“字符串->页码”这样的对应关系,就可以用到map。
     
      map可以将任何基本类型(包括STL容器)映射到任何基本类型(包括STL容器)。
     
      1.map的定义
        需用到#include<map>;和using namespace std;
        map<typename1 , typename2> mp;  实现从映射前类型 键(key)到映射后类型 值(value)的映射。
           如果是字符串到整形的映射,必须用string而不能用char数组。
      2.map容器内元素的访问
        1.通过下标访问
          和访问普通数组一样,如对一个定义为map<char , int> mp的map来说 ,就可以直接mp['c'] = 20来访问20。键是唯一的。
        2.通过迭代器访问
          map迭代器的定义: map<typename1 , typename2>::iterator it;
          map迭代器是使用方式和其他STL容器不同,因为map的每一对映射都有两个typename,这就决定了必须能通过一个it来同时访问键和值。所以可以用it->first来访问键,it->second来访问值。
          map会以键从小到大的顺序自动排序,这点和set一样
        3.常用函数
          1.find(key)  //返回键为key的映射的迭代器,时间复杂度为O(logN).
          2.erase()
            1.删除单个元素   
              mp.erase(it),it为需要删除的元素的迭代器,时间复杂度O(1)
              mp.erase(key) , key为想要删除的映射的键,时间复杂度O(logN)
            2.删除一个区间内的所有元素
              mp.erase(first , last),其中first是需要删除区间的歧视迭代器,last是需要删除的区间的末尾迭代器的下一个迭代器,也是左闭右开。时间复杂度O(last - first)
          3.size()  //映射对数
          4.clear()  //清空map中的所有元素,时间复杂度O(logN)
    例题:http://acm.hdu.edu.cn/showproblem.php?pid=2648
    AC代码:
    #include <bits/stdc++.h>
    using namespace std;
    int main()
    {
        int n,m,p;
        map<string,int> shop;
        while(cin>>n)
        {
            string s;
            for (int i = 0; i < n; ++i) cin>>s;
            cin>>m;
            while(m--)
            {
                for (int i = 0; i < n; ++i)
                {
                    cin>>p>>s;
                    shop[s]+=p;
                }
                int rank = 1;
                map<string,int>::iterator it;
                for (it=shop.begin();it != shop.end(); ++it) if(it->second>shop["memory"]) rank++;
                cout<<rank<<endl;
            }
            shop.clear();
        }
        return 0;
    }
     
    8.sort()
      排序函数
      定义形式
        sort(首元素地址(必填),尾元素地址的下一个地址(必填),比较函数(非必填))  //默认为递增排序
        比较函数写法:1.基本数据类型的排序  ,   例子,实现递减排序。
          bool cmp(int a, int b){
            return a > b;  //可以理解为当a > b时把a放在前面
          }
               2.结构体数组的排序。
                也是写一个比较函数,来规定按怎样的形式排序。
               3.容器的排序    
                和基本数据类型的数组的写法大同小异。
     
    9.next_permutation()
      给出一个序列在全排列中的下一个序列。
    例题:求全排列
    int main(){
      
      int a[3] = {1 , 3 , 2};
      sort(a, a+ 3);
      do{
        for(int i = 0 ; i<3 ; i++){
          printf("%d",i);
          printf(" ");
                    }
      }while(next_permutation(a , a + 3));
      return 0;
    }
     
     
    啊啊啊啊啊啊阿,可算写完了,希望对大家有帮助,对自己有帮助!!!
     
     
     

     

            

      

  • 相关阅读:
    6.1 tar:打包备份
    6.3-4 zip、unzip
    6.5 scp:远程文件复制
    S7 Linux用户管理及用户信息查询命令
    7.6 passwd:修改用户密码
    7.2-5 usermod
    DES
    FreeRTOS笔记
    第4章 裸机系统和多任务系统
    第008课_第1个ARM落版程序及引申
  • 原文地址:https://www.cnblogs.com/ZhaoHaoFei/p/11943106.html
Copyright © 2011-2022 走看看