@lychee123
2017-08-17T02:32:35.000000Z
字数 1595
阅读 1644
STL
STL中无序容器主要有unordered_set和unordered_map,其主要的功能和set与map差不太多,最大的特点就是其中的关键值是无序的,但是基本上所有的操作都是常数复杂度的。其内部主要是由哈希表实现,所以构造和析构的速度比有序容器稍慢。
以unordered_map为例
- begin 返回指向容器第一个元素的迭代器,但并不是最小的哈。注意map和unordered_map的迭代器都是指向一个pair的
- end 返回指向容器尾端的迭代器,这两个迭代器的返回,主要是用于遍历整个unordered_map
- empty 检查容器是否为空
- size 返回容纳的元素数
- clear 删除全部内容
- insert 插入元素。注意map和unordered_map的插入,都是插入一个pair
- emplace 就地构造元素,和insert功能相似,但是是直接给构造函数传参数。emplace在C++11 STL中基本上都能使用
- erase 删除元素,可以删除关键值,也可以删除迭代器
- []操作符,和map的[]操作符相同,返回的为引用值,可以被修改。注意使用[]的时候,如果[]的关键值在容器中不存在,则会插入该关键值,对应的映射值为默认值。如果随意的使用[],回造成大量的插入操作,减慢运行速度,甚至会造成MLE
- count 返回匹配特定键的元素数量, 返回值一定是0或者1,在不知道关键值是否存在的情况下,可以先count一下,再使用[]
- find 寻找带有特定键的元素的迭代器
由于unordered_map内部使用hash表,所以对于关键值,必须要存在hash函数和判等运算符。好在系统已经内置了所有基础数据类型和string的hash函数和判等运算符。可以直接把他们作为关键值。对于其他类型,暂不予讨论。
unordered_map是C++11新加入的标准容器,所以需要编译器有-std=gnu++11选项。除了#include无需包含其他的头文件。
以PowerOJ2436为例。
C++11代码:
#include<bits/stdc++.h>using namespace std;int main(){int n;while (~scanf("%d", &n)){int cnt = 0;unordered_map<string, int> m;while (n--){char s[12];scanf("%s", s);auto it = m.find(s);\\这里隐式调用了string的构造函数int ans;if (it == m.end())m[s] = ans = ++cnt;\\这里也隐式调用了string的构造函数elseans = it->second; \\迭代器指向的是pair<string,int>printf("%d\n", ans);}}return 0;}
但是并不是没有C++11就没法用这个容器了,需要包含tr1中的头文件和使用命名空间。
C++98代码:
#include<bits/stdc++.h>#include<tr1/unordered_map> \\在tr1库中有这个容器using namespace std;using namespace std::tr1; \\需要使用这个命名空间int main(){int n;while (~scanf("%d", &n)){int cnt = 0;unordered_map<string, int> m; \\其他操作和C++11的无区别,只是没有了emplacewhile (n--){char s[12];scanf("%s", s);unordered_map<string, int>::iterator it = m.find(s);int ans;if (it == m.end())m[s] = ans = ++cnt;elseans = it->second;printf("%d\n", ans);}}return 0;}