【问题标题】:Is the order of two same unordered_maps the same?两个相同的 unordered_map 的顺序是否相同?
【发布时间】:2012-04-09 00:55:51
【问题描述】:

换句话说,如果我填充两个 unordered_mapunordered_set 具有完全相同内容和相同散列函数的对象,对它们进行迭代会得到相同的键/值对序列吗?

如果是,那么它的成立条件是什么(例如,相同的散列函数、相同的键、不一定相同的值)。

【问题讨论】:

  • 您想到的散列函数实际上并不是最终使用的散列函数。桶的大小可以动态变化,而实际的散列函数派生自你的散列函数(大概是以某种模块化算术的方式)。

标签: c++ c c++11 unordered-map unordered-set


【解决方案1】:

没有。例如,没有要求以任何特定顺序放置具有相同散列的对象。事实上,一般来说,无序映射不可能做到这一点,因为它可以访问的唯一信息是哈希值。

【讨论】:

  • 如果您在相同大小的容器中以相同的顺序使用相同的散列函数添加具有相同键的项目(即不使用reserve 或其他任何东西),可能会使它们成为订购方式不同?
  • 是的,所以..这就是我要问的。即使它没有指定,实际上它实际上是指定的,不是吗? :)
  • @SethCarnegie:首先,OP 没有说它们会以相同的顺序添加。其次,任何事情都可能使它们以不同的方式排序。如果需要,该实现可以对它们进行随机排序,甚至重新排序以将最常访问的对象放在其哈希链中的首位。
【解决方案2】:

这种情况下的行为是未定义的。因此,在某些情况下,顺序将是相同的,在其他情况下 - 不同。你不能确定任何事情。您提到的类型被命名为 unordered 并非偶然。将它们作为有序的使用是一种非常非常糟糕且极其危险的风格。

您会发现您的编译器以您希望使用的某种特殊方式运行。但你不能确定。你不能确定!您不知道,是什么条件导致了编译器的这种行为。您永远无法确定编译器版本的任何更改都不会改变您需要的行为。

在其他语言中简单禁止的内容,在 C/C++ 中没有指定。但你也应该把它当成禁忌。

c-faq about the problem of undefined behavior这个概念是所有C/C++通用的

【讨论】:

  • 是的.. 但从我能读到的here 看来这是可能的......
  • 有可能发生这种情况。但也有可能不会发生。其他语言中简单禁止的内容,在 C/C++ 中没有指定。但是你也应该把它当作禁止的。
  • @pms:“无序”的意思是“不可靠的有序”。这意味着 C++ 规范 不会定义顺序。您对std::unordered_* 的实现可能确实有一些一致的顺序。但规范并未强制这一点。而它确实对std::map 执行特定命令。因此,如果您希望您的代码可移植,那么您不能依赖于排序。
【解决方案3】:

首先我会引用MSDN:

受控序列中元素的实际顺序取决于哈希函数、比较函数、插入顺序、最大负载因子和当前桶数。您通常无法预测受控序列中元素的顺序。但是,您始终可以放心,任何具有相同顺序的元素子集在受控序列中都是相邻的。

unordered_mapunordered_set 的上述引用相同,顾名思义,序列未指定,但是它们确实提到等效键是相邻的。

【讨论】:

  • 我认为这仅适用于MS的实施,不是吗?还是标准中的要求?似乎这会迫使实现对冲突使用线性探测(或将每个元素存储在间接动态数组中)。
  • @SethCarnegie:看来这是必需的,我发现了一个关于它的讨论 here(查看帖子 6)。
  • 我们正在讨论编译器特定行为和未定义行为之间的区别——C/C++ ANSI 标准的术语。 MS 的任何文本都可以满足他们的特定需求,但此处仅作为比较示例。
  • 第二条评论中的链接现在是404。至于其他cmets,我不太明白这里的反对意见。只要 MS 的实施是合规的——当然必须假定它是合规的——那么它所允许的变化就是缺乏标准强加约束的证据。指出可能影响秩序的事物的广泛性,但不定义它们如何做,这与避开已定义秩序的标准并不矛盾。并且等效地比较相邻元素是标准显然要求的桶/链实现的一个简单事实。
【解决方案4】:

如果您需要保证排序,这不是适合您的数据结构。事实上,如果您主要进行迭代,unordered_map/set 也不是您的数据结构。

对于迭代,std::map 将被证明是更好的数据结构,因为从一个节点到下一个节点的 gonig 在算法上不太复杂。 std::map 中的对象的迭代顺序由规范保证(实际上是结构本身的定义属性)。 (显然,这一切都假设您使用的是相同的比较运算符)。 std::map 不涉及散列。

我只想说,听起来你在这里找错树了。 unordered_map 通常应该用于诸如 O(1) 查找之类的好处,而不是用于存储对象列表然后对其进行迭代。如果您试图获得确定性的迭代顺序,则绝对不应该使用它。

【讨论】:

  • 当然不是。但如果这是您代码中对性能敏感的部分,那么它可能也是您唯一要做的事情。
  • 不是,我使用哈希表是有原因的,你没抓住重点。
  • 如果你认为我的帖子没有抓住重点,我认为你错过了一些东西。
  • 嗯,我很重视您的回复和建议,但您的帖子显然没有回答这里提出的问题,即“两个相同的 unordered_maps 的顺序是否相同?”。如果这就是你否决我的问题的原因,那么我认为它具有攻击性,你可能应该重新考虑你的态度。保重。
  • 我非常清楚地回答了您的问题:订单无法保证。这到底有多难?!?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-10-21
  • 1970-01-01
  • 2013-08-20
  • 2017-04-25
  • 1970-01-01
  • 2019-10-24
  • 2012-09-11
相关资源
最近更新 更多