c++ - C++中的无序集
问题描述
如果我为双精度提供自定义比较,我是否必须覆盖哈希?例如这段代码
#include <iostream>
#include <unordered_set>
#include <set>
#include <cmath>
int main()
{
auto comp = [](double x, double y) { return fabs(x - y) < 1e-10; };
std::unordered_set<double, std::hash<double>, decltype(comp)> theSet(2, std::hash<double>(), comp);
std::cout.precision(17);
theSet.insert(1.0);
theSet.insert(1.0 + 1e-13);
theSet.insert(1.0 - 1e-13);
theSet.insert(1.2);
theSet.insert(1.00000000000001);
theSet.insert(3.2);
std::cout << "Hash set \n";
for (const auto& setEl : theSet)
{
std::cout << setEl << "\n";
}
}
产生(在http://cpp.sh/中,使用 MS VS Studio 2019 时,所有重复值似乎都保留了)
Hash set
1
0.99999999999989997
3.2000000000000002
1.2
1.00000000000001
它似乎过滤掉了 1.0 + 1e-13 和 1.0 - 1e-13,但它根据比较函数留下了其他重复值。
解决方案
您不希望为此进行散列:您需要一种保留相关顺序拓扑的数据结构,而不是故意将输入打乱以使其尽可能统一的数据结构。虽然可以将散列与分箱结合使用,但对于您的问题,一个简单的有序列表或集合就足够了。
如果您可以存储所有数字,您可以对它们进行排序,然后跳过它们,跳过那些太接近的数字(这仍然承认在比较哪些值方面存在一些歧义)。否则,如果冲突的数量很高,请使用 astd::set
并在每次插入之前检查相邻的值(同样,插入顺序会影响结果存在一些随意性)。
推荐阅读
- javascript - 为 history.back 按钮定义一个参考站点
- python - 正则表达式去除 C 标识符周围的(双)下划线
- corda - 测试 CordaApp 更改的最佳(最快)方法是什么?
- javascript - 是否可以将 Angular JS 用于 JAMstack 架构?
- html - 制作响应式网站但图像太小?
- html - 如何将 html 验证的默认文本更改为自定义错误消息
- regex - 正则表达式可选词
- ansible - Ansible 在输入变量文件中传递多行
- android - 使用 SupportMapFragment 时应用更改按钮不起作用
- spring - 从 gwt 调用 Spring MicroService