【问题标题】:C++: How do unordered containers prevent duplications?C++:无序容器如何防止重复?
【发布时间】:2020-08-12 15:13:16
【问题描述】:

我们以 unordered_set 为例。 判断两个元素是否相等的默认谓词是std::equal_to<T>(t1,t2), 这就是t1==t2。 现在让我们假设对于这个 T 类型,我已经实现了operator==(),所以并不是所有的成员变量都是这个比较的一部分,即两个不同的 T 元素 t1,t2 在比较时可以相等。

如果底层哈希表为这些 t1 和 t2 中的每一个计算不同的哈希,它甚至何时执行t1==t2 检查键的重复?如果有更多检查,它如何平均保持恒定时间?

【问题讨论】:

  • 如果两个元素相等,它们的哈希值必须相等。可能有 2 个具有相同哈希但不相等的对象。使用适当的散列不可能有 2 个相等但具有不同散列的对象。
  • 所以对于一个有成员变量a、b和c的对象,但是只有a和b用于相等,那么hash应该只使用a和b。如果 x 和 y 对象使用(x.a == y.a && x.b == y.b) || (x.a == y.b && x.b == y.a)(交叉相等),那么哈希最好找出一种方法来为这两种情况提供相同的哈希。
  • @Eljay 因此,每当我覆盖 operator==() 时,我都必须为无序容器提供不同的哈希计算?
  • @ShookiMatzliah 它没有。 负责根据您的班级逻辑实施适当的std::hash 特化。
  • 如果您在需要哈希器的容器中使用您的对象,您有义务为您的类对象提供哈希器。 q.v. std::hash。除非您使用 C++ 已经提供哈希器的 std 对象之一。

标签: c++ hash stl unordered-map unordered-set


【解决方案1】:

我认为您缺少的关键点是您为无序容器提供了两个仿函数,并且它们必须一起工作。

有一个哈希函数,它从一个对象中计算一个数字。

有一个比较函数,比较两个对象的“等价性”。

正如@Eljay 在评论中所说,对于两个比较“等价”的对象(比较函数返回true),哈希函数必须返回相同的值。

如果您的函数不提供此保证,则容器将无法正常工作。

比较好的参考(虽然不权威)

std::unordered_set:满足UnorderedAssociativeContainer的要求。
UnorderedAssociativeContainer:通过Key/Hash/Pred参数化。
有要求:
* 如果两个 Key 根据 Pred 相等。
* 哈希必须为两个键返回相同的值。

【讨论】:

    【解决方案2】:

    无序关联容器要求任何两个比较相等的键也具有相同的哈希值。来自[unord.req]

    Hash 类型的容器对象——用hash 表示——被称为容器的散列函数。容器的Pred 类型的对象——用pred 表示——被称为容器的键相等谓词。

    如果容器的键相等谓词 pred(k1, k2) 有效并在传递这些值时返回 true,则认为两个值 k1k2 是等效的。如果k1k2 是等价的,容器的哈希函数应该返回相同的值。

    您的operator==std::hash 实现必须一致。如果不是,那么您没有满足将您的类用作无序关联容器中的键所需的先决条件。

    【讨论】:

      【解决方案3】:

      如果底层哈希表为这些 t1 和 t2 中的每一个计算不同的哈希,它甚至何时执行 t1==t2 检查键的重复?

      当哈希函数导致新插入的元素被放入非空桶时。将在该桶中预先存在的元素之间进行比较,以确保唯一性。

      它如何平均保持恒定时间?

      通过假设散列函数将随机键均匀地分配到桶中,并随着元素数量的增加而增加桶的数量。

      std::hash 怎么知道我是如何实现 openrator==()

      为您的类编写 std::hash 特化的人必须知道您如何实现 operator==。

      散列函数必须为所有比较相等的元素产生相同的散列。如果没有,那么程序的行为将是未定义的。标准参考:[unord.req][defns.required.behavior]

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-02-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-05-20
        • 1970-01-01
        • 2023-03-30
        • 1970-01-01
        相关资源
        最近更新 更多