种类
- unordered_set (C++11)
- unordered_map (C++11)
- unordered_multiset (C++11)
- unordered_multimap (C++11)
上述四种容器采用哈希表实现。
不同操作的时间复杂度为:
插入:O(1),最坏情况O(N)。
查询:O(1),最坏情况O(N)。
删除:O(1),最坏情况O(N)。
记住,如果你采用合适的哈希函数,你可能永远不会看到最坏情况。
操作汇总
unordered_set
例子:
#include <unordered_set>
#include <iostream>
namespace ClassFoo{
void PrintIntDoubleUnOrderedSet(std::unordered_set<int>& m, char* pre) {
std::unordered_set<int>::iterator it;
std::cout << pre;
for ( it = m.begin(); it != m.end(); it++ )
std::cout << *it << " ";
std::cout << std::endl;
}
void UnOrderedSetExample1() {
std::unordered_set<int> foo1;
// 普通插入
foo1.insert(1);
// 带暗示插入,std::pair<int,double>等价于上述的
// std::unordered_set<int,double>::value_type
foo1.insert(foo1.end(),2);
// 插入一个范围
std::unordered_set<int> foo2;
foo2.insert(3);
foo2.insert(4);
foo2.insert(5);
foo1.insert(foo2.begin(),foo2.end());
PrintIntDoubleUnOrderedSet(foo1,"插入元素后的foo1:");
// 查找主键4
std::unordered_set<int>::iterator it;
it = foo1.find(4);
if( it != foo1.end() )
{
std::cout << "foo1.find(4):";
std::cout << *it << std::endl;
}
// 删除上述找到的元素
if( it != foo1.end() )
{
foo1.erase(it);
}
PrintIntDoubleUnOrderedSet(foo1,"删除主键为4的元素后的foo1:");
// 遍历删除主键为2的元素
for(it = foo1.begin();it != foo1.end();it++)
{
//遍历删除主键等于2
//注意,删除元素会使迭代范围发生变化
if ( *it == 2 )
{
foo1.erase(it);
break;
}
}
// 内部数据
std::cout << "bucket_count:" << foo1.bucket_count() << std::endl;
std::cout << "max_bucket_count:" << foo1.max_bucket_count() << std::endl;
std::cout << "bucket_size:" << foo1.bucket_size(0) << std::endl;
std::cout << "load_factor:" << foo1.load_factor() << std::endl;
std::cout << "max_load_factor:" << foo1.max_load_factor() << std::endl;
PrintIntDoubleUnOrderedSet(foo1,"删除主键为2的元素后的foo1:");
foo1.clear();
PrintIntDoubleUnOrderedSet(foo1,"清空后的foo1:");
}
}
int main( )
{
ClassFoo::UnOrderedSetExample1();
return 0;
}
unordered_map
// num2pos是unordered_map
#include<iostream>
#include<stdlib.h>
#include<vector>
#include<unordered_map>
using namespace std;
class RandomizedSet {
public:
RandomizedSet() {}
bool insert(int val) {
// 判断key=val是否存在
if(num2pos.count(val)) return false;
nums.push_back(val);
num2pos[val] = nums.size() - 1;
return true;
}
bool remove(int val) {
if(!num2pos.count(val)) return false;
int last = nums.back();
num2pos[last] = num2pos[val];
nums[num2pos[val]] = last;
nums.pop_back();
// 删除key=val
num2pos.erase(val);
return true;
}
int getRandom() {
return nums[rand() % nums.size()];
}
private:
vector<int> nums;
unordered_map<int, int> num2pos;
};
int main() {
RandomizedSet obj;
bool param_1 = obj.insert(1);
bool param_2 = obj.remove(1);
bool param_4 = obj.insert(2);
int param_3 = obj.getRandom();
cout<<param_3<<endl;
return 0;
}
#include <iostream>
#include <unordered_map>
#include <string>
int main(int argc, char **argv) {
std::unordered_map<int, std::string> map;
map.insert(std::make_pair(1, "Scala"));
map.insert(std::make_pair(2, "Haskell"));
map.insert(std::make_pair(3, "C++"));
map.insert(std::make_pair(6, "Java"));
map.insert(std::make_pair(14, "Erlang"));
if(map[14] != "Erlang") return 1;
std::unordered_map<int, std::string>::iterator it;
if ((it = map.find(6)) != map.end()) {
std::cout << it->second << std::endl;
}
return 0;
}
#include <iostream>
#include <map>
using namespace std;
int main() {
map<int,string> student;
student.insert(pair<int,string>(2,"li"));
student.insert(pair<int,string>(1,"wang"));
student.insert(pair<int,string>(3,"sun"));
for(auto &v : student) // for(auto v : student)也是可以的
cout<<"key: "<<v.first<<" | value: "<<v.second<<endl;
return 0;
}
以unordered_map为例讲解(unordered_set…同理)
map
内部数据的组织,基于红黑树实现,红黑树具有自动排序的功能,因此map内部所有的数据,在任何时候,都是有序的。hash_map(非标准,以后用就用unordered_map)
基于哈希表,数据插入和查找的时间复杂度很低,几乎是常数时间,而代价是消耗比较多的内存。底层实现上,使用一个下标范围比较大的数组来存储元素,形成很多的桶,利用hash函数对key进行映射到不同区域进行保存。
插入操作:得到key -> 通过hash函数得到hash值 -> 得到桶号(hash值对桶数求模) -> 存放key和value在桶内
取值过程:得到key -> 通过hash函数得到hash值 -> 得到桶号(hash值对桶数求模) -> 比较桶内元素与key是否相等 -> 取出相等纪录的value
当每个桶内只有一个元素时,查找时只进行一次比较,当很多桶都没有值时,查询更快。
用户可以指定自己的hash函数与比较函数。unordered_map
C++ 11标准中加入了unordered系列的容器。unordered_map记录元素的hash值,根据hash值判断元素是否相同。map相当于java中的TreeMap,unordered_map相当于HashMap。无论从查找、插入上来说,unordered_map的效率都优于hash_map,更优于map;而空间复杂度方面,hash_map最低,unordered_map次之,map最大。
速度:unordered_map>hash_map>map
注意:对于STL里的map容器,count方法与find方法,都可以用来判断一个key是否出现,count统计的是key出现的次数,因此只能为0/1,而find基于迭代器实现,以mp.end()判断是否找到要求的key。