STL学习与使用

STL

vector
基础知识
  • #include < vector>
  • using std::vector;
  • vector< T> v;//定义空的动态数组
  • vector< T> v(num, value); //定义一个长度为num,每一个元素初值都是value的动态数组
  • v.push_back(value);//插入value
  • v.pop_back(); //删除一个元素
  • v.clear(); 清空动态数组
  • v.size();返回动态数组的长度
  • vector< vector< int > > vec;//定义二维的动态数组
  • vector<vector< int> > vec(n, vector< int>(m, 0)); //二维动态数组定义并初始化为全0
练手
  1. 打印乘法表

    #include <iostream>
    #include <vector>
    using namespace std;
    int main()
    {
        vector<vector<int> > v2d;
        for (int i = 0; i < 5; i++)
        {
            v2d.push_back(vector<int>());
        }
        for (int i = 0; i < v2d.size(); i++)
        {
            for (int j = 0; j <= i; j++)
            {
                v2d[i].push_back((i + 1) * (j + 1));
            }
        }
        for (int i = 0; i < v2d.size(); i++)
        {
            for (int j = 0; j < v2d[i].size(); j++)
            {
                cout << i + 1 << " * " << j + 1 << " = "
                    << v2d[i][j] << "\t";
            }
            cout << endl;
        }
        return 0;
    }
    /*
    1 * 1 = 1
    2 * 1 = 2       2 * 2 = 4
    3 * 1 = 3       3 * 2 = 6       3 * 3 = 9
    4 * 1 = 4       4 * 2 = 8       4 * 3 = 12      4 * 4 = 16
    5 * 1 = 5       5 * 2 = 10      5 * 3 = 15      5 * 4 = 20      5 * 5 = 25
    */
    
set
知识
  • #include < set>
  • using namespace std::set;
  • 集合中的元素要求互异性。
  • 插入元素用insert(),如果集合中已经存在了某个元素,再次插入不会产生任何效果。
  • 判断某个元素是否在集合里,可以用count()函数,存在返回1,否则返回0。
  • 遍历要用迭代器。通过* 解引用可以获取迭代器指向的元素。set< T>::iterator it;
  • erase();可以删除元素
  • clear()可以清空set,而且会清空内存。
  • set中插入、删除、查找时间复杂度都是 O ( l o g n ) O(log n) O(logn),且内部元素是有序的。但自定义的结构体,需要自行重载<运算符。
练手
#include <iostream>
#include <set>
using namespace std;

struct Point
{
    int x, y;
    bool operator<(const Point &rhs) const
    {   //rhs:right hand side右操作数
        //后面这个const表示不能对其数据成员进行修改,并且const对象只能调用const成员函数
        if (x == rhs.x)
        {
            return y < rhs.y;
        }
        return x < rhs.x;
    }
};

int main()
{
    int n;
    set<Point> v;
    cin >> n;
    for (int i = 0; i < n; i++)
    {
        Point temp;
        cin >> temp.x >> temp.y;
        v.insert(temp);
    }
    for (set<Point>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << it->x << " " << it->y << endl;
    }
    return 0;
}
/*
输入:
6
5 6
5 2
2 1
3 4
1 2
1 1
输出:
1 1
1 2
2 1
3 4
5 2
5 6
*/
map
知识
  • map是映射,通过key可以找value

  • insert()函数向集合中插入新的映射,参数是一个pair

  • pair: 在头文件utility中,可以看作两个成员变量first和second的结构体,重载了<运算符,先比较first,再比较second。

    pair<string, int> p;

  • make_pair(v1, v2)函数返回由v1和v2初始化的pair,类型可以从v1和v2的类型推断出来。

  • 插入时,如果插入的key之前已经存在,将不会用插入的新的value替代原来的value,插入无效。

  • 访问映射和数组一样,用[]就能访问。如果没有对[]里的key做过映射的话,系统会自动生成一个映射,value是对应类型的默认值。insert无法完成更改,但[]可以给映射赋予新的值。但有时我们不希望自动生成映射,就需要用count()函数进行判断是否已有映射。

  • map<T1, T2>::iterator it可以定义一个迭代器。迭代器指向的是一个pair,有first和second。

    it -> first 和 (*it).first效果是一样的。

  • 遍历map是按照关键字从小到大遍历的,和set类似。

  • clear()可清空map和其占用的内存。

  • map的insert()和count都是O(log n)的,size()获取映射对个数是O(1)的,clear()是O(n)的。

