关于map和list容器删除效率问题。

expter 2011-01-14 01:36:32
代码如下:

long time = timeGetTime( );
for( Mptable::iterator itr = mapnode.begin() ; itr != mapnode.end() ; )
{
delete itr->second;
mapnode.erase( itr++ );
}

std::cout <<"map : spend " << timeGetTime() - time << " second " << std::endl;

list
long time = timeGetTime( );
for( List::iterator itr = listnode.begin() ; itr != listnode.end() ; )
{
delete *itr;
itr = listnode.erase( itr );
}

std::cout <<"list : spend " << timeGetTime() - time << " second " << std::endl;


typedef std::map<long,node*> Mptable;
typedef std::list<node*> List;

Mptable mapnode;
List listnode;

每个容器都有10W个item,遍历删除,要释放item空间,然后在删除迭代器。

测试发现,list比map容器还要慢,map本身erase的时候本身会维护,list是双向链表,删除是O(1);

咋list比map容器还要慢?
还是上面的代码不能说明问题。
...全文
840 18 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
Arcticanimal 2011-01-17
  • 打赏
  • 举报
回复
编译器代码优化是针对特定代码整体上的优化,并不是针对map或list的操作,优化的结果随编译器的优化策略不同而不同。一般测试算法性能的时候最好去掉编译优化,毕竟算法大多是为通用目的设计而不是为特定代码设计,编译器优化后测试的结果就不准确了

曾经遇到过一次,VS的编译器竟然把我的要测试的整个函数都都优化掉了!最后执行时间接近为0!
后来发现是因为这个函数“在编译器看来”没有做任何“有意义”的事情,编译器并不知道这个函数是用来测试性能的,直接就给优化没了。最后通过加一个全局变量,在函数里象征性的改了一下变量的值才避过编译器的优化。。。
luciferisnotsatan 2011-01-17
  • 打赏
  • 举报
回复
mapnode.erase( itr++ );

itr = listnode.erase( itr ); // 这里也写成 listnode.erase( itr++ );试试。这里不会造成迭代器失效的



expter 2011-01-16
  • 打赏
  • 举报
回复
VS2008 release 禁用代码优化确实list快,难道优化后list比map还慢。。
gaomingok 2011-01-15
  • 打赏
  • 举报
回复
删除应该分几个步骤:1、定位 2、删除 3、重构
list在2、3步有优势,但是map在1步有优势
Arcticanimal 2011-01-15
  • 打赏
  • 举报
回复
VS2008 release 禁用代码优化,100万数据,重复测试10次,统计5次的结果(Performance Counter)

Performance Frequency: 1566064
map_erase(mp):
Repeat count: [1], Stat count: [50]
Minimum Time: [932545]
Average Time: [951295]
Summary Time: [47564785]

list_erase(ls):
Repeat count: [1], Stat count: [50]
Minimum Time: [569265]
Average Time: [588079]
Summary Time: [29403984]


测试的代码


void prev_test(std::map<int, int>& mp)
{
for(int i = 0; i < 1000000; ++i){ mp[i] = i; }
}

void map_erase(std::map<int, int>& mp)
{
while( !mp.empty() ){ mp.erase(mp.begin()); }
}

void post_test(std::map<int, int>& mp)
{
mp.clear();
}

void prev_test(std::list<int>& ls)
{
for(int i = 0; i < 1000000; ++i){ ls.push_back(i); }
}

void list_erase(std::list<int>& ls)
{
for(std::list<int>::iterator i = ls.begin(); i != ls.end(); ){ i = ls.erase(i); }
}

void post_test(std::list<int>& ls)
{
ls.clear();
}

int main(int argc, char* argv[])
{
LONGLONG perfFreq;
QueryPerformanceFrequency((LARGE_INTEGER*)&perfFreq);
std::cout << "Performance Frequency: " << perfFreq << '\n';

std::map<int, int> mp;
std::list<int> ls;
PERFORMANCE_TEST(prev_test(mp), map_erase(mp), std::cout, post_test(mp) );
PERFORMANCE_TEST(prev_test(ls), list_erase(ls), std::cout, post_test(ls) );

return 0;
}


PERFORMANCE_TEST 是一个取统计平均的宏
qq120848369 2011-01-14
  • 打赏
  • 举报
回复
为什么我这里返回值是迭代器.
expter 2011-01-14
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 qq120848369 的回复:]
为什么mapnode.erase( itr++ )不接受返回的迭代器,而list接受,你有什么理由?
[/Quote]

mapnode.erase 返回值为void
...
qq120848369 2011-01-14
  • 打赏
  • 举报
回复
为什么mapnode.erase( itr++ )不接受返回的迭代器,而list接受,你有什么理由?
iambic 2011-01-14
  • 打赏
  • 举报
回复
时间太短了,说明不了什么问题,把数据加大100倍,另外所有容器的对象类型要统一,最好是int,不要放指针,说不准你这时间都花在delete上了。
expter 2011-01-14
  • 打赏
  • 举报
回复

long time = timeGetTime( );
for( Mptable::iterator itr = mapnode.begin() ; itr != mapnode.end() ; )
{
delete itr->second;
mapnode.erase( itr++ );
}

std::cout <<"map : spend " << timeGetTime() - time << " msec " << std::endl;

time = timeGetTime( );
for( List::iterator itr = listnode.begin() ; itr != listnode.end() ; )
{
delete *itr;
itr = listnode.erase( itr );
}

std::cout <<"list : spend " << timeGetTime() - time << " msec " << std::endl;


这里是数据:
map : spend 296 msec
list : spend 407 msec
请按任意键继续. . .

vs2010 Release,数量级100W。。。
iambic 2011-01-14
  • 打赏
  • 举报
回复
贴数据。难不成还要每个看贴的人自己跑一遍?
expter 2011-01-14
  • 打赏
  • 举报
回复
10W是不能说明什么,
我用100W来测试的时候,list要慢100ms...
Arcticanimal 2011-01-14
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 expter 的回复:]

说明下
1.测试单线程,
2.map的删除有一个树维护的过程。
[/Quote]

如果程序总的执行时间小于系统线程切换时间,上面的代码没什么问题。
如果程序执行时间很长,执行的时候将有线程换入换出,如果这个换入换出发生在你两次GetTime之间,通过GetTime的差值计算运行时间就不准确了。10W次删除操作肯定已经超过线程切换时间了

我测了一下楼主的代码,这种遍历删除list比map约快一倍, 遍历删除时map的维护复杂度是常量级别的,不会造成太大影响
expter 2011-01-14
  • 打赏
  • 举报
回复
说明下
1.测试单线程,
2.map的删除有一个树维护的过程。
hai040 2011-01-14
  • 打赏
  • 举报
回复
xx = timeGetTime() - time
后再输出
直接可能输出不准
Arcticanimal 2011-01-14
  • 打赏
  • 举报
回复
1. 可能你的测试代码不严格,timeGetTime 处理线程被换出了吗?Win上面20ms线程就换出一次,要注意把线程换出的时间减掉,或者重复测试。
2. 使用release编译选项,但是去掉编译器优化
3. 遍历时进行map的删除操作总是在叶子节点上进行,这个也是O(1)吧

65,186

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