C++中map/set和unordered_map/unordered_set的区别及其适用情况
文章目录map/set与unordered_map/unordered_set的区别map/set与unordered_map/unordered_set性能测试测试结论map/set与unordered_map/unordered_set的区别map/set与unordered_map/unordered_set性能测试测试结论根据测试结果可以得出以下结论:当处理数据量小时,map/set容器与
map/set与unordered_map/unordered_set的区别
xxx容器与unordered_xxx容器对上层所提供函数接口的名字和功能虽然一致,但它们的底层实现却大不相同,xxx容器和unordered_xxx容器的区别如下:
容器 | 底层数据结构 | 是否有序 | 实现版本 | 增删查改的效率 | 迭代器类型 |
---|---|---|---|---|---|
unordered_map/unordered_set | 哈希表/散列表 | 遍历无序 | C++11 | O ( 1 ) O(1) O(1) | 单向迭代器 |
map/set | 红黑树 | 遍历有序 | C++98 | O ( l o g N ) O(logN) O(logN) | 双向迭代器 |
map/set与unordered_map/unordered_set的性能测试
map容器与unordered_map容器的差别和set容器与unordered_set容器的差别类似,下面我们以set容器和unordered_set容器的测试为例。
说到一个容器的性能,我们最关心的实际就是该容器增删查改的效率。我们可以通过下列代码测试set容器和unordered_set容器insert、find以及erase的效率。
#include <iostream>
#include <set>
#include <unordered_set>
#include <time.h>
using namespace std;
int main()
{
int N = 1000;
vector<int> v;
v.reserve(N);
srand((unsigned int)time(NULL));
//随机生成N个数字
for (int i = 0; i < N; i++)
{
v.push_back(rand());
}
/****************插入效率测试****************/
//将这N个数插入set容器
set<int> s;
clock_t begin1 = clock();
for (auto e : v)
{
s.insert(e);
}
clock_t end1 = clock();
//将这N个数插入unordered_set容器
unordered_set<int> us;
clock_t begin2 = clock();
for (auto e : v)
{
us.insert(e);
}
clock_t end2 = clock();
//分别输出插入set容器和unordered_set容器所用的时间
cout << "set insert: " << end1 - begin1 << endl;
cout << "unordered_set insert: " << end2 - begin2 << endl;
/****************查找效率测试****************/
//在set容器中查找这N个数
clock_t begin3 = clock();
for (auto e : v)
{
s.find(e);
}
clock_t end3 = clock();
//在unordered_set容器中查找这N个数
clock_t begin4 = clock();
for (auto e : v)
{
us.find(e);
}
clock_t end4 = clock();
//分别输出在set容器和unordered_set容器中查找这N个数所用的时间
cout << "set find: " << end3 - begin3 << endl;
cout << "unordered_set find: " << end4 - begin4 << endl;
/****************删除效率测试****************/
//将这N个数从set容器中删除
clock_t begin5 = clock();
for (auto e : v)
{
s.erase(e);
}
clock_t end5 = clock();
//将这N个数从unordered_set容器中删除
clock_t begin6 = clock();
for (auto e : v)
{
us.erase(e);
}
clock_t end6 = clock();
//分别输出将这N个数从set容器和unordered_set容器中删除所用的时间
cout << "set erase: " << end5 - begin5 << endl;
cout << "unordered_set erase: " << end6 - begin6 << endl;
return 0;
}
对1000个数做增删查改操作
当N为1000时,set容器和unordered_set容器增删查改的效率差异并不大,在Debug版本下的测试结果如下:
在Release版本下,set容器和unordered_set容器对1000个数做增删查改操作所用的时间更是被优化到了接近0毫秒。
对10000000个数做增删查改操作
而当N为10000000时,set容器和unordered_set容器增删查改的效率的差异就很明显了,在Debug版本下的测试结果如下:
而经过Release版本优化后,unordered_set容器对10000000个数做查找和删除操作所用的时间还是被优化到了接近0毫秒,插入操作所用的时间也仅仅是0.1秒左右。但是set容器对10000000个数做增删查改操作所用的时间还是需要1秒左右,与unordered_set容器相比就占了下风。
注意: 这里给出的N值仅作参考,在不同的测试环境下可能不同。
测试结论
根据测试结果可以得出以下结论:
- 当处理数据量小时,map/set容器与unordered_map/unordered_set容器增删查改的效率差异不大。
- 当处理数据量大时,map/set容器与unordered_map/unordered_set容器增删查改的效率相比,unordered系列容器的效率更高。
因此,当处理数据量较小时,选用xxx容器与unordered_xxx容器的差异不大;当处理数据量较大时,建议选用对应的unordered_xxx容器。
补充一点: 当需要存储的序列为有序时,应该选用map/set容器。
更多推荐
所有评论(0)