C++哈希表 - 如何解决自定义数据类型作为键的unordered_map冲突?

C++ Hash Table - How is collision for unordered_map with custom data type as keys resolved?

本文关键字:unordered 冲突 map 定义数据类型 哈希表 何解决 解决 C++      更新时间:2023-10-16

我定义了一个名为Point的类,它将用作unordered_map中的键。因此,我在类中提供了一个operator==函数,并且还提供了std::hashtemplate specialization。根据我的研究,这是我发现必要的两件事。相关代码如下所示:

class Point
{
int x_cord = {0};
int y_cord = {0};
public:
Point()
{
}
Point(int x, int y):x_cord{x}, y_cord{y}
{
}
int x() const
{
return x_cord;
}
int y() const
{
return y_cord;
}
bool operator==(const Point& pt) const
{
return (x_cord == pt.x() && y_cord == pt.y());
}
};
namespace std
{
template<>
class hash<Point>
{
public:
size_t operator()(const Point& pt) const
{
return (std::hash<int>{}(pt.x()) ^ std::hash<int>{}(pt.y()));
}
};
}
// Inside some function
std::unordered_map<Point, bool> visited;

该程序在我测试的情况下编译并给出了正确的结果。但是,我不相信在使用用户定义的类作为键时这是否足够。在这种情况下,unordered_map如何知道如何解决冲突?我是否需要添加任何内容来解决冲突?

这是一个可怕的哈希函数。但它是合法的,所以你的实现会起作用。

哈希和等于的规则(实际上是唯一的规则(是:

  • 如果a == b,则std::hash<value_type>(a) == std::hash<value_type>(b)

(同样重要的是,哈希和等于始终为相同的参数生成相同的值。我曾经认为这是不言而喻的,但我见过几个 SO 问题,unordered_map产生意想不到的结果,正是因为这些函数中的一个或两个都依赖于某个外部值。

这将通过始终返回 42 的哈希函数来满足,在这种情况下,地图在填满时会变得非常慢。但除了速度问题之外,代码还可以工作。

std::unordered_map使用链式哈希,而不是开放寻址哈希。具有相同哈希值的所有条目都放置在同一个存储桶中,这是一个链表。因此,低质量的哈希不能很好地在存储桶之间分配条目。

很明显,您的哈希给出{x, y}{y, x}相同的哈希值。更严重的是,小矩形中的任何点集合都将共享相同数量的不同哈希值,因为哈希值的高阶位都将相同。

知道Point旨在将坐标存储在图像中,这里最好的哈希函数是:

pt.x() + pt.y() * width

其中width是图像的宽度。

考虑到x[0, width-1]范围内的值,上面的哈希函数为任何有效的值pt生成一个唯一的数字。不可能发生碰撞。

请注意,如果将图像存储为单个内存块,则此哈希值对应于点pt的线性索引。也就是说,给定y也在有限的范围内([0, height-1](,所有生成的哈希值都在[0, width* height-1]范围内,并且可以生成该范围内的所有整数。因此,请考虑将哈希表替换为简单的数组(即图像(。图像是将像素位置映射到值的最佳数据结构。