C++ 在C+;中使用HashMap的最佳方式是什么+;?
我知道STL有一个HashMapAPI,但我找不到任何好的、完整的文档,其中有关于这个的好例子C++ 在C+;中使用HashMap的最佳方式是什么+;?,c++,hashmap,C++,Hashmap,我知道STL有一个HashMapAPI,但我找不到任何好的、完整的文档,其中有关于这个的好例子 任何好的例子都将不胜感激。标准库包括有序和无序的映射(和)容器。在有序映射中,元素按键、插入和访问顺序进行排序。通常,标准库在内部用于有序映射。但这只是一个实现细节。在无序映射中,插入和访问位于O(1)中。它只是哈希表的另一个名称 带有(有序)std::map的示例: #include <map> #include <iostream> #include <cassert
任何好的例子都将不胜感激。标准库包括有序和无序的映射(和)容器。在有序映射中,元素按键、插入和访问顺序进行排序。通常,标准库在内部用于有序映射。但这只是一个实现细节。在无序映射中,插入和访问位于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;
}
它也是boost的一部分,也就是说,您可以使用相应的来提高可移植性。A
hash\u map
是一个较旧的非标准化版本,出于标准化目的,它被称为unordered\u map
(最初在TR1中,从C++11开始就包含在标准中)。顾名思义,它与std::map
的主要区别在于无序——例如,如果您从begin()
到end()
迭代一个映射,您将按键1按顺序获取项目,但如果您从begin()
到end()
迭代一个无序的映射,则,您可以或多或少随意地获取项目
无序的_映射
通常具有恒定的复杂性。也就是说,无论表中有多少项,插入、查找等通常需要固定的时间。std::map
的复杂性与存储的项目数成对数关系,这意味着插入或检索项目的时间会增加,但随着map的增大,速度会非常缓慢。例如,如果查找100万项中的一项需要1微秒,那么您可以预期查找200万项中的一项需要2微秒,查找400万项中的一项需要3微秒,查找800万项中的一项需要4微秒,等等
从实际的角度来看,这并不是全部。从本质上讲,一个简单的哈希表具有固定的大小。使其适应通用容器的可变大小要求有些不简单。因此,(可能)增加表的操作(例如插入)可能相对较慢(也就是说,大多数操作相当快,但周期性地会慢得多)。无法更改表大小的查找通常要快得多。因此,与插入次数相比,进行大量查找时,大多数基于哈希的表往往处于最佳状态。对于插入大量数据,然后在表中迭代一次以检索结果(例如,计算文件中的唯一字数)的情况,std::map
可能同样快,甚至更快(但是,计算复杂度也是不同的,因此也可能取决于文件中唯一单词的数量)
1其中,在创建映射时,顺序由第三个模板参数定义,默认情况下,std::less
。
这里有一个更完整、更灵活的示例,它没有忽略生成编译错误所需的包括:
#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");
}
#包括
#包括
类哈希表{
std::无序地图htmap;
公众:
无效放置(常量无效*键,常量无效*值){
htmap[key]=值;
}
常量无效*获取(常量无效*键){
返回htmap[key];
}
};
int main(){
哈希表ht;
ht.put(“鲍勃”、“迪伦”);
int-one=1;
ht.put(“一”和“一”);
std::cout证明std::unordered_map
在GCC stdlibc++6.4中使用哈希映射的证据
这一点在中提到:但在以下回答中:我已经通过以下方式为GCC stdlibc++6.4实现提供了进一步的证据:
- GDB在类中逐步调试
- 性能特性分析
下面是该答案中描述的性能特征图的预览:
如何将自定义类和哈希函数与无序映射一起使用
这个答案很准确:
摘录:平等:
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);
}
};
}
名称空间std{
模板
结构散列
{
std::size\u t运算符()(常数键和k)常数
{
使用std::size\u t;
使用std::hash;
使用std::string;
//计算第一个的单个散列值,
//第二个和第三个,并使用XOR组合它们
//和位移位:
返回((hash()(k.first)
^(散列()(k.second)>1)
^(hash()(k.third)对于那些试图找出如何在仍然使用标准模板的情况下对自己的类进行散列的人,有一个简单的解决方案:
在您的类中,您需要定义一个等式运算符重载=
。如果您不知道如何做到这一点,Geeksforgeks有一个很棒的教程
在标准名称空间下,声明一个名为hash的模板结构,并将您的类名作为类型(见下文)我发现了一篇很棒的博客文章,其中也展示了一个使用XOR和位移位计算哈希的示例,但这超出了这个问题的范围,但它也包含了关于如何使用哈希函数的详细说明
名称空间std{
模板
结构散列{
size\u t运算符()(常量my\u type&k){
//在这里执行哈希函数
...
}
};
}
因此,要使用新的哈希函数实现哈希表,只需像通常一样创建std::map
或std::unordered_map
,并使用my_type
作为键,标准库将自动使用您之前定义的哈希函数(在步骤2中)对键进行哈希
#包括
int main(){
std::无序_图我的_图;
}
你是在问C++1x哈希映射,还是在问std::map?我想要一个类似java.util的东西。
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);
}
};
}