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

时间:2016-07-16 21:42:32

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

一本书提到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

1 个答案:

答案 0 :(得分:3)

以下是标准对排序[unord.req] / §6的说法:

  

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

所以,回答这个问题:

  

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

不,没有这样的要求或保证。如果这本书对标准提出了这样的要求,那就不正确了。如果本书描述了std::unordered_multimap的特定实现,则该描述可能适用于该实现。

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

因为等效键 - 必然会发生碰撞 - (实际上,并非明确要求)存储在单独的链表中,插入它们的最有效方式是按插入(push_back)或反向(push_front)的顺序)。如果单独的链是单链的,那么只有后者是有效的。