oi-wiki
Version:
wiki for OI / ACM-ICPC
102 lines (62 loc) • 3.56 kB
Markdown
### `map` 是啥鬼?
`map` 是利用红黑树实现的。
当你在写程序的时候,可能需要存储一些信息,例如存储学生姓名对应的分数,例如:`Tom 0`,`Bob 100`,`Alan 100`。
但是由于数组下标只能为非负整数,所以无法用姓名来存储,这个时候最简单的办法就是使用 STL 的 `map` 了!
`map` 可任意类型为下标(在 `map` 中叫做 `key`,也就是索引),下面是 `map` 的模型:
```cpp
map <类型名,类型名> 你想给map起的名字
```
其中两个类型名第一个是 `key`(索引,可以理解为数组的下标),第二个是 `value`(对应的元素)。例如上面的例子,我们可以这样的存储:
```cpp
map <string,int> mp
```
是不是感觉很神奇?
### `map` 具体怎么使用?
- `map` 添加元素
1. 直接存,例如 `mp["Tom"]=0`
2. 通过插入,例如 `mp.insert(pair<string,int>("Alan",100));`
3. 初始化( C++11 及以上)和数组差不多:
```cpp
map <string,int> mp= {
{"Tom",0},
{"Bob","100"},
{"Alan",100}};
```
- `map` 查找删除元素
1. 在你知道查找元素是啥的时候直接来就可以了,例如:`int grade=mp["Tom"]`
2. 如果你知道了元素的下标,但是想知道这个元素是否已经存在 `map` 中,可以使用 `find` 函数。
格式:`if(mp.find()==mp.end())`,意思是是否返回的是 `map` 的末尾,因为 `map` 如果没有查找到元素,迭代器会返回末尾。
其中 `mp.end()` 返回指向 map 尾部的迭代器, 另外 也可以用 `mp.count(__key) != 0` 来判断
3. 如果你想知道 map 里全部的元素,那么最正确的做法使用迭代器了,如果你还不会,请查阅之前文章中的迭代器。
```cpp
for(iter=mp.begin();iter!=mp.end();iter++)
cout<<iter->first<<" "<<iter->second<<endl;
```
其中 `mp.begin()` 返回指向 `map` 头部的迭代器
当然,如果使用 C++11 (及以上)你还可以使用 C++11 的新特性 ,如下
```cpp
for(auto &i : mp) {
printf("Key : %d, Value : %d\n", i.first, i.second);
}
```
`iter->first` 是 `key` 索引,例如 `Tom`,而 `iter->second` 是 `value`。
如果你想删除 `Tom` 这个元素,则可以利用 `find` 函数找到 `Tom` ,然后再 `erase` 如下
```cpp
map<string, int> :: iterator it;
it = mp.find("Tom");
mp.erase(it)
```
如果你想清空所有的元素,可以直接 `mp.clear()`
- 其他
我们刚才介绍了最常用的,下面是其他比较常用的:
- `count()` 返回指定元素出现的次数 ,例如 `mp.count()`
- `swap()` 可以交换两个 `map` ,例如 `swap(m1,m2)`
- `size()` 返回 `map` 中元素的个数
- `empty()` 如果 `map` 为空则返回 `true`,例如 `mp.empty()`。
### `map` 常数靠得住吗?
一般情况下是可以的。无论查询,插入,删除的复杂度都是 $O(\log N)$,遍历是 $O(N)$。
不过有的时候不会满足啊!我只想查询元素,插入元素,但是时间不够咋办?请往下看!
- 由于 NOIP 不资瓷吸氧(开启 O2 优化),所以 NOIP 要注意是否会被卡
### 更快:基于 `Hash` 实现的 `map`!
这个 `map` 的名字就是 `unordered_map` 了,它的查询,插入,删除的复杂度几乎是 $O(1)$ 级别(不过最坏会达到 $O(N)$)的!所有的操作几乎和 `map`一样(注意 `unordered_map` 用迭代器遍历是无序的)。
不过它的遍历速度会很慢,而且空间占用的会更大。