【问题标题】:C++ std::unordered_map slower than std::map?C++ std::unordered_map 比 std::map 慢?
【发布时间】:2022-01-13 11:20:19
【问题描述】:

在下面的示例中,我期望 unordered_mapmap 快,但事实并非如此。为什么会这样? unordered_map 是不是为了比常规地图更快而设计的?

#include <iostream>
#include <chrono>
#include <unordered_map>
#include <map>


int main()
{
    std::unordered_map<int, double> grid_unmap_int;
    std::map<int, double> grid_map_int;
    
    size_t map_size = 1e7;

    auto t1 = clock();
    for (size_t i = 0; i < map_size; ++i) {
        grid_unmap_int[i] = 1.0;
    }
    auto t2 = clock();


    for (size_t k = 0; k < map_size; ++k) {
        grid_map_int[k] = 1.0;
    }
    auto t3 = clock();

    std::cout << "Insertion \n";
    std::cout << "Filling unordered map int key: " << (t2 - t1) / static_cast<double>(CLOCKS_PER_SEC) << " seconds.\n";
    std::cout << "Filling map int key: " << (t3 - t2) / static_cast<double>(CLOCKS_PER_SEC) << " seconds.\n";
    std::cout << std::endl;

    t1 = clock();
    for (size_t i = 0; i < map_size; ++i) {
        double b = grid_unmap_int[i] ;
    }
    t2 = clock();


    for (size_t k = 0; k < map_size; ++k) {
        double b = grid_map_int[k];
    }
    t3 = clock();

    std::cout << "Retrieve \n";
    std::cout << "Filling unordered map int key: " << (t2 - t1) / static_cast<double>(CLOCKS_PER_SEC) << " seconds.\n";
    std::cout << "Filling map int key: " << (t3 - t2) / static_cast<double>(CLOCKS_PER_SEC) << " seconds.\n";


    return 0;
}

编辑: 结果: enter image description here

【问题讨论】:

  • unordered_map 并非设计为比常规地图更快。他们的工作方式不同。就像一个向量或列表。您不能称其中之一为 fastestbest。它们有强弱之分,使用哪一个取决于您的用例。
  • 您在不提供统计信息或编译标志的情况下声称性能。
  • quick-bench 建议实际上 unordered_map 对于您的特定测试用例要快 5 倍:quick-bench.com/q/OK0XfUYBuko17quF1edWLIgLdK8
  • 您的声明似乎与 cppreference 上的内容有冲突。 unordered_map - 元素的搜索、插入和删除具有平均恒定时间复杂度。 map - 搜索、删除和插入操作具有对数复杂度。跨度>
  • 你用过-O3吗?在我的系统上,unordered_map 的插入速度快了 2.8 倍,检索速度快了 10 倍。

标签: c++ stl


【解决方案1】:

在下面的示例中,我期望 unordered_mapmap 快,但事实并非如此。为什么会这样?

可能是这样,正如std::map 承诺logarithmic lookup time,而std::ordered_map 承诺constant lookup time on average, worst case linear in the size of the container

这是一种奇特的说法:“可能会更好,也可能会更糟。针对您的特定场景进行分析”。

unordered_map 的设计目的是为了比普通的map 更快吗?

是的。

std::map 只能使用有序的键。必须有一种既定的方法来对类型进行排序,例如您的示例中的int。作为回报,迭代 std::map 会为您提供该排序。

std::unordered_map 只能使用定义了std::hash&lt;Key&gt; 的键。键不需要有既定的顺序(例如,它们可以是图像。或颜色。或声音。)但必须存在某种方法将值转换为哈希。

【讨论】:

  • 实际上复杂性并不能告诉我们太多。对于所有可实现的 n(例如 n
  • @freakish 你是绝对正确的。复杂性试图描述可扩展性,而不是速度。如果按比例放大恰好将 O(1) 更改为 O(n),那么它本身就会爆炸。
  • 我的意思是,无论复杂性如何,对性能仍有一些期望。特别是在这种情况下。我知道没有保证,但是当不需要订购时,几乎每个人都会使用 map 而不是 unordered_map 而不进行测量。还有关于排序:实际上所有对象都可以排序。毕竟每个对象都表示为某个数字。可能很大,例如图像,但仍然是一个数字。
  • @freakish 如果您觉得任何措辞不合适,欢迎您编辑此答案。我可能不太清楚“有订单”与是否可以订购不同。
猜你喜欢
  • 1970-01-01
  • 2012-02-05
  • 2023-03-30
  • 2021-05-30
  • 1970-01-01
  • 1970-01-01
  • 2012-01-17
  • 1970-01-01
相关资源
最近更新 更多