【问题标题】:How to choose between map and unordered_map?如何在 map 和 unordered_map 之间进行选择?
【发布时间】:2012-11-27 18:52:12
【问题描述】:

假设我想以字符串为键映射数据。 我应该选择哪个容器,mapunordered_mapunordered_map 占用更多内存,所以我们假设内存不是问题,关注的是速度。

unordered_map 通常应该给出 O(1) 的平均复杂度,最坏的情况是 O(n)。 在什么情况下会达到 O(n)? map 什么时候比 unordered_map 更节省时间?当 n 小时会发生这种情况吗?

假设我将使用 STL unordered_map 和默认的 haser Vs。地图。字符串是关键。

如果我要遍历元素而不是每次都访问单个元素,我应该更喜欢map吗?

【问题讨论】:

  • 是否需要对映射中的项目进行排序?
  • unordered_map 的哪个实现使用更多内存?
  • 哈希映射中总是有内存开销,尽管它通常可以忽略不计。
  • 这是一个小问题,但当你提到迭代时,值得指出的是,如果你在插入元素时进行迭代,你应该更喜欢 map 而不是 unordered_map。

标签: c++ dictionary data-structures stl unordered-map


【解决方案1】:
                       | map              | unordered_map
---------------------------------------------------------
element ordering       | strict weak      | n/a 
                       |                  |
common implementation  | balanced tree    | hash table
                       | or red-black tree|  
                       |                  |
search time            | log(n)           | O(1) if there are no hash collisions
                       |                  | Up to O(n) if there are hash collisions 
                       |                  | O(n) when hash is the same for any key
                       |                  |     
Insertion time         | log(n)+rebalance | Same as search
                       |                  | 
Deletion time          | log(n)+rebalance | Same as search
                       |                  | 
needs comparators      | only operator <  | only operator ==
                       |                  |
needs hash function    | no               | yes
                       |                  |
common use case        | when good hash is| In most other cases. 
                       | not possible or  | 
                       | too slow. Or when|
                       | order is required| 

【讨论】:

  • 关于常见实现的评论:红黑树是一种平衡树(或者更具体地说,一种自平衡二叉搜索树)。
  • 重新平衡不会超过log(n)
  • 遍历所有元素怎么样?
  • 为什么map 的元素排序是strict weak
【解决方案2】:

实际上,如果内存没有问题,如果您想访问单个元素,unordered_map 总是更快。

最坏的情况是理论上的,并且绑定到一个哈希值来解释所有元素。这没有实际意义。只要您至少有 log N 个属于同一散列的元素,unordered_map 就会变慢。这也没有实际意义。在某些特殊情况下,您可以使用特定的散列算法来确保更均匀的分布。对于不共享特定模式的普通字符串,unordered_map 附带的通用哈希函数同样出色。

如果您想以排序方式遍历地图(使用迭代器),则不能使用unordered_map。相反,map 不仅允许这样做,而且还可以根据键的近似值为您提供映射中的下一个元素(请参阅lower_boundupper_bound 方法)。

【讨论】:

  • 这个答案充其量只是误导。 “unordered_map 对于单个元素的访问总是更快”这不是真的——我唯一能想到的总是正确的是它总是更快 amortizedasymptotically。 “摊销”是实践中的一个重要警告:假设它是作为某种哈希表实现的,如果我没记错我的哈希表,当你通过插入元素来增长它时,它会因 Ω(n) 操作而“打嗝”每隔一段时间。这可能是也可能不是任何特定应用都可以容忍的。
  • 使用了有趣的术语“在实践中”。假设我们编写时间要求严格的系统,例如火箭发动机控制器或金融交易系统或心脏刺激器控制器。我们需要一张地图。在 99.999% 的情况下,std::map 会比 std::unordered_map 慢,因为 std::unordered_map 的平均 O(1)。但是在 0.001% 的情况下,我们会得到最坏的情况,并且 unordered_map 的 O(n)。那么我们有什么?坠毁的火箭,损失了数百万,人类死亡。不是每天,甚至可能不是每年。但是,最坏的情况仍然会发生。最坏情况 O(log n) 的 std::map 可以处理它们,而 unordered_map 不能。
  • 如果你写的是火箭发动机控制器,希望你不用去 Stack Overflow 上询问数据结构和算法的基础知识。这是每所大学的计算机科学学士学位课程中广泛讨论的主题,其深度远远超过这里的问题。
【解决方案3】:

我应该选择什么容器,map 还是 unordered_map? unordered_map 占用更多内存,所以我们假设内存不是问题,关注的是速度。

配置文件然后决定。 unordered_map 通常更快,但因情况而异。

在什么情况下会达到 O(n)?

当散列不好并且一堆元素被分配到相同的 bin 时。

什么时候地图比 unordered_map 更省时?当 n 小时会发生这种情况吗?

可能不会,但如果您真的在乎,请对其进行分析。让一个小尺寸的容器成为你程序的瓶颈似乎是极不可能的。无论如何,对于这种情况,使用线性搜索的简单 vector 可能会更快。


决定时最重要的是排序的要求和迭代器失效的缺乏。如果你需要任何一个,你几乎必须使用map。否则,unordered_map

【讨论】:

    【解决方案4】:

    什么情况下会达到 O(n)?

    如果你有这样一个 bad 散列函数,它为所有输入搅拌产生相同的散列值(即产生冲突)......

    我应该选择什么容器,map 还是 unordered_map?

    始终是您拥有的需求和数据种类/数量的问题。

    地图什么时候比 unordered_map 更省时?

    只是结构不同而已。您最好根据您的典型用例选择使用其中一个(考虑到您拥有什么样的数据及其数量)

    n 很小的时候会出现问题吗?

    在小数据量的情况下,一切都取决于特定的 STL 实现...... 所以有时即使是普通的向量/数组也可能比关联容器更快...

    【讨论】:

      【解决方案5】:

      std::map 在内部将元素存储在平衡的 BST 中。因此,元素将按键的排序顺序存储。

      std::unordered_map 使用哈希表存储元素。因此,元素不会以任何排序顺序存储。它们将以任意顺序存储。

      内存使用:

      与 map 相比,unordered_map 的内存使用更多,因为 unordered_map 也需要空间来存储哈希表。

      搜索元素的时间复杂度:

      在 std::map 中搜索元素的时间复杂度为 O(log n)。即使在最坏的情况下也将是 O(log n),因为元素在内部存储为平衡二叉搜索树 (BST)。

      然而,在 std::unordered_map 中,搜索的最佳情况时间复杂度是 O(1)。其中,如果哈希码函数不好,那么最坏情况的复杂度可能是 O(n)

      【讨论】:

        猜你喜欢
        • 2011-04-23
        • 2017-03-21
        • 2023-03-25
        • 2011-01-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多