为什么在unordered_map中使用find()比直接读取要快得多?

时间:2019-06-13 07:53:29

标签: c++

很难描述,所以我只显示代码:

#include <bits/stdc++.h> 
using namespace std; 

int main() 
{ 
    clock_t start, end; 
    unordered_map<int, int> m;
    long test=0;
    int size = 9999999;
    for (int i=0; i<size/3; i++) {
        m[i] = 1;
    }
    start = clock(); 
    for (int i=0; i<size; i++) {
        //if (m.find(i) != m.end())
            test += m[i];
    }
    end = clock(); 
    double time_taken = double(end - start) / double(CLOCKS_PER_SEC); 
    cout << "Time taken by program is : " << fixed  
         << time_taken << setprecision(5); 
    cout << " sec " << endl; 
    return 0; 
} 

结果(3次): 没有if (m.find(i) != m.end())

Time taken by program is : 3.508257 sec 
Time taken by program is : 3.554726 sec 
Time taken by program is : 3.520102 sec 

使用if (m.find(i) != m.end())

Time taken by program is : 1.734134 sec 
Time taken by program is : 1.663341 sec 
Time taken by program is : 1.736100 sec 

谁能解释为什么?当密钥不出现时,加m [i]里面真正发生了什么?

2 个答案:

答案 0 :(得分:7)

在此行

test += m[i];

operator[]做两件事:首先,它尝试查找给定键的条目,然后,如果该条目不存在,它将创建一个新条目。

另一方面,

if (m.find(i) != m.end())
        test += m[i];

operator[]仅做一件事:它查找具有给定键的元素(并且由于您在存在该元素之前就进行了检查,因此无需构造新条目)。

由于映射仅包含最多size/3个键,因此您的结果表明,创建元素的开销超过了首先检查该元素是否存在的开销。

在第一种情况下,地图中只有size个元素,而在第二种情况下,地图中只有size/3个元素。 请注意,地图中的元素越多,调用operator[]的成本就越高。它是Average case: constant, worst case: linear in size.,对于find也是一样。但是,多次调用这些方法,最坏的情况应该摊销,您将获得平均常数。

感谢阿空加瓜,指出您没有在地图上保留空间。在第一种情况下,您添加了许多需要分配空间的元素,而在第二种情况下,地图的大小在您测量的零件期间保持不变。尝试在循环之前调用reserve。天真的我希望在那种情况下循环会非常相似。

答案 1 :(得分:3)

使用和不使用if的区别在于您仅填充了地图的前三分之一。

如果您进行查找,则程序将继续查找该元素,如果该元素存在,则它将执行operator [],该操作将再次查找该元素(效率不高),找到它并返回值

没有if的话,当您执行operator []时。它会尝试找到该元素,然后失败,然后创建该元素(int的默认值为0),然后将其返回

因此,如果没有if,您将填充整个地图,这将增加运行时间。

如果想提高效率,可以使用查找结果获取值

auto iter = m.find(i);
if (iter != m.end()) 
{
    test += iter->second;
}