CPP unordered_set只使用比较器而不是哈希

cpp unordered_set just use comparator not hash

本文关键字:比较器 哈希 unordered set CPP      更新时间:2023-10-16
#include <unordered_set>
#include <iostream>
class edge{
public:
float a1;
float a2;
};
struct comp{
bool operator()(const edge& e1, const edge& e2) const {
return true;
return (
(e1.a1==e2.a1 && e1.a2==e2.a2) ||
(e1.a1==e2.a2 && e1.a2==e2.a1)
);
};
};
struct hash{
size_t operator()(const edge& e1) const {
// return std::hash<float>()(e1.a1+e1.a2);
return std::hash<float>()(e1.a1+e1.a2*2);
};
};

int main() {
std::unordered_set<edge,hash,comp> s1;
s1.insert(edge{1.1,2.2});
s1.insert(edge{2.2,1.1});
for( auto& it : s1 ) {
std::cout << it.a1 << " " << it.a2 << "n";
}
std::cout << "s1.size " << s1.size() << "n";
}

我意识到如果不同的元素具有相同的哈希值,那么它们被认为是相等的,但我只想unordered_set使用我定义的比较器,只是忽略哈希?

如何实现?

我知道我可以使用set,但是使用set需要考虑顺序,如果a<b为真,b><a也是真的,那么这个元素将无法成功插入,有时,很难提供顺序。>

如果有人能帮忙,非常感谢


编辑: 我的目的是让两个边称为 e1,e2,如果(e1.a1==e2.a1&&e1.a2==e2.a2)(e1.a1==e2.a2 && e1.a2==e2.a1),它们与我提供的相同 在结构体中。 但是当我测试时。哈希函数似乎也可以改变比较。有人说我定义哈希和比较器的方式会导致未定义的行为。 这是真的吗?为什么? 如果是真的,如何解决这个问题?我只想让比较器决定哪一个满意地插入unordered_set而不重复。而且真的不在乎哈希。

顺便说一句,感谢很多人的回复

如果要互换处理edge.a1edge.a2,则必须实现一个哈希函数,即使它们被交换,也返回相同的值。我建议不要使用加法,因为加法对于浮点数可能不是可交换的,但您可以按大小对它们进行排序,然后合并哈希:

struct hash {
size_t operator()(const edge& e1) const {
auto h1 = std::hash<float>{}(std::min(e1.a1, e1.a2));
auto h2 = std::hash<float>{}(std::max(e1.a1, e1.a2));
return h1 ^ (h2 << 1)
};
};

这只对相当大的浮点数集有意义,因为否则哈希开销可能首先超过使用哈希数据结构的好处。

旧答案供参考:

具有相同哈希值的对象unordered_set.它们只是存储在同一个存储桶中。有一个KeyEqual用于比较的模板参数,其通过 默认使用Keyoperator==。所以你的主要问题是,comp应该实现e1 == e2而不是e1 < e2(并且应该 可能被称为equal(。

哈希仅用于加快搜索、插入和删除的速度 的元素。

另一方面,您可能希望使用成员的哈希值 变量而不是值本身来计算哈希edge

struct hash {
size_t operator()(const edge& e1) const {
auto h1 = std::hash<float>{}(e1.a1);
auto h2 = std::hash<float>{}(e1.a2);
return h1 ^ (h2 << 1)
};
};

这样,您就不会为交换的两个边缘获得相同的哈希值 坐标。这里建议使用这种组合哈希的方式(但是 不是组合两个以上的好方法(。

您不必使用edge的成员来提供哈希。仅要求相等的值具有相等的哈希值。"始终有效"哈希是

struct hash{
size_t operator()(const edge& e1) const {
return 0;
};
};

但似乎你最初的尝试更好

struct hash{
size_t operator()(const edge& e1) const {
return std::hash<float>{}(e1.a1 + e1.a2); // + is commutative
};
};