【问题标题】:Should items with duplicate keys in unordered_multimap be kept in the order of their insertion?unordered_multimap 中具有重复键的项目是否应按插入顺序保留?
【发布时间】:2016-07-16 21:42:31
【问题描述】:

一本书提到std::unordered_multimap

元素的顺序未定义。唯一的保证是 由于使用了多重集而可能出现的重复项被分组 按照插入的顺序放在一起。

但从下面示例的输出中,我们可以看到打印顺序与它们的插入相反。

#include <string>
#include <unordered_map>

int main()
{
    std::unordered_multimap<int, std::string> um;
    um.insert( {1,"hello1.1"} );
    um.insert( {1,"hello1.2"} );
    um.insert( {1,"hello1.3"} );

    for (auto &a: um){
        cout << a.first << '\t' << a.second << endl;
    }
}

编译和运行时会产生此输出 (g++ 5.4.0):

1   hello1.3  
1   hello1.2  
1   hello1.1  

更新: unordered_multiset 有同样的问题:

auto cmp = [](const pair<int,string> &p1, const pair<int,string> &p2)
            {return p1.first == p2.first;};
auto hs = [](const pair<int,string> &p1){return std::hash<int>()(p1.first);};

unordered_multiset<pair<int, string>, decltype(hs), decltype(cmp)> us(0, hs, cmp);
us.insert({1,"hello1.1"});
us.insert({1,"hello1.2"});
us.insert({1,"hello1.3"});

for(auto &a:us){
    cout<<a.first<<"\t"<<a.second<<endl;
}

输出:

1   hello1.3
1   hello1.2
1   hello1.1

【问题讨论】:

  • The order of the elements is undefined. 我想你需要明白标准在说“未定义”时的含义:任何事情都可能发生,但发生什么并不重要,任何人都不应该依赖什么可能发生在星期二,风向东吹。实现可以根据需要定义一个顺序 - 可能是不故意拜占庭的副作用 - 但标准没有。就这样。话虽如此,如果您要插入更多元素,您可能会发现“可预测”的顺序开始崩溃。但是,这根本不重要。这是unordered_map
  • @underscore_d: 不,这是一个unordered_multimap,其中 C++14 November 2014 草案(至少)要求“具有等效键的元素在迭代顺序中彼此相邻容器”和“重新散列保留等效元素的相对顺序”(23.2.5)。我找不到任何关于根据插入顺序定义的相对顺序的信息,但值得了解。
  • @RyanO'Hara 感谢您提供信息。我没有完全处理,因为第一行缺少multi。现在我们需要知道哪本书是这么说的,而不是说它会比标准更可靠!
  • @underscore_d 该语句来自 C++ 标准库 A 教程和参考第 6.2 章容器,在第 183 页的开头: 现在,如果我们打印所有元素,则顺序可能会有所不同,因为顺序未定义.唯一的保证是,由于使用了多重集而可能出现的重复项按照它们的插入顺序组合在一起。
  • @camino 感谢您的引用和额外报价。我认为它的说法没有任何意义。 “顺序未定义”与“按插入顺序组合在一起”直接冲突。它们只是按未定义(尽管通常不变)的顺序组合在一起。

标签: c++ c++11 c++-standard-library unordered-multimap


【解决方案1】:

这是标准对订购 [unord.req] / §6 的表述:

... 在支持等效键的容器中,具有等效键的元素在容器的迭代顺序中彼此相邻。因此,尽管未指定无序容器中元素的绝对顺序,但其元素被分组到等效键组中,这样每个组的所有元素都具有等效键。除非另有说明,否则无序容器上的变异操作应保留每个等效键组中元素的相对顺序。

所以,回答这个问题:

unordered_multimap 中具有重复键的项是否应按插入顺序保留?

不,没有这样的要求或保证。如果这本书对标准做出这样的声明,那么它是不正确的。如果这本书描述了std::unordered_multimap 的特定实现,那么该描述对于该实现可能是正确的。


标准的要求使得使用开放寻址的实现变得不切实际。因此,兼容的实现通常使用单独的哈希冲突链接,请参阅How does C++ STL unordered_map resolve collisions?

因为等价键 - 必然会发生冲突 - (在实践中,没有明确要求)存储在单独的链表中,插入它们的最有效方法是按插入顺序 (push_back) 或反向 (push_front )。如果单独的链是单独链接的,则只有后者是有效的。

【讨论】:

  • 实现者没有义务在其库的未来版本中保持这种行为。
猜你喜欢
  • 1970-01-01
  • 2010-10-14
  • 1970-01-01
  • 2019-05-11
  • 2011-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-28
相关资源
最近更新 更多