C++ STL 中查找速度最快的是什么数据结构?

2020-12-04 21:37:30 +08:00
 black11black

如题,C++不太熟,最近有个需求是要把 python 科学计算代码用 C++加速,写的过程中遇到问题就来问 V 友了。

目前要实现一个类似 python 中字典映射的操作,即比如输入 token = "sam" ,要求能够快速的获取到某数据结构(比如说一个 vector )中 sam 对应的指定项。据我所知 vector 原生可以用角标提取,但应该是不支持用字符串提取这种的,即 v[0]这种是 OK 的但是 v["sam"]这种应该是不行的。

由于我不清楚 stl 容器具体的搜索实现,并不能确定用哪种方式会更快。因为我知道 py 的字典查找经过了 hash 优化,如果 c++不好好选择算法的话,一个搞不好比 python 更慢也是有可能的。

网上搜到一些资料显示 vector 比 set 查找更快,而另一些资料则显示相反,互相矛盾,看不太懂。求问一下 c++带佬,这种常见数据结构在 c++里的最佳实践是什么?

===========================

另外之前 v2 一个老哥似乎说过 map 查找速度超级慢

2696 次点击
所在节点    问与答
12 条回复
lcdtyph
2020-12-04 21:41:03 +08:00
unordered_map
agagega
2020-12-04 21:41:42 +08:00
你想要的是 unordered_map
DGideas
2020-12-04 21:45:15 +08:00
楼上正解,另外也别这么黑 map 啊。。。充其量查找速度还是对数时间复杂度呢。。
secondwtq
2020-12-04 22:15:47 +08:00
vector 只能整数 index 这只是个接口问题而已,你自己往里面存个 pair 自己写函数查也可以
C++ 社区的意思是,所有涉及到 pointer chasing 的都慢,所以 std::list 是垃圾,vector FTW
所以如果数据小的话,就直接用 vector 线性查,可能比其他数据结构还要快,这个叫 flat map (不是 Monad bind 的那个 flatmap )
另外,vector 还会加一个 SBO 的优化,这样就可以完全避免内存分配,这个叫 small vector

unordered_map 在性能方面的问题在于它是 chaining 实现的,内存性能一般不如 open addressing,所以有时候会用 open_addressing 的实现,这个叫 dense_map
unordered_map 的优势在于迭代器稳定,map 的优势在于 ordered access

至于查字符串还有专门的数据结构

至于楼主这个,你得自己 benchmark
black11black
2020-12-04 23:27:35 +08:00
@secondwtq 大佬再问个事,有关插入,读取和删除的效率。目前需要对一个表类数据结构频繁操作,对应的是 py 的 list,插入,读取,删除我粗略估计在 5:10:3 这样的比例,用 vector 是正确选择吗?因为听说 vec 读取很快,但是删除开销很高。如果用链表的话哪个更合适?
QBugHunter
2020-12-05 10:41:54 +08:00
@black11black
vector 时这样的,比如你要储存 10000 个对象,然后 vector 会申请一块连续的内存,可能可以存放 20000 个(这个值不同版本的 STL 有所不同),然后你要在尾部插入 10 个,或者删除 10 个,速度很快
但如果你要在尾部再插入 10000 个对象,vector 就会再申请一块 40000 个对象长度的内存,然后把 20000 个对象复制进去
wctml
2020-12-05 14:57:53 +08:00
年轻人 你不讲武德,为什么查同一位置;

```
unordered_map<int, float> mapValue;
clock_t timeStart = clock();
for (size_t index(0); index < 10000000; ++index)
{
mapValue[index] = 1000000 - index;
}
std::cout << "make time " << (clock() - timeStart) << std::endl;
double sum(0);
timeStart = clock();
for (size_t index(0); index < 10000000; ++index)
{
sum += mapValue[9999999];
}
std::cout << "find time " << (clock() - timeStart) << std::endl;

sum = 0;
timeStart = clock();
for (size_t index(0); index < 10000000; ++index)
{
const auto& iter = mapValue.find(9999999);
if (iter != mapValue.end())
{
sum += iter->second;
}
}
std::cout << "find time " << (clock() - timeStart) << std::endl;
```

make time 3432
find time 39
find time 7
black11black
2020-12-05 18:44:35 +08:00
@wctml 这方代码啥意思大佬,uo_map 的搜索比索隐快的多的意思吗?
black11black
2020-12-05 18:45:50 +08:00
有需要大量用到排序的数据结构,网上查了查似乎是 deque 最快,然而实测还是 vector 快,序列长度在一万左右。也是神秘
wctml
2020-12-07 09:26:49 +08:00
@black11black
1 、这是 C++坑的地方,在不同的用法,有不同的区别。这点不像 python 做一个事情可能只有一个最优解,但是 C++可能有 N 个解法得你去踩坑。
2 、可以了解 C ++中的 map []和 map.at 的区别;
3 、另外查找同一个位置可能编译器会有优化的,可以试试伪随机搜索效率测试。
wctml
2020-12-07 09:27:45 +08:00
sum = 0;
timeStart = clock();
for (size_t index(0); index < 10000000; ++index)
{
sum += mapValue.at(9999999);
}
std::cout << "find time " << (clock() - timeStart) << std::endl;

find time 7
wctml
2020-12-07 09:29:47 +08:00
```
sum = 0;
timeStart = clock();
for (size_t index(0); index < 10000000; ++index)
{
sum += mapValue 。at(9999999);
}
std::cout << "find time " << (clock() - timeStart) << std::endl;

find time 7
```

请不要在每一个回复中都包括外链,这看起来像是在 spamming
我只能把点换成句号

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/732273

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX