【问题标题】:Why hash_map and unordered_map on my machine are extremely slow?为什么我机器上的 hash_map 和 unordered_map 非常慢?
【发布时间】:2012-08-25 10:49:17
【问题描述】:

我用这段代码测试了它们(在 Visual Studio 2010 sp1 上):

#include <ctime>
#include <iostream>
#include <map>
#include <unordered_map>
#include <hash_map>

int main()
{ 
    clock_t time;
    int LOOP = (1 << 16);
    std::map<int, int> my_map;
    std::unordered_map<int, int> map_unordered_map;
    std::hash_map<int, int> my_hash_map;

    time = clock();
    for (int i = 0; i != LOOP; ++i)
    {
        my_map[i] = i;
    }
    std::cout << "map: " << ((double)(clock() - time) / CLOCKS_PER_SEC) << std::endl;

    time = clock();
    for (int i = 0; i != LOOP; ++i)
    {
        map_unordered_map[i] = i;
    }
    std::cout << "unordered_map: " << ((double)(clock() - time) / CLOCKS_PER_SEC) << std::endl;

    time = clock();
    for (int i = 0; i != LOOP; ++i)
    {
        my_hash_map[i] = i;
    }
    std::cout << "hash_map: " << ((double)(clock() - time) / CLOCKS_PER_SEC) << std::endl;

    system("PAUSE");
    return EXIT_SUCCESS;
}

结果太奇怪了:

在调试中: 地图:0.289 无序地图:10.738 哈希映射:10.58 按任意键继续 。 . .

在发布中: 地图:0.101 无序地图:0.463 哈希映射:0.429 按任意键继续 。 . .

【问题讨论】:

  • 可能是std::map 实现特别针对增加密钥插入进行了调整,您应该使用随机数进行测试。也可能是 2^16 太小而无法显示散列容器的理论优势。
  • std::map 使用红黑树作为其内部数据结构,而 std::hash_map 使用哈希表。您所看到的可能是随着哈希表的增长而重新设置哈希表的成本。如果您清除它们并再次运行相同的插入会发生什么?
  • 因为如果我将 LOOP 设置得更大,它会变得非常慢,所以最后我将它设置为 1
  • Jens Agby 是对的.....如果我在插入所有元素后第二次循环它,hash_map 比 map 快得多.....
  • 添加了一个描述我们发现的答案

标签: c++ map hashmap unordered-map


【解决方案1】:
  1. 您只在每个地图中插入了 65536 个项目 - 不足以让 O(log N) 和 O(1) 之间的差异意味着很多。
  2. 只是插入项目,之后不进行任何搜索。
  3. 您的键都是按递增顺序排列的连续整数 - 不适合任何地图的通常使用方式。

底线:这不太可能告诉您有关数据结构的太多信息。

【讨论】:

  • 我稍微改了一下代码,先插入所有元素,然后计算搜索每个元素的时间。这一次的结果符合预期......还是谢谢你......
【解决方案2】:

这是算法的摊销与最坏情况成本的示例。

std::map 使用具有 O(logN) 插入复杂度的红黑树。
std::hash_map 使用具有 O(1) 分摊插入复杂度的哈希表。

但是,当必须调整表大小并重新散列表时,散列表的最坏情况复杂度为 O(N)。

在您的情况下,您最终会进行大量重新散列,因此哈希表插入遇到了最坏的情况,以至于树插入变得更快 - O(N) > O(logN)。

如果你用足够大的表初始化 hash_map,那么哈希表永远不会遇到最坏的情况,它会比树快 - O(1)

【讨论】:

  • 因此,如果经常插入和擦除两者,请使用 map;当一起加载大量数据,然后用一个键读取它们时,使用任何类型的 hash_map,对吗?
  • 并非如此。 hash_map 的性能取决于提供的哈希函数。如果哈希函数与您的输入数据不能很好地匹配,那么性能可能会很糟糕。
  • @hythloday - hash_map 应该是您的默认选择,如果您只是在执行插入、查找和删除操作。只要确保将其初始化为适合您的数据的大小即可。是的,hash_map 有一些注意事项 - 散列函数和最坏的情况。因此,请确保您对如何解决这些问题有基本的了解。 map 的优点是按排序顺序迭代数据非常便宜。如果您不在乎,那么hash_map 应该是您的首选。
猜你喜欢
  • 1970-01-01
  • 2010-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-07
  • 2013-06-29
相关资源
最近更新 更多