对于关键字查找,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个。
原因是通过连续内存块进行线性搜索是访问内存最便宜的方法。映射将数据保存在随机存储位置,因此访问它们的成本要高一点。在元素数量很少的情况下,这可能会起到一定作用。在有成百上千个元素的现实生活中,查找操作的算法复杂性将主导这种性能增益。
但是您的基准测试完全不同:
- 您正在填充地图。在向量的情况下,你不能这样做
- 您的代码可以执行两个映射查找:第一,find检查是否存在,第二个[]运算符查找要修改的元素。这些都是相对繁重的作业。您只需使用一个find就可以修改一个元素(自己解决这个问题,检查引用!)
- 在每个测试迭代中,您都要执行额外的繁重操作,比如为每个映射/向量分配内存。这意味着您的测试不仅在测量查找性能,而且在测量其他方面
- 基准测试是一个难题,不要自己做。例如,有一些副作用,比如缓存加热,你必须处理它们。使用类似Celero、hayai或谷歌基准测试的东西
您的向量具有恒定的内容,因此编译器无论如何都会优化大部分代码
测量这种小计数没有什么用处,测量硬编码值也没有什么用处。
相关文章:
- 如何导出包含具有"std::unique_ptr"值的"std::map"属性的
- 使用一个考虑到std::map中键值的滚动或换行的键
- 有没有办法对std::unordered_set、std::unrdered_map、std::set、std::map
- 将重物插入std::map
- 使用通用值初始化 std::map,不重复
- 仅包含可移动 std::map 的类的移动构造函数不起作用
- C++:当所有条目都保证是唯一时,替代 std::map
- 使用模板化的键类型定义 std::map,该键类型基于作为参数接收的函数
- 如果 KEY 是 std::list 或 std::vector 而不是值,那么 std::map 的默认行为是什么?
- C++如何创建 std::map
- 从其他容器中移动构造"std::map"
- 将 std::map::emplace 与返回 shared_ptr 的函数一起使用是否正确?
- C++中 std::map 的运行时复杂度是多少?
- 为什么在 std::map 上移动无法将元素从一个映射移动到另一个映射
- 使用重载 [] 运算符返回 std::map() 的可赋值
- std::map, std::unordered_map - 缩小初始值设定项列表中的转换范围
- C++ 使用枚举类对象分配 std::map 值
- 静态 std::map instatiation 在类的方法中调用构造函数吗?
- std::map:当元素不可默认构造时创建/替换元素
- Arduino编译器和STL:使用std::vector和std::map