KeyEqual
中第三个参数std::unordered_set
的目的是什么?哈希的唯一性不够吗?
template<
class Key,
class Hash = std::hash<Key>,
class KeyEqual = std::equal_to<Key>,
class Allocator = std::allocator<Key>
> class unordered_set;
对不起,如果这个问题听起来很幼稚。从Python / PHP迁移到C ++:)
现在我的KeyEqual
实现总是重复Hash
impl。所以我很想知道我是否正确地做到了。
答案 0 :(得分:3)
但是如果我们有哈希冲突怎么办?
该图片演示了两个不同的元素碰巧具有相等哈希值的情况。因此,当涉及散列时,散列值可能不是唯一的。
引用> p + scale_x_discrete(limits = c("Cat1", "Cat2", "Cat3", "Cat4", "Cat5"), drop=FALSE)
的{{3}}:
在内部,unordered_set中的元素未按任何方式排序 特定的顺序,但根据其哈希值组织成桶 允许直接快速访问单个元素的值 它们的值(平均时间复杂度恒定)。
所以一个桶可以有多个元素!这两个元素将具有相同的哈希值,但不保证是唯一的!
唯一保证唯一的是键!
答案 1 :(得分:2)
我们举个例子,一组带有散列函数的int
s,只做一个简单的mod %
操作
struct IntMod {
constexpr std::size_t operator()(int i) const { return i % 10; }
};
std::unordered_set<int, IntMod> s;
这很容易导致哈希冲突,当发生这种情况时,您需要能够比较密钥以了解密钥是否已经存在。
s.insert(25); // hash == 5
s.insert(35); // hash == 5
assert(*s.find(25) == 25); // both 25 and 35 are present despite the same hash
assert(*s.find(35) == 35);
如果我们添加一个只使用哈希函数的KeyEqual
(就像你默认的那样建议),它会在第二次插入时中断。
struct IntEq {
constexpr bool operator()(int a, int b) const {
return IntMod{}(a) == IntMod{}(b);
}
};
std::unordered_set<int, IntMod, IntEq> s;
s.insert(25); // hash == 5
s.insert(35); // hash == 5
assert(*s.find(25) == 25);
assert(*s.find(35) == 35); // now this fails. s.find(35) returns iterator to 25
答案 2 :(得分:1)
很简单,该集需要知道两个键是否相等。 KeyEqual
是实现这一目标的机制。
请记住,两个不能比较的密钥可以哈希到相同的值,并且该集需要能够检查它。
答案 3 :(得分:1)
不同的值不一定有不同的哈希值。例如,std::string
的结果实际上有无限数量的std::size_t
个对象,但只有2 ^ N std::hash<std::string>()(s)
个对象,因此有些&#34;哈希冲突&#34;虽然算法试图让它们变得不可能,但这是不可避免的。
因此,std::unordered_set
和std::unordered_map
需要一种方法来测试元素是否相等或不相等,即使它们的哈希值相等。