【问题标题】:How do I use unordered_set? [duplicate]如何使用 unordered_set? [复制]
【发布时间】:2013-08-08 12:31:56
【问题描述】:

我正在尝试像这样定义一个 unordered_set:

unordered_set<Point> m_Points;

当我编译它时,我得到以下错误:

C++ 标准不提供这种类型的散列。

班级Point:

class Point{
    private:
        int x, y;
    public:
        Point(int a_x, int a_y)
            : x(a_x), y(a_y)
        {}
        ~Point(){}

        int getX()const { return x; }
        int getY()const { return y; }

        bool operator == (const Point& rhs) const{
            return x == rhs.x && y == rhs.y;
        }

        bool operator != (const Point& rhs) const{
            return !(*this == rhs);
        }
};
  • 如何/在哪里为 Point 定义哈希函数?
  • 对于二维点,什么是好的散列函数?

【问题讨论】:

  • 有一个很好的描述here
  • 一个懒惰的解决方案可能是从std::pair&lt;int, int&gt;派生你的类...
  • 我可以在 Point 类中定义一个哈希函数并将其作为函子传递给模板的第二个参数中的 unordered_set 吗?
  • @brainydexter 是的 - 第二个参数是类 Hash 默认为 std::hash
  • @doctorlove 是的..我想弄清楚的是,如果我在 Point 类中指定一个哈希函数,当我定义 unordered_set 时,如何将它指定为函子?我不确定我是否能做到。

标签: c++ stl set unordered-set


【解决方案1】:

std::unordered_set 要求您编写 hash functions 来存储和查找您自己的类型。

std 命名空间中的基本类型和许多类型在std::hash&lt;Key&gt; 中确实具有此类哈希函数。这些函数遵循certain rules

  1. 接受Key 类型的单个参数。

  2. 返回一个size_t 类型的值,表示参数的哈希值。

  3. 调用时不抛出异常。

  4. 对于两个相等的参数k1k2std::hash&lt;Key&gt;()(k1) == std::hash&lt;Key&gt;()(k2)

  5. 对于两个不同的参数k1k2不相等,std::hash&lt;Key&gt;()(k1) == std::hash&lt;Key&gt;()(k2)的概率应该很小,接近1.0/std::numeric_limits&lt;size_t&gt;::max()

现在我们已经解决了定义,让我们考虑一下什么是适合您的点结构的好的散列函数。有一个requeststd::pair(与点结构非常相似)有一个哈希函数,但不幸的是,它没有进入 C++11 标准。

但我们很幸运:SO 很棒,当然,您基本上已经可以find the answer。请注意,您不必自己散列整数,因为std::hash 已经对此进行了专门化。那么让我们深入研究一下我们的哈希函数,根据this answer

namespace std
{
    template <>
    struct hash<Point>
    {
        size_t operator()(Point const & x) const noexcept
        {
            return (
                (51 + std::hash<int>()(x.getX())) * 51
                + std::hash<int>()(x.getY())
            );
        }
    };
}

我们已经完成了。

【讨论】:

  • 感谢您的精心回复和链接。当我定义 unordered_set 时,我可以将上述哈希对象函数指定为我的 Point 类的一部分并将其用作函子吗?
  • noexcept 是我们给编译器的承诺,运行函数时不会出现异常。
  • @brainydexter 你的括号已关闭。它是 (51+hash(2))*51 + hash(4) 不等于 (51+hash(4))*51 + hash(2) 我已经编辑了答案以使其更清楚。
  • @doctorlove 从技术上讲,您可以在 Point 中声明 size_t operator()(Point const &amp;) noexcept 并使用 std::unordered_set&lt;Point, Point&gt;(假设 Point 有一个默认构造函数,在上面的示例中没有),但我发现这非常令人困惑;)我还想指出,明确鼓励专业化std::hash
  • @nijansen 为什么首选 std::hash 专业化?我认为扩展 std 命名空间是一种不好的做法。
猜你喜欢
  • 1970-01-01
  • 2010-12-21
  • 2014-05-05
  • 2019-07-11
  • 1970-01-01
  • 2012-11-21
  • 2015-08-05
  • 1970-01-01
相关资源
最近更新 更多