C++ unordered_map与矢量一起使用时失败
C++ unordered_map fail when used with a vector as key
>背景:我来自Java世界,我对C++或Qt相当陌生。
为了玩unordered_map,我编写了以下简单的程序:
#include <QtCore/QCoreApplication>
#include <QtCore>
#include <iostream>
#include <stdio.h>
#include <string>
#include <unordered_map>
using std::string;
using std::cout;
using std::endl;
typedef std::vector<float> floatVector;
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
floatVector c(10);
floatVector b(10);
for (int i = 0; i < 10; i++) {
c[i] = i + 1;
b[i] = i * 2;
}
std::unordered_map<floatVector, int> map;
map[b] = 135;
map[c] = 40;
map[c] = 32;
std::cout << "b -> " << map[b] << std::endl;
std::cout << "c -> " << map[c] << std::endl;
std::cout << "Contains? -> " << map.size() << std::endl;
return a.exec();
}
不幸的是,我遇到了以下错误,这并不鼓舞人心。甚至没有行号。
:-1:错误:收集 2:ld 返回 1 个退出状态
知道问题的根源吗?
23.2.5,第3段说:
每个无序关联容器都由
Key
参数化,由满足 Hash 要求 (17.6.3.4( 的函数对象类型Hash
参数化,并充当Key
类型参数值的哈希函数,以及由在类型Key
的值上诱导等价关系的二进制谓词Pred
。
使用 vector<float>
作为Key
,不提供显式哈希和等效谓词类型意味着将使用默认std::hash<vector<float>>
和std::equal_to<vector<float>>
。
等价关系的std::equal_to
很好,因为向量有一个运算符==
,这就是std::equal_to
使用的。
但是,没有std::hash<vector<float>>
专业化,这可能是您没有向我们显示的链接器错误所说的。您需要提供自己的哈希器才能正常工作。
编写此类哈希器的一种简单方法是使用 boost::hash_range
:
template <typename Container> // we can make this generic for any container [1]
struct container_hash {
std::size_t operator()(Container const& c) const {
return boost::hash_range(c.begin(), c.end());
}
};
然后,您可以使用:
std::unordered_map<floatVector, int, container_hash<floaVector>> map;
当然,如果你在映射中需要不同的相等语义,你需要适当地定义哈希和等价关系。
1. 但是,对于散列无序容器,请避免这样做,因为不同的顺序会产生不同的哈希值,并且无法保证无序容器中的顺序。
我发现 R. Martinho Fernandes 的答案不适合竞争性编程,因为大多数时候您必须处理提供的 IDE,并且无法使用外部库,例如 boost
.如果您想充分利用 STL,可以使用以下方法。
如上所述,您只需要编写一个哈希函数。它应该专门用于存储在矢量中的数据类型。以下哈希函数假定int
类型数据:
struct VectorHasher {
int operator()(const vector<int> &V) const {
int hash = V.size();
for(auto &i : V) {
hash ^= i + 0x9e3779b9 + (hash << 6) + (hash >> 2);
}
return hash;
}
};
请注意,您可以使用任何类型的操作来生成哈希。您只需要发挥创造力,以便最大程度地减少碰撞。例如,hash^=V[i]
、hash|=V[i]
、hash+=V[i]*V[i]
甚至hash+=(V[i]<<i)*(V[i]<<i)*(V[i]<<i)
都是有效的,直到你的哈希不会溢出。
最后要将此哈希函数与您的unordered_map
一起使用,请按如下方式初始化它:
unordered_map<vector<int>,string,VectorHasher> hashMap;
- 如果没有malloc,链表实现将失败
- 模板参数替换失败,并且未完成隐式转换
- 具有默认模板参数的多态类的模板推导失败
- 视图中的参数推导失败:take_while
- 如何将enable-if与模板参数和参数包一起使用
- 如何将PERF_AMPLE_READ与mmap一起使用
- 链接到自行创建的dll失败
- 如何将两个不同矢量的同一位置的两个元素组合在一起
- 带有特殊路径部分的"std::filesystem::weakly_canonical"失败
- GetShortPathName在网络驱动器上使用中文文件夹时失败
- gcc和c++17的过载解析失败
- 为什么使用 P/Invoke 调用 dll 时,某些计算机中的 LoadLibrary 失败?
- 在WSL:configure_file上对config_file的每次调用都失败:配置文件时出现问题
- 与卡特琳娜一起卷曲C++失败并得到"Undefined symbols for architecture x86_64"
- Googletest 在 bazel test 中永远不会失败(在它应该失败的地方),但与 cmake & clion 一起工作
- 将 dirent->d_name 与字符串一起使用失败
- 与长路径一起使用时,创建目录失败并显示错误 123
- C++ unordered_map与矢量一起使用时失败
- 为什么mem_fn在与smatch::str一起使用时编译失败?
- C++API声明与Cython一起失败