为什么STL unordered_map和unordered_set无法按STL算法排序?

时间:2014-06-13 19:09:06

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

我首先来说明一个简单的用例示例:

  • 考虑社会安全ID数据库的问题,其中C ++代码被建模为std::unordered_map,其中密钥是一个人的社会安全ID,其值为std::string用该人的全名(例如std::unordered_map<int, std::string> DB;)。

  • 还要考虑,根据个人ID(即std::unordered_map的密钥)按照升序排序打印此数据库的请求。< / p>

  • 天真地,人们会考虑使用std::sort来根据请求的标准对std::unordered_map进行排序,然后将其打印出来,如下面的示例代码所示:


   std::sort(DB.begin(), DB.end());
   for(auto p : DB) std::cout << "ID(" << p.first
                              << ") - " 
                              << p.second 
                              << std::endl;

  • 但是,情况并非如此,因为使用范围为std::sortstd::unordered_map的{​​{1}}会引发编译错误。

问题:

  1. 为什么无法按std::unordered_set排序STL&#39的无序容器?
  2. 是否有合法有效的方式对std::sortstd::unordered_map进行排序?

3 个答案:

答案 0 :(得分:6)

unordered containers存储内部散列数据,因此在生成散列后无法对其进行排序。

为了对数据进行排序,您可以使用其他非散列容器(例如map或set),并将它们与无序版本一起使用(这样您就可以使用正常的数据对数据进行排序,将无序数据与有快速的每项访问权限)或者你可以做类似

的事情
std::map<int, int> ordered(unordered.begin(), unordered.end());
for(auto it = ordered.begin(); it != ordered.end(); ++it)
     std::cout << it->second;

我建议不要经常这样做(无序容器有慢速顺序访问)

https://stackoverflow.com/a/6212709/1938163

答案 1 :(得分:5)

排序仅对 sequence 容器有意义, sequence 容器是容器,其元素由它们添加到容器的顺序决定。标准库中的动态序列容器是vector,deque,list和forward_list。

另一方面,地图和集合是关联容器,其中元素由标识。因此,要求“排序”是没有意义的,因为容器元件没有以任何顺序排列。 (确实,有序地图可以按照键上的比较顺序进行迭代,但是从容器中出现 ;用户不提供它。)

答案 2 :(得分:2)

  

1.为什么STL的无序容器无法按std::sort排序?

因为无序容器“已排序”,但不是直接由其键,而是(通常)hash_function (key) % bucket_count {{1} }(也可以bucket ()进行访问)。这种“排序”顺序并不美观 - 它是哈希表能够快速找到元素的完整基础。如果允许(key)通过键重新排序元素,那么容器将不再能够用作哈希表:无法可靠地找到或删除元素,插入可能会在容器中放置重复项等。

  

2.是否有合法有效的方式对std::sortstd::unordered_map进行排序?

在一般情况下,只有首先将元素复制到可排序或排序的容器,例如std::unordered_setstd::vector(前者通常会更快,但如果您真的关心,则进行基准测试):

std::set

对于std::unordered_set<T> my_set = ...; std::vector<T> my_vec{my_set.begin(), my_set.end(), my_set.size()}; std::sort(my_vec.begin(), my_vec.end()); ,我建议只将std::unordered_map<int, std::string> DB;个密钥复制到int进行排序,然后在迭代过程中查找vector中的每个密钥:这将避免大量unordered_map复制。

(有时可以通过按键排序来编排无序容器(例如,散列函数返回密钥,容器预先设定为最大桶索引&gt; =最大密钥值),但任何考虑此类滥用的人最好使用{{ 1}}。)