对于以下情况,哪一个是更好的stl map或unordered_map

时间:2012-09-12 01:35:05

标签: c++ visual-c++ stl

我正在尝试比较某些操作的stl map和stl unordered_map。我在网上看了一下,这只会增加我对哪一个整体更好的疑虑。所以我想根据他们执行的操作来比较两者。

哪一个在

中表现得更快

插入,删除,查找

哪一个占用更少的内存,更少的时间从内存中清除它。任何解释都热烈欢迎!!!

提前致谢

4 个答案:

答案 0 :(得分:10)

  

哪一个在插入,删除,查找中表现得更快?哪一个占用更少的内存,更少的时间从内存中清除它。任何解释都热烈欢迎!!!

对于特定用途,你应该尝试使用你的实际数据和使用模式,看看哪个实际上更快......有足够的因素,假设任何一个总是“赢”是危险的。

无序映射/散列表的实现和特性

学术上 - 随着元素数量向无穷大增加,std::unordered_map上的那些操作(这是为计算科学提供的“哈希映射”或“哈希表”提供的C ++库)将继续花费相同的时间O(1)(忽略内存限制/缓存等),而使用std::map(平衡二叉树)每次元素数量加倍时,通常需要额外做一个比较操作,因此逐渐变慢O(log 2 n)。

std::unordered_map实现necessarily use open hashing:基本的期望是会有一个连续的“桶”数组,每个逻辑上都是任何值的容器。

它通常用于将哈希表描绘为vector<list<pair<key,value>>>,其中从向量元素到值的值从至少一个指针解除引用,当您按照列表头指针存储时在桶中到初始列表节点;插入/查找/删除操作的性能取决于列表的大小,平均等于unordered_map的{​​{3}}。

如果load_factor降低(默认值为1.0),则插入过程中会有更少的冲突但更多的重新分配/重新散列以及更多的内存浪费(这可能会通过增加缓存未命中而影响性能)。

这个最明显的unordered_map实现的内存使用涉及max_load_factor list-head-iterator /指针大小的桶的连续数组和每个键/值的一个双向链接列表节点对。通常,bucket_count() + 2 * size()额外的开销指针,根据实现可能执行的动态内存分配请求大小的任何舍入进行调整。例如,如果要求100个字节,则可能会得到128或256或512.实现的动态内存例程也可能使用一些内存来跟踪已分配/可用的区域。

尽管如此,C ++标准为实际实现留出了空间,可以做出一些自己的性能/内存使用决策。例如,在分配一个新的更大的阵列之后,它们可以将旧的连续桶阵列保持一段时间,因此可以逐步地将值重新组合到后者中,以便以平均情况性能为代价来降低最坏情况的性能。在操作期间咨询两个阵列。

地图/平衡二叉树的实现和特征

map是一个二叉树,可以使用指针链接不同调用返回到new的不同堆内存区域。除了键/值数据,树中的每个节点都需要父指针,左指针和右指针(如果丢失,请参阅bucket_count())。

比较

因此,unordered_mapmap都需要为键/值对分配节点,前者通常具有上/下一节点链接的双指针/迭代器开销,后者有三个为父/左/右。但是,unordered_map还为bucket_count()存储分配了一个连续的分配(== size() / load_factor())。

对于大多数目的而言,内存使用量并没有显着差异,并且一个额外区域的释放时间差异不太可能引人注意。

另一种选择

对于容器填充前面然后重复搜索而没有进一步插入/删除的情况,有时使用标准算法wikipedia's binary tree articlebinary_search,{{ 3}},equal_range。这具有单个连续内存分配的优点,其更加缓存友好。它总是优于map,但unordered_map可能仍然更快 - 如果你关心的话可以衡量。

答案 1 :(得分:2)

两者兼顾的原因是两者都不是更好。

使用任何一个。切换,如果另一个证明更好的使用。

  • std :: map为更糟糕的时间提供更好的空间。
  • std :: unordered_map为更糟糕的空间提供了更好的时间。

答案 2 :(得分:1)

您的问题的答案在很大程度上取决于您正在使用的特定STL实现。实际上,您应该查看STL实现的文档 - 它可能会有大量关于性能的信息。

一般而言,根据cppreference.com,maps通常实现为red-black trees并支持时间复杂度为O(log n)的操作,而unordered_maps通常支持常量 - 时间操作。 cppreference.com对内存使用情况缺乏洞察力;但是,another StackOverflow answer建议地图通常使用的内存少于unordered_maps。

对于使用Visual Studio 2012的STL实现Microsoft软件包,看起来map在分摊的O(log n)时间内支持这些操作,unordered_map在分摊的常量时间内支持它们。但是,文档没有明确说明内存占用情况。

答案 3 :(得分:1)

<强>地图

插入:

  1. 对于第一个版本(insert(x)),对数。
  2. 第二个 版本(插入(位置,x)),一般是对数,但是 如果在元素指向后插入x,则分摊常量 按位置。
  3. 对于第三个版本(插入(第一个,最后一个)), 一般是Nlog(大小+ N)(其中N是第一个和第二个之间的距离) 最后,并在插入之前调整容器的大小),但是 如果第一个和最后一个之间的元素已经排序,则为线性 根据容器使用的相同排序标准。
  4. 删除:

    1. 对于第一个版本(擦除(位置)),摊销常数。
    2. 对于第二个版本(erase(x)),以容器大小为对数。
    3. 对于最后一个版本(擦除(第一个,最后一个)),容器大小的对数加上第一个和最后一个距离之间的线性。
    4. 查找

      1. 对数大小。
      2. 无序地图:

        插入:

        1. 单个元素插入:
          1. 平均情况:不变。
          2. 最坏情况:容器尺寸呈线性。
        2. 多元素插入:
          1. 平均大小写:插入元素数量的线性。
          2. 最坏情况:N *(大小+ 1):插入的元素数乘以容器大小加一。
        3. 删除:

          1. 平均情况:删除的元素数量为线性(仅删除一个元素时为常量)
          2. 最坏情况:容器尺寸为线性。
          3. 查找

            1. 平均情况:不变。
            2. 最坏情况:容器尺寸呈线性。
            3. 了解这些,您可以根据实现的类型决定使用哪个容器。

              来源:www.cplusplus.com