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

时间:2018-08-28 01:01:10

标签: c++ hashmap unordered-map user-defined-types hash-collision

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

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如何知道在这种情况下如何解决冲突?我需要添加任何东西来解决冲突吗?

2 个答案:

答案 0 :(得分:4)

那是一个糟糕的哈希函数。但这是合法的,因此您的实现将起作用。

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

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

(同样重要的是,Hash和Equals始终为相同的参数产生相同的值。我曾经认为不用说,但是我已经看到了几个SO问题,其中unordered_map产生意外结果的原因恰恰是因为其中一个或两个这些功能取决于某些外部值。)

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

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

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

答案 1 :(得分:1)

Knowing that Point is intended to store coordinates within an image,最好的哈希函数是:

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

其中width是图像的宽度。

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

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