• map && multimap


    map

    map 的意思是映射。用法一般是

                     map<char, int>mp

    按照我的理解,map 类似于一个高级的数组。前面的数据类型 char 相当于下脚标,而数组元素的值就对应着后面的类型 int。例如可以用一个 map<string, int>month_name 来表示“月份名字对应的月份编号“。然后用 month_name["july"] = 7 这样的方式来赋值。所以说,”高级的数组“指下脚标和元素类型可以是任意数据类型的(当然包括结构体)。

    接下来说说基本操作

    1.声明,赋值

    除了上面已经讲过的像数组元素那样赋值的方法, 还支持这样 mp.insert(make_pair(”july“, 7)); (不过当然是上面的方法简单)

    2.查找

    和 set 很像:if (mp.find('f') == mp.end()) ......,若找不到,就执行 if 里面的语句。(找的是下脚标,不是元素的值)

    3. 输出大小

    同理 set :mp.size()

    4.遍历

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 map<char, int>mp;
     4 int main()
     5 {
     6     for (int i = 0; i < 5; i++) mp['a' + i] = i;
     7     for (map<char, int>::iterator it = mp.begin(); it != mp.end(); ++it)
     8         printf("%c %d
    ", it -> first, it -> second);
     9     /*若嫌麻烦,也可在前面用 typedef 改个名,以后遍历就不用写一串了
    10     typedef map<char, int>::iterator mcit;
    11     for(mcit it = mp.begin(); it != mp.end(); ++it) */
    12     return 0;
    13 }

    输出:

    a 0

    b 1

    c 2

    d 3

    e 4

    还有 first 就是指“下脚标”, second 指”数组元素值“。

    5.删除

    和 set 一样

    mp.erase('f');  或  map<char, int>::iterator it = mp.find('f'); mp.erase(it);

    6. lower_bound() 和 upper_bound()

     map<char, int>::iterator it1 = mp.lower_bound('f'); printf("%c %d ", it1->first, it1->second); 就这样

    7.!注意 !

    看这段代码

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 map<char, int>mp;
     4 int main()
     5 {
     6     for (int i = 0; i < 5; i++) mp['a' + i] = i;
     7     cout << mp['z'] << endl;
     8     for (map<char, int>::iterator it = mp.begin(); it != mp.end(); ++it)
     9         printf("%c %d
    ", it -> first, it -> second);
    10     return 0;
    11 }

    在第7行,我们发现 mp['z'] 根本没有,然而这是能过编译的!而且输出时,结果是这样的:

    0

    a 0

    b 1

    c 2

    d 3

    e 4

    z 0

    可见 mp['z'] 的值是0。而且这个 mp['z'] 也被自动添加到了 mp 中,看来c++是自己在 mp 中创建了一个 mp['z']。所以我们凡是要对 map 进行操作时,都要首先确认这个元素是否存在,否则就会出现这些像意想不到的错误。

    multimap

    multimap的用法几乎map一样,唯一不同的是,它里面的元素是可以重的。

    所以两种删除方法在这里就不一样了:

    1.mp.erase('f'):删除multimap中所有以'f'为下标的元素。

    2. map<char, int>::iterator it = mp.find('f'); erase(it):只删除第一个‘’f.

    应用

    1.map可以代替hash

      虽然复杂度多了一个log,但是在时间充裕而且代码比较长的情况下,用map写就显得极为方便。

      举一个很水的例子:洛谷P3370 【模板】字符串哈希

     1 #include<cstdio>
     2 #include<string>
     3 #include<map>
     4 using namespace std;
     5 
     6 map<string, bool> mp;
     7 int n, cnt = 0; 
     8 char s[1505];
     9 
    10 int main()
    11 {
    12     scanf("%d", &n);
    13     for(int i = 1; i <= n; ++i)
    14     {
    15         scanf("%s", s);
    16         if(!mp[s]) mp[s] = 1, cnt++;
    17     }
    18     printf("%d
    ", cnt);
    19     return 0;
    20 }
    View Code

    2.解决一些比较麻烦的记录问题

      如果你看不懂这个标题在说啥,说明语文学得不好。不管了,直接上题:家谱

      这道题确实是并查集水题,但是我们要记录出现过的字符串,这时候就是map大显神威的时候了。我这篇博客里讲的挺细的,简单易懂。

      不过里面可以不用string类型输入,而用字符数组,只不过map的类型是map<string, int>。

    3.优!化!

      别看map带一个log,但在某些情况下还能优化!

      [九省联考2018]一双木棋chess

      没错,去年的辽宁省选Day1T1。

      解法是对抗搜索,但这不是我们今天的重点。

      暴力的搜索还要判断每一行的状态,多了一层复杂度,导致后几个点TLE。如果把状态压成一个数的话不仅数组装不下,int都会爆。因此我们把表示状态的long long当成map的下标,然后找状态的时候时间复杂度成功降到了logn。虽然不是最优的,但是AC已经绰绰有余了。最重要的是,这个优化也别好想,随手就是一加。

    放个代码吧(有人是不是想c-c + c-v瞬间A题)

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<cstdlib>
     5 #include<cstring>
     6 #include<algorithm>
     7 #include<map>
     8 using namespace std;
     9 typedef long long ll;
    10 const int maxn = 15;
    11 //mrclr
    12 
    13 struct Node
    14 {
    15   int x, y;      
    16 }a[maxn][maxn];
    17 struct Node2
    18 {
    19   int xx, yy, cha2;
    20   bool operator < (const Node2& other)const
    21   {
    22     return cha2 < other.cha2; 
    23   }
    24 };
    25 int n, m;
    26 const int INF = 0x3f3f3f3f;
    27 struct Node3
    28 {
    29     int a[maxn];
    30     ll encode()const
    31     {
    32         ll ret = 0;
    33         for(int i = 1; i <= n; ++i) {ret |= a[i]; ret <<= 5;}
    34         return ret;  
    35     }
    36     
    37 }chess;
    38 map<ll, int> mpMax, mpMin;
    39 int Minsearch(const Node3& chess);
    40 int Maxsearch(const Node3& chess)
    41 {
    42     if(chess.a[n] == m) return 0;
    43     if(mpMax.find(chess.encode()) != mpMax.end()) return mpMax[chess.encode()];
    44     int Max = -INF;
    45     for(int i = 1; i <= n; ++i)
    46         if(chess.a[i] < chess.a[i - 1])
    47         {
    48             Node3 _ch = chess;
    49             _ch.a[i]++;
    50             Max = max(Max, a[i][_ch.a[i]].x + Minsearch(_ch));             
    51         }
    52     return mpMax[chess.encode()] = Max;
    53 }
    54 int Minsearch(const Node3& chess)
    55 {
    56     if(chess.a[n] == m) return 0;
    57     if(mpMin.find(chess.encode()) != mpMin.end()) return mpMin[chess.encode()];
    58     int Min = INF;
    59     for(int i = 1; i <= n; ++i)
    60         if(chess.a[i] < chess.a[i - 1])
    61         {
    62             Node3 _ch = chess;
    63             _ch.a[i]++;
    64             Min = min(Min, -a[i][_ch.a[i]].y + Maxsearch(_ch));             
    65         }
    66     return mpMin[chess.encode()] = Min;
    67 }
    68 int main()
    69 {
    70   scanf("%d%d", &n, &m);
    71   for(int i = 1; i <= n; ++i)
    72     for(int j = 1; j <= m; ++j) scanf("%d", &a[i][j].x);
    73   for(int i = 1; i <= n; ++i)
    74     for(int j = 1; j <= m; ++j) scanf("%d", &a[i][j].y);
    75   for(int i = 1; i <= n; ++i) chess.a[i] = 0;
    76   chess.a[0] = m;
    77   printf("%d
    ", Maxsearch(chess)); 
    78   return 0;
    79 } 
    View Code

    map讲到这里就算讲完了,如果有更好的用法,欢迎在下面评论,或者当面diss mrclr。

  • 相关阅读:
    写出结构优雅代码的4个技巧
    ABP 调用swagger里面的登录接口报错400,/api/TokenAuth/Authenticate ,调用post接口就报错400
    FreeRTOS的任务优先级测试
    Freertos的队列的具体实现
    嵌入式实时操作系统和NVIC
    ARM在gcc下面的汇编指令片段解析
    手写的一个兼容到ie6的提示更换浏览器的提示框
    ie低版本的一些兼容性问题
    Linux Docker实战目录
    Linux安装jdk和配置环境变量
  • 原文地址:https://www.cnblogs.com/mrclr/p/8410709.html
Copyright © 2020-2023  润新知