C++ std::无序_映射相等性是否取决于插入顺序

C++ std::无序_映射相等性是否取决于插入顺序,c++,unordered-map,C++,Unordered Map,如果使用同一组(不相等)键值对创建两个std::unordered_map容器,但插入顺序不同(因此容器包含相等的元素,但可能顺序不同),根据相等运算符(),容器是否保证相等。我假设容器元素的哈希代码和相等运算符满足其实现的所有必需约束。是的,在这种情况下,它们保证返回相等。具体措辞(来自N4659,§[unord.req]/12)为: 如果a.size()==b.size(),则两个无序容器a和b比较相等,并且对于从a.equal\u range(Ea1)获得的每个等价密钥组b.equal\u

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

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

如果
a.size()==b.size()
,则两个无序容器
a
b
比较相等,并且对于从
a.equal\u range(Ea1)
获得的每个等价密钥组
b.equal\u range(Ea1)
,存在从
b.equal\u range(Ea1)获得的等价密钥组
,使得
是置换(Ea1、Ea2、Eb1、Eb2)
返回
真值

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

如果
a.size()==b.size()
,则两个无序容器
a
b
比较相等,并且对于从
a.equal\range(Ea1)
获得的每个等效密钥组
b.equal\range(Ea1)
,存在从
b.equal\range(Ea1)获得的等效密钥组
,使得
是置换(Ea1、Ea2、Eb1、Eb2)
返回
真值
[…]

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

下面是关于std:unordered_映射的引用,操作符==,!=(std::unordered_映射):

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

  • lhs.size()==rhs.size()
  • 从lhs.equal_range(lhs_eq1)获得的每组等效元素[lhs_eq1,lhs_eq2]在从rhs.equal_range(rhs_eq1)获得的另一个容器[rhs_eq1,rhs_eq2]中有一组相应的等效元素,该容器具有以下属性:
    • 标准::距离(lhs_eq1,lhs_eq2)=标准::距离(rhs_eq1,rhs_eq2)
    • std::is_置换(lhs_eq1,lhs_eq2,rhs_eq1)=真
请注意:

如果Key或T不是相等可比较的,则行为是未定义的

如果Hash和KeyEqual do(直到C++20)KeyEqual do(因为C++20)在lhs和rhs上没有相同的行为,或者如果operator==for Key不是将分区细化为KeyEqual引入的等效密钥组(即,如果使用operator==比较相等的两个元素落入不同的分区),则该行为也是未定义的

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

与N成比例调用运算符==on value_type,调用key_eq返回的谓词,调用hash_函数返回的哈希器,在平均情况下,与N2成比例,在最坏情况下,其中N是容器的大小


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

您尝试过吗?此外,该保证将遵循相应的ISO标准,从而间接包含answ呃。@UlrichEckhardt我试过了,答案似乎是“是的,这取决于插入顺序”,但我不确定这是否是因为我犯了一个错误。否。(此空格故意留空)显示4的映射的所有插入序列排列相等的示例pairs@UlrichEckhardt“你试过了吗”不能告诉你“它不依赖于插入顺序”是这个实现的一个特征,或者是对所有C++实现的保证。(我想它可以告诉你,它确实依赖于插入顺序”-但是下面的所有答案都表明这将是实现中的一个错误。)@ HGM-红黑树?这个问题涉及无序映射,而不是(有序的)。映射。@Ant:无序容器是散列表,所以它们从散列到同一个bucket中相同值的所有键开始。我希望它们实际上会使用
std::is_permutation
来检查同一个bucket中的键。@Ant-标准中的引用适用于所有无序容器。如果有,这将大大简化每个键最多有一个条目,就像无序映射的情况一样。遍历第一个映射中的键值对是O(N)。在第二个映射中找到等价的键值对平均是O(1),最坏的情况是O(N)。因此,无序映射的
操作符==
平均是O(N),O(N^2)最坏的情况。@JerryCoffin-对于两个无序映射,
运算符==
的gcc和llvm实现都没有使用
std::is_permutation
。对于无序映射,这太过分了。两者都遍历第一个参数中的键值对,并使用
find
而不是
equal\u range
来获得等价的键-第二个参数中的值对(如果存在)。@André:对不起,我可能应该修正措辞——但它还要求键具有相同的关联值。