练手
  1. 嵌套,两层的时候,遍历定义的两个迭代器

    #include <iostream>
    #include <string>
    #include <map>
    
    using namespace std;
    
    int main()
    {
        map<int, map<string, int> > info;
        int n;
        cin >> n;
        for (int i = 0; i < n; i++)
        {
            int class_id;
            string name;
            cin >> class_id >> name;
            info[class_id][name]++;
        }
        for (map<int, map<string, int> >::iterator it = info.begin(); it != info.end(); it++)
        {
            for (map<string, int>::iterator it2 = it->second.begin(); it2 != it->second.end(); it2++)
            {
                cout << "There are " << it2->second << " people named "
                    << it2->first << " in class " << it->first << endl;
            }
        }
        return 0;
    }
    /*
    输入:
    6
    1 zgh
    2 yuhaoran
    2 yuhaoran
    1 party
    100 xxxx
    50 xxxx
    输出:
    There are 1 people named party in class 1
    There are 1 people named zgh in class 1
    There are 2 people named yuhaoran in class 2
    There are 1 people named xxxx in class 50
    There are 1 people named xxxx in class 100
    */
    
  2. 锯齿矩阵:每一行元素个数不相同的矩阵,现在在某些行的末尾插入某些元素。

    #include <iostream>
    #include <vector>
    using namespace std;
    vector<int> mat[10005];
    int main()
    {
        int n, m, x, y;
        cin >> n >> m;
        for (int i = 0; i < m; i++)
        {
            cin >> x >> y;
            mat[x].push_back(y);
        }
        for (int i = 1; i <= n; i++)
        {
            for (int j = 0; j < mat[i].size(); j++)
            {
                if (j != mat[i].size() - 1)
                {
                    cout << mat[i][j] << " ";
                }else
                {
                    cout << mat[i][j] << endl;
                }
            }
            if (mat[i].size() == 0)
                cout << endl;
        }
        return 0;
    }
    /*
    输入:
    3 12
    1 3
    2 2
    2 3
    2 4
    3 1
    3 6
    1 5
    1 2
    1 6
    3 2
    3 7
    1 1
    输出:
    3 5 2 6 1
    2 3 4
    1 6 2 7
    */
    
  3. 对比两个结构体是否相同,样本库应该是互不相同的,用set

    #include <iostream>
    #include <set>
    
    using namespace std;
    
    struct people
    {
        int h;
        int w;
        int age;
        people(int _h, int _w, int _age)
        {
            h = _h;
            w = _w;
            age = _age;
        }
        bool operator<(const people &rhs) const
        {
            if(h != rhs.h)
                return h < rhs.h;
            if (w != rhs.w)
                return w < rhs.w;
            return age < rhs.age;
        }
    };
    set<people> s;
    int main()
    {
        int n, m, h, w, age;
        cin >> n >> m;
        for (int i = 0; i < n; i++)
        {
            cin >> h >> w >> age;
            s.insert(people(h, w, age));
        }
        for (int i = 0; i < m; i++)
        {
            cin >> h >> w >> age;
            if (s.count(people(h, w, age)))
            {
                cout << "yes" << endl;
            }
            else
            {
                cout << "no" << endl;
            }
        }
        return 0;
    }
    /*
    输入:
    3 2
    166 50 30
    178 60 23
    132 40 15
    167 50 30
    178 60 23
    输出:
    yes
    */
    
  4. 输出不同书籍的数量,按照字典序。显然可以用map,map本身就是排好序的。

    #define _CRT_SECURE_NO_WARNINGS
    #include <iostream>
    #include <map>
    #include <string>
    #include <cstdio>   //10^5以上的输入就要用scanf
    using namespace std;
    map<string, int> mp;
    char name[105];
    int main()
    {
        int n;
        scanf("%d", &n);
        for (int i = 0; i < n; i++)
        {
            scanf("%s", name);  //string类型不能直接scanf %s,但可以用c_str()转为c字符串;但机制很奇怪,很容易出错,所以用scanf就用char数组
            mp[name]++; //map用[]访问,如果没有初始化为默认值
        }
        printf("%d\n", mp.size());
        for (map<string, int>::iterator it = mp.begin(); it != mp.end(); it++)
        {
            printf("%s %d\n", (it->first).c_str(), it->second);
        }
        return 0;
    }
    /*
    4
    English
    Math
    Chinese
    Chinese
    3
    Chinese 2
    English 1
    Math 1
    */
    
  5. 移动积木,本来n个位置上分别放着编号1-n的积木,然后进行m次操作a,b,每次将b的积木整体移动到a上。如果a,b相等,则不移动。

    #define _CRT_SECURE_NO_WARNINGS
    #include <cstdio>
    #include <vector>
    using namespace std;
    vector<int> v[10005];
    int main()
    {
        int n, m, a, b;
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++)
        {
            v[i].push_back(i);
        }
        for (int i = 0; i < m; i++)
        {
            scanf("%d%d", &a, &b);
            if (a == b)
                continue;
            for (int j = 0; j < v[b].size(); j++)
            {
                v[a].push_back(v[b][j]);
            }
            vector<int>().swap(v[b]);
        }
        for (int i = 1; i <= n; i++)
        {
            for (int j = 0; j < v[i].size(); j++)
            {
                if (j != v[i].size()-1)
                {
                    printf("%d ", v[i][j]);
                }
                else
                {
                    printf("%d", v[i][j]);
                }
            }
            printf("\n");
        }
        return 0;
    }
    /*
    输入:
    4 4
    3 1
    4 3
    2 4
    2 2
    输出:
    2 4 3 1
    */
    
  6. 求两个集合的并集。

    #define _CRT_SECURE_NO_WARNINGS
    #include <cstdio>
    #include <set>
    
    using namespace std;
    set<int> s;
    int main()
    {
        int n, m, x, cnt = 0;
        scanf("%d%d", &n, &m);
        for(int i = 0; i < n + m; i++)
        {
            scanf("%d", &x);
            s.insert(x);
        }
        for(set<int>::iterator it = s.begin(); it != s.end(); it++)
        {
            if (cnt != s.size() - 1)
            {
                printf("%d ", (*it));
                cnt++;
            }
            else
            {
                printf("%d\n", (*it));
            }
        }
        return 0;
    }
    /*
    输入:
    1 2
    1
    2 3
    输出:
    1 2 3
    */
    
  7. 输入n:表示事件数;n行整数d和单词word:d=0表示记住该单词,d=1表示询问是否认识该单词。(大小写等价)\

    #include <cstdio>
    #include <set>
    #include <string>
    #include <iostream>
    
    using namespace std;
    set<string> s;
    string ss;
    int main()
    {
        int n, op;
        cin >> n;
        for (int i = 0; i < n; i++)
        {
            cin >> op >> ss;
            for (int j = 0; j < ss.size(); j++)
            {
                if(ss[j] >= 'A' && ss[j] <= 'Z')
                {
                    ss[j] = 'a' + (ss[j] - 'A');
                }
            }
            if (op == 0)
            {
                s.insert(ss);
            }
            else
            {
                if (s.count(ss))
                {
                    cout << "Yes" << endl;
                }
                else
                {
                    cout << "No" << endl;
                }
            }
        }
        return 0;
    }
    /*
    输入:
    4
    1 jisuanke
    0 Jisuanke
    0 JISUANKE
    1 JiSuanKe
    输出:
    No
    Yes
    */
    
  8. 输出出现次数最多的数和出现的次数。如果有多个最大次数的数,输出值最大的那个。

    #include <iostream>
    #include <string>
    #include <map>
    using namespace std;
    
    map<string, map<string, int > > mp;
    string s1, s2;
    int d;
    int main()
    {
        int n;
        cin >> n;
        for (int i = 0; i < n; i++)
        {
            cin >> s1 >> s2 >> d;
            mp[s2][s1] += d;
        }
        for (map<string, map<string, int> >::iterator it1 = mp.begin(); it1 != mp.end(); it1++)
        {
            cout << (it1->first) << endl;
            for(map<string, int>::iterator it2 = (it1->second).begin(); it2 != (it1->second).end(); it2++)
            {
                cout << "   |----" << (it2->first) << "(" << (it2->second) << ")" << endl;
            }
        }
        return 0;
    }
    /*
    输入:
    5
    apple shandong 3
    pineapple guangdong 1
    sugarcane guangdong 1
    pineapple guangdong 3
    pineapple guangdong 1
    输出:
    guangdong
       |----pineapple(5)
       |----sugarcane(1)
    shandong
       |----apple(3)
    */
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值