【问题标题】:Why STL unordered_map and unordered_set cannot be sorted by STL algorithms?为什么 STL unordered_map 和 unordered_set 不能通过 STL 算法排序?
【发布时间】:2014-08-04 10:17:03
【问题描述】:

我将从一个简单的用例示例开始:

    1234563该人的姓名(例如,std::unordered_map<int, std::string> DB;)。
  • 还要考虑,有一个请求打印此数据库,该数据库根据个人 ID(即std::unordered_map 的密钥)按升序排序。

  • 天真地,有人会认为使用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::unordered_mapstd::unordered_set 范围内使用 std::sort 会引发编译器错误。

问题:

  1. 为什么STL的无序容器不能按std::sort排序?
  2. 是否有一种合法有效的方法来对std::unordered_mapstd::unordered_set 进行排序?

【问题讨论】:

  • 如果将两个相加没有意义,请不要将事物存储为整数。将两个 SSID 一起添加没有意义,将它们存储为字符串或其他内容。
  • 只有在顺序容器上使用类似的变异算法才有意义,unordered_* 不是。
  • 1) sort 不知道迭代器来自哪个容器,错误是因为sort 需要RandomAccessIterators 而(unordered_)map|set 迭代器是BiDirectionalIterators。 2) 这些容器被命名为 unordered _map|set 是有原因的。如果您想订购,请使用map|set

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


【解决方案1】:

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

因为无序容器已经“排序”了,虽然不是直接按它们的键,而是按(通常)hash_function(key) %bucket_count()(也可以通过bucket访问(key))。这种“排序”顺序不是装饰性的——它是哈希表能够快速找到元素的整个基础。如果允许std::sort 改为通过键对元素重新排序,则容器将不再能够用作哈希表:无法可靠地找到或删除元素,插入可能会将重复项放入容器等。 .

2.是否有一种合法有效的方式来对std::unordered_mapstd::unordered_set 进行排序?

在一般情况下,只需首先将元素复制到可排序或已排序的容器中,例如 std::vectorstd::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&lt;int, std::string&gt; DB; 的情况下,我建议仅将int 键复制到vector 进行排序,然后在迭代期间查找unordered_map 中的每个键:这将避免很多@ 987654341@复制。

(有时可以通过键排序来编排无序容器(例如,哈希函数返回键,容器预先调整大小,因此最大存储桶索引 >= 最大键值)但任何考虑此类滥用的人最好使用 vector .)

【讨论】:

  • 这应该是答案,因为它包含更完整的信息。
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多