【问题标题】:Does std::unordered_map equality depend on insertion orderstd::unordered_map 相等性是否取决于插入顺序
【发布时间】:2018-08-06 15:22:44
【问题描述】:

如果您使用相同的一组(不相等)键值对创建两个 std::unordered_map 容器,但以不同的顺序插入(因此容器包含相同的元素,但可能以不同的顺序),容器是否有保证相等,根据相等运算符 (operator==)。我假设容器元素的哈希码和相等运算符满足其实现所需的所有约束。

【问题讨论】:

  • 你试过了吗?此外,该保证将遵循相应的 ISO 标准,因此间接包含答案。
  • @UlrichEckhardt 我试过了,答案似乎是“是的,这取决于插入顺序”,但我不确定这是否是因为我犯了一个错误。跨度>
  • 没有。 (此空间特意留空)
  • 示例 code 显示 4 对映射的所有插入序列排列相等
  • @UlrichEckhardt “你试过了吗”不能告诉你“它不依赖于插入顺序”是这个实现的一个特性,还是所有 C++ 实现都保证。 (我想它可以告诉你“它确实取决于插入顺序” - 但下面的所有答案都表明这将是实现中的一个错误。)

标签: c++ unordered-map


【解决方案1】:

是的,在这种情况下,它们保证返回相等。具体措辞(来自 N4659,§[unord.req]/12)是:

两个无序容器ab 比较相等,如果a.size() == b.size() 并且对于从a.equal_range(Ea1) 获得的每个等效键组[Ea1, Ea2),存在从@987654328 获得的等效键组[Eb1, Eb2) @,这样is_permutation(Ea1, Ea2, Eb1, Eb2) 返回true

因此,只要一个中的键(和关联的值)与另一个相同(但可能以不同的排列顺序),它就会比较相等。

【讨论】:

  • @hgm -- 红黑树?这个问题涉及无序地图,而不是(有序)地图。
  • @Ant:无序容器是哈希表,因此它们从在同一个桶中哈希到相同值的所有键开始。我希望他们实际上会使用std::is_permutation 来检查同一个存储桶中的密钥。 That can be O(n).
  • @Ant - 标准中的引用适用于所有无序容器。如果每个键最多有一个条目,这将大大简化,就像 unordered_map 的情况一样。遍历第一个映射中的键值对是 O(N)。在第二个映射中找到等效的键值对平均是 O(1),最坏的情况是 O(N)。所以operator== 对于无序地图平均是 O(N),最坏的情况是 O(N^2)。
  • @JerryCoffin - 对于两个无序映射,operator== 的 gcc 和 llvm 实现都不使用 std::is_permutation。对于无序地图来说,这太过分了。两者都遍历第一个参数中的键值对,并使用find 而不是equal_range 在第二个参数中获取等效的键值对(如果存在)。
  • @André:抱歉,我应该修正一下措辞——但它也要求键具有相同的关联值。
【解决方案2】:

来自[unord.red]/12

两个无序容器ab 比较相等,如果a.size() == b.size() 并且对于从a.equal_­range(Ea1) 获得的每个等效键组[Ea1, Ea2),存在从@987654328 获得的等效键组[Eb1, Eb2) @,这样is_­permutation(Ea1, Ea2, Eb1, Eb2) 返回true。 [...]

因此,只要键相同且大小相同,无论键的顺序如何,容器都会比较相等。

【讨论】:

    【解决方案3】:

    以下是 cppreference.com 关于 std:unordered_map, operator==,!=(std::unordered_map) 的引用:

    如果满足以下条件,则两个无序容器 lhs 和 rhs 的内容相等:

    • lhs.size() == rhs.size()
    • 从 lhs.equal_range(lhs_eq1) 获得的每组等价元素 [lhs_eq1, lhs_eq2) 在从 rhs.equal_range(rhs_eq1) 获得的另一个容器 [rhs_eq1, rhs_eq2) 中都有对应的一组等价元素,具有以下特性:
      • std::distance(lhs_eq1, lhs_eq2) == std::distance(rhs_eq1, rhs_eq2)。
      • std::is_permutation(lhs_eq1, lhs_eq2, rhs_eq1) == true。

    注意:

    如果 Key 或 T 不是 EqualityComparable,则行为未定义。

    如果 Hash 和 KeyEqual 确实(C++20 前)KeyEqual 确实(C++20 起)在 lhs 和 rhs 上没有相同的行为,或者如果 KeyEqual 的 operator== 不是对将分区划分为 KeyEqual 引入的等效键组(即,如果使用 operator== 比较相等的两个元素落入不同的分区)

    最后,要考虑的是复杂性:

    在 value_type 上对 operator== 的调用、对 key_eq 返回的谓词的调用以及对 hash_function 返回的哈希器的调用与 N 成正比,在平均情况下,与 N2 在最坏的情况下成正比,其中 N 是容器。

    因此,如果两个无序映射具有相同的大小,并且其中一个容器中的每个键都在另一个容器中查找,则如果碰巧找到了,则比较它们的值,则认为它们是相同的。

    【讨论】:

      猜你喜欢
      • 2011-02-08
      • 2012-10-23
      • 2013-01-01
      • 1970-01-01
      • 2012-04-09
      • 2013-11-05
      • 1970-01-01
      • 2010-12-09
      • 2023-02-23
      相关资源
      最近更新 更多