我知道STL有一个HashMap API,但是我找不到有关此方面的良好示例的任何详尽的文档。
任何好的例子将不胜感激。
我知道STL有一个HashMap API,但是我找不到有关此方面的良好示例的任何详尽的文档。
任何好的例子将不胜感激。
Answers:
标准库包括有序和无序的map(std::map
and std::unordered_map
)容器。在有序映射中,元素通过键排序,插入和访问在O(log n)中。通常,标准库在内部将红黑树用于有序地图。但这只是一个实现细节。在无序映射中,插入和访问位于O(1)中。它只是哈希表的别称。
一个示例(有序)std::map
:
#include <map>
#include <iostream>
#include <cassert>
int main(int argc, char **argv)
{
std::map<std::string, int> m;
m["hello"] = 23;
// check if key is present
if (m.find("world") != m.end())
std::cout << "map contains key world!\n";
// retrieve
std::cout << m["hello"] << '\n';
std::map<std::string, int>::iterator i = m.find("hello");
assert(i != m.end());
std::cout << "Key: " << i->first << " Value: " << i->second << '\n';
return 0;
}
输出:
23 关键:你好值:23
如果您需要在容器中订购并且适合O(log n)运行时,则只需使用std::map
。
否则,如果您确实需要哈希表(O(1)插入/访问),请签出std::unordered_map
,其具有与std::map
API 类似的功能(例如,在上面的示例中,您只需搜索并替换map
为unordered_map
)。
该unordered_map
容器是C ++ 11标准修订版引入的。因此,根据您的编译器,您必须启用C ++ 11功能(例如,使用GCC 4.8时,必须添加-std=c++11
到CXXFLAGS)。
甚至在C ++ 11发行版之前unordered_map
,在命名空间中都支持GCC std::tr1
。因此,对于旧的GCC编译器,您可以尝试像这样使用它:
#include <tr1/unordered_map>
std::tr1::unordered_map<std::string, int> m;
它也是boost的一部分,即您可以使用相应的boost-header以获得更好的可移植性。
hash_map
在某种形式的SGI STL。
unordered_map
。因此,没有理由考虑非标准hash_map
。
A hash_map
是用于标准化目的的较旧的未标准化版本,称为a unordered_map
(最初在TR1中,自C ++ 11起已包含在标准中)。顾名思义,它与std::map
无序的主要区别在于-例如,如果您从begin()
到遍历映射end()
,则可以通过键1来按顺序获取项目,但是如果unordered_map
从begin()
到遍历则可以从end()
a中获取项目。或多或少的任意顺序。
unordered_map
通常期望An 具有恒定的复杂性。也就是说,无论表中有多少项,插入,查找等操作通常都需要花费固定的时间。一个std::map
具有复杂性的对数上存储项目的数量-这意味着插入或检索项目长的时间,但非常缓慢,随着地图变得更大。例如,如果查找一百万个项目中的一个要花费1微秒,那么您可以期望花费约2微秒来查找200万个项目中的一个,400万个项目中的一个要花费3微秒,800万个项目中的一个要花费4微秒。物品等
从实际的角度来看,这并不是全部。本质上,简单的哈希表具有固定的大小。使它适应通用容器的可变大小要求有些困难。结果,(潜在地)扩展表的操作(例如,插入)可能相对较慢(也就是说,大多数操作都相当快,但是周期性地会慢得多)。无法更改表大小的查找通常要快得多。结果,与插入数量相比,当您进行大量查找时,大多数基于散列的表往往处于最佳状态。对于您插入大量数据的情况,然后遍历表一次以检索结果(例如,计算文件中唯一词的数量)很可能是std::map
速度会一样快,甚至可能甚至更快(但同样,计算复杂度是不同的,因此也可能取决于文件中唯一字的数量)。
1std::less<T>
默认情况下,在创建地图时由第三个模板参数定义顺序的位置。
rehash
。调用时rehash
,您可以为表格指定大小。将使用该大小,除非这样做会超出表中指定的最大负载因子(在这种情况下,大小将自动增加以使负载因子保持在限制范围内)。
这是一个更完整,更灵活的示例,其中没有省略生成编译错误的必要内容:
#include <iostream>
#include <unordered_map>
class Hashtable {
std::unordered_map<const void *, const void *> htmap;
public:
void put(const void *key, const void *value) {
htmap[key] = value;
}
const void *get(const void *key) {
return htmap[key];
}
};
int main() {
Hashtable ht;
ht.put("Bob", "Dylan");
int one = 1;
ht.put("one", &one);
std::cout << (char *)ht.get("Bob") << "; " << *(int *)ht.get("one");
}
除非将键预定义为指针,否则对于键仍然不是特别有用,因为匹配的值不会起作用!(但是,由于我通常将字符串用作键,因此在键的声明中将“ string”替换为“ const void *”应该可以解决此问题。)
void*
。对于初学者来说,没有理由将unordered_map
它包装为标准的一部分,从而降低了代码的可维护性。接下来,如果坚持要包装,请使用templates
。那正是他们的目的。
std::unordered_map
在GCC stdlibc ++ 6.4 中使用哈希映射的证据
在https://stackoverflow.com/a/3578247/895245中提到了此问题,但在以下答案中:在C ++中std :: map内包含什么数据结构?我通过以下方式为GCC stdlibc ++ 6.4实现提供了进一步的证据:
这是该答案中描述的性能特征图的预览:
如何使用自定义类和哈希函数 unordered_map
这个答案很明确:使用自定义类类型作为键的C ++ unordered_map
摘录:平等:
struct Key
{
std::string first;
std::string second;
int third;
bool operator==(const Key &other) const
{ return (first == other.first
&& second == other.second
&& third == other.third);
}
};
哈希函数:
namespace std {
template <>
struct hash<Key>
{
std::size_t operator()(const Key& k) const
{
using std::size_t;
using std::hash;
using std::string;
// Compute individual hash values for first,
// second and third and combine them using XOR
// and bit shifting:
return ((hash<string>()(k.first)
^ (hash<string>()(k.second) << 1)) >> 1)
^ (hash<int>()(k.third) << 1);
}
};
}
对于那些试图弄清楚如何在仍然使用标准模板的同时对自己的类进行哈希处理的人来说,有一个简单的解决方案:
在您的课程中,您需要定义一个相等运算符重载==
。如果您不知道该怎么做,GeeksforGeeks会提供出色的教程https://www.geeksforgeeks.org/operator-overloading-c/
在标准名称空间下,声明一个名为hash的模板结构,其类名为类型(请参见下文)。我发现了一个很棒的博客文章,其中还展示了使用XOR和位移位计算哈希的示例,但这超出了此问题的范围,但是其中还包括有关如何完成使用哈希函数的详细说明,以及https://prateekvjoshi.com/ 2014/06/05 /在C中为用户定义的类使用哈希函数/
namespace std {
template<>
struct hash<my_type> {
size_t operator()(const my_type& k) {
// Do your hash function here
...
}
};
}
std::map
或std::unordered_map
就像通常那样使用并my_type
用作键,标准库将自动使用您之前(在步骤2中)定义的哈希函数进行哈希你的钥匙。#include <unordered_map>
int main() {
std::unordered_map<my_type, other_type> my_map;
}