Algorithm20.1 STL map

[TOC]

STL - map

【注意,此处的map是指的c++STL的map,c++STL的map的底层时红黑树,而Java的map的底层是哈希,类似于unordered_map,本质不同】

map底层:红黑树(一种非严格意义上的平衡二叉树)【利用二叉树来进行查询、插入、删除=>O(logn)】map内部所有的数据都是无重复+有序的

map有序性:map的key需要定义operator <。一般的数据类型系统已经确定了(如果是结构体做key的话,需要重载小于号。)

unordered_map底层:hash_value【利用哈希来进行查询、插入、删除=>O(1)】unordered_map内部的数据只保证无重复 (不能保证有序)

unordered_map无重复性:unordered_map需要重载 == ,因为他判断重复就是看 ==。一般的数据类型系统已经确定了(如果是结构体做key的话,需要重载==。)

vector+pair实现:

map与unordered_map VS set与multiset:

map有序,而unordered_map的无序性,但是两者都保持的是key唯一。

set唯一,而multiset不唯一,可重复,但是两者都保持的是有序。

查看是否已经映射

https://www.luogu.com.cn/problem/P1918

#include <iostream>
using namespace std;
#include <map>
map<int, int> mp;
int n, m, t;

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {scanf("%d", &t);mp[t] = i;}
    scanf("%d", &m);
    while (m--) {
        scanf("%d", &t);
        if (mp.count(t)) printf("%d\n", mp[t]);
        else printf("0\n");
    }
    return 0;
}

管理系统映射

https://www.luogu.com.cn/problem/P5266

#include <iostream>
using namespace std;
#include <map>
typedef unsigned long long ull;
map<string, ull> mp;
ull t, tp, score;
string name;

int main() {
    scanf("%lld", &t);
    while (t--) {
        scanf("%lld", &tp);
        if (tp == 1) {
            cin>>name>>score;mp[name] = score;printf("OK\n");
        } else if (tp == 2) {
            cin>>name;
            if (mp.count(name)) printf("%lld\n", mp[name]);
            else printf("Not found\n");
        } else if (tp == 3) {
            cin>>name;
            if (mp.count(name)) {mp.erase(name);printf("Deleted successfully\n");}
            else printf("Not found\n");
        } else printf("%d\n", mp.size());
    }
    return 0;
}

计数映射,直接销毁

https://www.luogu.com.cn/problem/P1684

题目大意:找一个字串中满足移除一定数量之后,满足AABB ABAB ABBA AAAA最多的数量。

思路:能不删就不删,然后只要满足有两种凑够了两个或者有一种凑够了4个,就可以立马将答案+1,然后重置(也就是前面的都不管了)

因而可以利用map进行计数。

#include <iostream>
using namespace std;
#include <map>
int n, t, cnt, ans;
map<int, int> mp;

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &t);
        mp[t]++;
        if (mp[t] == 2) cnt++;
        if (cnt == 2) cnt = 0, ans++, mp.clear();
        if (mp[t] == 4) cnt = 0, ans++, mp.clear();
    }
    printf("%d\n", ans);
    return 0;
}

利用map的key有序性 - (find函数logn复杂度)

https://www.luogu.com.cn/problem/P5250

题目大意:一堆木头(无重复)有放有拿。拿的时候,如果有刚好对应的长度就拿,没有对应的长度,就拿离他最近长度的,如果比他长和比他短的长度一样,那就拿比他短的那个长度的那根。

思路:

1、利用map的key的有序性,来直接用logn的复杂度来找。

2、想快速查到合适的位置,利用map的key的有序性进行(或者利用lowerbound二分来查找合适的位置然后添加进去)

3、如果没有映射到的,那就可以先创建一个映射,找到这个位置的iterator,然后再通过iterator来上下找。

4、注意erase的时候,如果通过迭代器iterator来进行erase(iterator)的话,很容易发生runtime error,也就是数组越界。所以一般通过erase(key)来进行移除。

#include <iostream>
using namespace std;
#include <map>
map<int, int> mp;
int t, tp, ta;

int main() {
    scanf("%d", &t);
    while (t--) {
        scanf("%d%d", &tp, &ta);
        if (tp == 1) {
            if (mp.count(ta)) printf("Already Exist\n");
            else mp[ta] = 1;
        } else {
            if (mp.size() == 0) {printf("Empty\n");}
            else if (mp.count(ta)) {printf("%d\n", ta);mp.erase(ta);}
            else {
                mp[ta] = 1;
                auto iter = mp.find(ta);
                auto iter2 = iter;
                iter++;
                if (iter2 == mp.begin()) {printf("%d\n", iter->first);mp.erase(iter);}
                else if (iter == mp.end()) {printf("%d\n", (--iter2)->first);mp.erase(iter2);}
                else if (ta-(--iter2)->first > iter->first-ta) {printf("%d\n", iter->first);mp.erase(iter);}
                else {printf("%d\n", iter2->first);mp.erase(iter2);}
                mp.erase(ta);
            }
        }
    }
    return 0;
}

unordered_map - 查看是否重复

题意:输出去重之后的

思路:用unordered_map直接判断是否重复。如果重复就不输出。

(注意:对于unordered_map迭代器iterator无法自减,只能自增。然后也不能reverse。如果按照遍历顺序输出map的话,此时得到的是反向的,也就是说他是先进先出的顺序。虽然unordered_map内部是无序的。

#include <iostream>
using namespace std;
int t, n, ta;
#include <unordered_map>
unordered_map<int, int> mp;

int main() {
    scanf("%d", &t);
    while (t--) {
        mp.clear();
        scanf("%d", &n);
        for (int i = 1; i <= n; ++i) {
            scanf("%d", &ta);
            if (mp.count(ta) == 0) printf("%d ", ta);
        }
//        auto iter = mp.begin();
//        while (iter != mp.end()) {
//            printf("%d ", iter->first);
//            iter++;
//        }
        printf("\n");
    }
    return 0;
}
Posted on Feb 1, 2021