繁体   English   中英

std :: vector比std :: map更快的键查找?

[英]std::vector is faster than std::map for a key lookup?

我一直在使用std :: vector,并且想知道是否应该使用std :: map进行关键查找以提高性能。

这是我完整的测试代码。

#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <ctime>
#include <chrono>

using namespace std;

vector<string> myStrings = {"aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk", "lll", "mmm", "nnn", "ooo", "ppp", "qqq", "rrr", "sss", "ttt", "uuu", "vvv", "www", "xxx", "yyy", "zzz"};

struct MyData {

    string key;
    int value;
};

int findStringPosFromVec(const vector<MyData> &myVec, const string &str) {

    auto it = std::find_if(begin(myVec), end(myVec),
                           [&str](const MyData& data){return data.key == str;});
    if (it == end(myVec))
        return -1;
    return static_cast<int>(it - begin(myVec));
}

int main(int argc, const char * argv[]) {

    const int testInstance = 10000; //HOW MANY TIMES TO PERFORM THE TEST

    //----------------------------std::map-------------------------------
    clock_t map_cputime = std::clock(); //START MEASURING THE CPU TIME

    for (int i=0; i<testInstance; ++i) {

        map<string, int> myMap;

        //insert unique keys
        for (int i=0; i<myStrings.size(); ++i) {

            myMap[myStrings[i]] = i;
        }
        //iterate again, if key exists, replace value;
        for (int i=0; i<myStrings.size(); ++i) {

            if (myMap.find(myStrings[i]) != myMap.end())
                myMap[myStrings[i]] = i * 100;
        }
    }
    //FINISH MEASURING THE CPU TIME
    double map_cpu = (std::clock() - map_cputime) / (double)CLOCKS_PER_SEC;
    cout << "Map Finished in " << map_cpu << " seconds [CPU Clock] " << endl;


    //----------------------------std::vector-------------------------------
    clock_t vec_cputime = std::clock(); //START MEASURING THE CPU TIME

    for (int i=0; i<testInstance; ++i) {

        vector<MyData> myVec;

        //insert unique keys
        for (int i=0; i<myStrings.size(); ++i) {

            const int pos = findStringPosFromVec(myVec, myStrings[i]);

            if (pos == -1)
                myVec.push_back({myStrings[i], i});
        }
        //iterate again, if key exists, replace value;
        for (int i=0; i<myStrings.size(); ++i) {

            const int pos = findStringPosFromVec(myVec, myStrings[i]);

            if (pos != -1)
                myVec[pos].value = i * 100;
        }
    }
    //FINISH MEASURING THE CPU TIME
    double vec_cpu = (std::clock() - vec_cputime) / (double)CLOCKS_PER_SEC;
    cout << "Vector Finished in " << vec_cpu << " seconds [CPU Clock] " << endl;
    return 0;
}

这就是我得到的结果。

Map Finished in 0.38121 seconds [CPU Clock] 
Vector Finished in 0.346863 seconds [CPU Clock] 
Program ended with exit code: 0

我通常在一个容器中存储少于30个元素。

这是否意味着在我的情况下最好使用std :: vector而不是std :: map?

编辑:当我移动map<string, int> myMap; 在循环之前,std :: map比std :: vector更快。

Map Finished in 0.278136 seconds [CPU Clock] 
Vector Finished in 0.328548 seconds [CPU Clock] 
Program ended with exit code: 0

因此,如果这是正确的测试,我想std :: map会更快。

但是,如果我将元素数量减少到10,则std :: vector会更快,因此我猜它实际上取决于元素的数量。

我要说的是,一般而言,矢量在查找方面可能比映射更好,但仅用于少量数据,例如,您提到的元素少于30个。

原因是通过连续内存块进行线性搜索是访问内存的最便宜方法。 映射将数据保存在随机的内存位置,因此访问它们的开销会更高一些。 在元素数量很少的情况下,这可能会起作用。 在具有成千上万个元素的现实生活中,查找操作的算法复杂性将主导这种性能提升。

但! 您正在对完全不同的基准进行基准测试:

  1. 您正在填充地图。 如果是向量,则不要这样做
  2. 您的代码可以执行两次映射查找:首先, 查找以检查是否存在,第二个[]运算符以查找要​​修改的元素。 这些是相对繁重的操作。 您可以只用一次查找就修改一个元素(自己弄清楚,检查引用!)
  3. 在每个测试迭代中,您将执行其他繁重的操作 ,例如为每个映射/向量分配内存。 这意味着您的测试不仅在衡量查找性能,而且还在衡量其他内容。
  4. 基准测试是一个困难的问题,请不要自己做。 例如,有一些副作用,例如高速缓存加热,您必须对其进行处理。 使用诸如CeleroHayaiGoogle基准之类的东西

向量具有恒定的内容,因此无论如何编译器都会优化大多数代码。
测量这么小的计数几乎没有用,测量硬编码值也没有用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM