参考《C++ STL中哈希表 hash_map介绍》即可。博主写的很详细。
注: hash_map 不是标准的。笔者写该文档时本来想尝试些一个 hash_map 例程,但发现自己用 Qt + MSVC2010 编译器出现了编译错误。网上原因好像说是 STL 加入标准C++之时,hash_map系列当时还没有完全实现,所以很多平台上虽然安装了 g++ 编译器,但不一定有 hash_map 的实现。所以如果有平台移植的内容,尽量少用 hash_map。
以下内容翻译自《unordered_map - C++ Reference》。
template < class Key, // unordered_map::key_type
class T, // unordered_map::mapped_type
class Hash = hash<Key>, // unordered_map::hasher
class Pred = equal_to<Key>, // unordered_map::key_equal
class Alloc = allocator< pair<const Key,T> > // unordered_map::allocator_type
> class unordered_map;
unordered_map 是一种关联容器,用于存储由关键值 (Key Value,以下称为Key 值) 和映射值 (Mapped Value,以下称为映射值) 组成的元素,并且允许根据其 Key 值快速检索各个元素。 在 unordered_map 容器中,Key 值通常用来唯一标识元素,映射值是与该 Key 值关联内容的对象。Key 值与映射值的类型可能不同。 在 unordered_map 内部,元素没有按照其 Key 值与映射值的任何顺序进行排序 ,而是根据它们的 Hash 值组织成桶,允许它们通过其 Key 值直接快速访问单个元素(通常具有常数等级的平均时间复杂度)。 unordered_map 容器与 map 容器相比,通过 Key 值访问各个元素的速度更快,然而通过其元素子集进行范围迭代的效率通常较低。 unordered_map 实现了直接访问操作符 (operator[]),它允许使用 Key 值作为输入参数,直接访问映射值。 容器中的迭代器至少是前向迭代器。
hash <Key>
,它返回一个碰撞概率接近于1.0/std::numeric_limits<sizet>::max()1.0 / std::numeric\_limits <size_t>::max() 的 Hash 值。equal_to <Key>
,它返回与等号运算符 operator(a==b) 相同的值。在 unordered_map 成员函数的参考中,模板函数假定了相同的名称:Key, T, Hash, Pred, Alloc。 unordered_map 容器元素的迭代器可以访问 Key 值与映射值。为此 unordered_map 定义了一个对应的类 value_type,它的第一个值对应于 Key 值类型的常量版本,第二个值对应于映射值(即模板参数 T):
typedef pair<const Key, T> value_type;
unordered_map 容器的迭代器指向该 value_type 的元素。因此对于一个调用 value_type 的迭代器而言,迭代器指向 unordered_map 的一个元素,它的 Key 值与映射值可以分别用下面的方式进行访问:
unordered_map<Key,T>::iterator it;
(*it).first; // the key value (of type Key)
(*it).second; // the mapped value (of type T)
(*it); // the "element value" (of type pair<const Key,T>)
当然可以用任何其他的直接访问运算符,如 -> 或 []。例程如下:
it->first; // same as (*it).first (the key value)
it->second; // same as (*it).second (the mapped value)
以下内容译自《unordered_map::bucket - C++ Reference》
原型
size_type bucket ( const key_type& k ) const;
说明 定位元素所在的桶,返回 Key 值为输入参数 k 的元素的所在桶号。 桶是容器内部 Hash 表中的一个槽,槽中的元素根据 Key 值分配元素。桶号的编号从 0 到 (bucket_count - 1)。 桶中单个元素可以通过 unordered_map::begin 和 unordered_map::end 返回的范围迭代器进行访问。
例程 下面例程片段摘自后面的程序示例:
for (auto& x : mymap3) {
std::cout << "Element [" << x.first << ":" << x.second << "]";
// 返回元素所在桶号
std::cout << " is in bucket #" << mymap3.bucket(x.first) << std::endl;
}
以下内容译自《unordered_map::count - C++ Reference》
原型
size_type count ( const key_type& k ) const;
说明 使用给定的 Key 值计算元素。 搜索容器中 Key 值为输入参数 k 的元素,并返回找到元素的数量。由于 unordered_map 容器不允许存在重复的 Key 值,这说明如果容器中存在具有该 Key 值的元素,则该函数返回 1,否则返回 0。
其他操作函数基本和 map 相同:
以下示例从《C++11中std::unordered_map的使用》挑选,并加以注释说明。
#include <iostream>
#include <string>
#include <unordered_map>
// reference: http://www.cplusplus.com/reference/unordered_map/unordered_map/at/
typedef std::unordered_map<std::string, std::string> stringmap;
// 将 a, b 融合为一个 unordered_map
stringmap merge(stringmap a, stringmap b) {
// unordered_map 复制构造函数
stringmap temp(a);
// 范围插入,将 b 全部插入进 a 中
temp.insert(b.begin(), b.end());
return temp;
}
int main()
{
//============================
// 1. unordered_map 元素计算与基础遍历
//============================
// 定义第一个 unordered_map
std::unordered_map<std::string, int> mymap = { { "Mars", 3000 }, { "Saturn", 60000 }, { "Jupiter", 70000 } };
// 对元素进行计算
mymap.at("Mars") = 3396;
mymap.at("Saturn") += 272;
mymap.at("Jupiter") = mymap.at("Saturn") + 9638;
// auto:自动判断类型
// 基于范围的 for 循环,遍历 mymap
for (auto& x : mymap) {
std::cout << x.first << ": " << x.second << std::endl;
}
std::cout << "mymap.size() is " << mymap.size() << std::endl << std::endl;
//============================
// 2. iterator, 迭代器遍历
//============================
// 定义第二个 unordered_map
std::unordered_map<std::string, std::string> mymap2 = { { "Australia", "Canberra" }, { "U.S.", "Washington" }, { "France", "Paris" } };
std::cout << "mymap2 contains:" << std::endl;
// 遍历 mymap2
for (auto it = mymap2.begin(); it != mymap2.end(); ++it)
std::cout << " " << it->first << ":" << it->second << std::endl;
std::cout << std::endl;
// mymap2 分配的各桶中的元素
std::cout << "mymap2's buckets contain:\n";
for (unsigned i = 0; i < mymap2.bucket_count(); ++i) {
std::cout << "bucket #" << i << " contains:";
for (auto local_it = mymap2.begin(i); local_it != mymap2.end(i); ++local_it)
std::cout << " " << local_it->first << ":" << local_it->second;
std::cout << std::endl;
}
//============================
// 3. bucker, 桶操作
//============================
// 定义第三个 unordered_map
std::unordered_map<std::string, std::string> mymap3 = {
{ "us", "United States" },
{ "uk", "United Kingdom" },
{ "fr", "France" },
{ "de", "Germany" }
};
// 遍历 mymap3
for (auto& x : mymap3) {
std::cout << "Element [" << x.first << ":" << x.second << "]";
// 返回元素所在桶号
std::cout << " is in bucket #" << mymap3.bucket(x.first) << std::endl;
}
//============================
// 4. count ,判断元素是否在容器中
//============================
// 定义第四个 unordered_map
std::unordered_map<std::string, double> mymap4 = {
{ "Burger", 2.99 },
{ "Fries", 1.99 },
{ "Soda", 1.50 } };
// 遍历 mymap4
for (auto& x : { "Burger", "Pizza", "Salad", "Soda" })
{
// 判断 x 是否在容器中
if (mymap4.count(x)>0)
std::cout << "mymap4 has " << x << std::endl;
else
std::cout << "mymap4 has no " << x << std::endl;
}
//============================
// 5. erase ,删除操作
//============================
// 定义第五个 unordered_map
std::unordered_map<std::string, std::string> mymap5;
mymap5["U.S."] = "Washington";
mymap5["U.K."] = "London";
mymap5["France"] = "Paris";
mymap5["Russia"] = "Moscow";
mymap5["China"] = "Beijing";
mymap5["Germany"] = "Berlin";
mymap5["Japan"] = "Tokyo";
// 通过迭代器删除
mymap5.erase(mymap5.begin());
// 通过 Key 值删除
mymap5.erase("France");
// 通过迭代器范围删除
mymap5.erase(mymap5.find("China"), mymap5.end());
// 基于范围的 for 循环,遍历展示删除后的 mymap
for (auto& x : mymap5)
std::cout << x.first << ": " << x.second << std::endl;
//============================
// 6. find ,搜索操作
//============================
// 定义第六个 unordered_map
std::unordered_map<std::string, double> mymap6 = {
{ "mom", 5.4 },
{ "dad", 6.1 },
{ "bro", 5.9 } };
std::string input;
std::cout << "who? ";
// 输入 mom, dad, bro 中的一个,否则搜索失败返回 Not Found
getline(std::cin, input);
// 根据输入参数 Key 值进行搜索,返回一个迭代器
std::unordered_map<std::string, double>::const_iterator got = mymap6.find(input);
// find 返回值若为 unordered_map 的尾部,则没有在容器中找到
if (got == mymap6.end())
std::cout << "not found";
else
std::cout << got->first << " is " << got->second;
std::cout << std::endl;
//============================
// 6. insert ,插入操作
//============================
// 定义第七、八个 unordered_map
std::unordered_map<std::string, double>
myrecipe,
mypantry = { { "milk", 2.0 }, { "flour", 1.5 } };
// 定义插入元素,类型为 pair 的对象
std::pair<std::string, double> myshopping("baking powder", 0.3);
// 复制插入
myrecipe.insert(myshopping);
// 移动插入
myrecipe.insert(std::make_pair<std::string, double>("eggs", 6.0));
// 范围插入
myrecipe.insert(mypantry.begin(), mypantry.end()); // range insertion
// 初始化列表插入
myrecipe.insert({ { "sugar", 0.8 }, { "salt", 0.1 } }); // initializer list insertion
std::cout << "myrecipe contains:" << std::endl;
for (auto& x : myrecipe)
std::cout << x.first << ": " << x.second << std::endl;
std::cout << std::endl;
//============================
// 7. 等于运算符 = 操作
//============================
// 初始化列表
stringmap first = { { "AAPL", "Apple" }, { "MSFT", "Microsoft" } };
stringmap second = { { "GOOG", "Google" }, { "ORCL", "Oracle" } };
// 移动
stringmap third = merge(first, second);
// 复制
first = third;
std::cout << "first contains:";
for (auto& elem : first) std::cout << " " << elem.first << ":" << elem.second;
std::cout << std::endl;
return 0;
}
摘选自 Leetcode 问题 Two Sum:给出一个整数数组,返回两个数的下标值,令其和等于一个指定的目标值。 例:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].
有解如下:
#include <unordered_map>
class Solution {
public:
vector<int> twoSum(vector<int> &numbers, int target)
{
//Key is the number and value is its index in the vector.
unordered_map<int, int> hash;
vector<int> result;
for (int i = 0; i < numbers.size(); i++) {
int numberToFind = target - numbers[i];
//if numberToFind is found in map, return them
if (hash.find(numberToFind) != hash.end()) {
result.push_back(hash[numberToFind]);
result.push_back(i);
return result;
}
//number was not found. Put it in the map.
hash[numbers[i]] = i;
}
return result;
}
};
算法本身遍历一次,花费了 O(n) 的时间复杂度,遍历过程中的 find() 方法本身花费 O(log n),所以该算法总时间复杂度为 O(nlog n)。
参考网址: 《c++中map与unordered_map的区别》 《C++中map和hash_map的区别》
#include <map>
#include <hash_map>
#include <unordered_map>