免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 8544 | 回复: 7
打印 上一主题 下一主题

std::list调用std::remove_if比list::remove到底哪个快? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-04-09 11:01 |只看该作者 |倒序浏览
本帖最后由 zuiwei 于 2012-04-09 11:02 编辑

<<effective stl>> 书上说list用remove_if比remove快,中文版原文是这样的:
去除一个容器中满足一个特定判定式的所有对象:
如果容器是vector、string或deque,使用erase-remove_if惯用法。
如果容器是list,使用list::remove_if。
如果容器是标准关联容器,使用remove_copy_if和swap,或写一个循环来遍历容器元素,当你把迭代器传给erase时记得后置递增它。

×××××××××××××××××××××××××××××××××××××××××
但是问题是既然都是遍历一遍然后删除,凭什么说std::remove_if比list::remove要快?

我测试了一下发现这个说法并不准确。下面这个代码
(1)元素个数是50k和200k的时候,std::remove_if快
(2)元素个数2M/5M个的时候,remove快。

这是为什么?
<<effective stl>>书上的说法是否确切,

  1. #include"stdafx.h"
  2. #include<windows.h>
  3. #include<algorithm>
  4. #include<iostream>
  5. #include<iterator>
  6. #include<string>
  7. #include<deque>
  8. #include<list>
  9. #include<vector>
  10. using namespace std;
  11. int main(void){
  12. #define LOOP 5000000
  13.         typedef int valuetype;
  14.         typedef list<valuetype> li;
  15.         {
  16.                 li vli;
  17.                 for(int i=0;i<LOOP;++i){
  18.                         vli.push_back(1);
  19.                         vli.push_back(2);
  20.                 }
  21.                 DWORD ret1=GetTickCount();        
  22.                 vli.remove(2);
  23.                 DWORD ret2=GetTickCount();        
  24.                 cout<<"list shrink:"<<ret2-ret1<<endl;
  25.         }
  26.         {
  27.                 li vli;
  28.                 for(int i=0;i<LOOP;++i){
  29.                         vli.push_back(1);
  30.                         vli.push_back(2);
  31.                 }
  32.                 DWORD ret1=GetTickCount();        
  33.                 remove_if(vli.begin(),vli.end(),[=](valuetype i){return i==2;});
  34.                 DWORD ret2=GetTickCount();        
  35.                 cout<<"list shrink:"<<ret2-ret1<<endl;
  36.         }
  37.         return 0;
  38. }
复制代码

论坛徽章:
14
巨蟹座
日期:2013-11-19 14:09:4615-16赛季CBA联赛之青岛
日期:2016-07-05 12:36:0515-16赛季CBA联赛之广东
日期:2016-06-29 11:45:542015亚冠之全北现代
日期:2015-07-22 08:09:472015年辞旧岁徽章
日期:2015-03-03 16:54:15巨蟹座
日期:2014-12-29 08:22:29射手座
日期:2014-12-05 08:20:39狮子座
日期:2014-11-05 12:33:52寅虎
日期:2014-08-13 09:01:31巳蛇
日期:2014-06-16 16:29:52技术图书徽章
日期:2014-04-15 08:44:01天蝎座
日期:2014-03-11 13:06:45
2 [报告]
发表于 2012-04-09 11:20 |只看该作者
我这人看到烂代码就喜欢改一下,楼主莫怪
  1. #include <iostream>
  2. #include <algorithm>
  3. #include <list>
  4. #include <ctime>
  5. using namespace std;

  6. int main(void)
  7. {
  8.     const size_t LOOP = 5000000;

  9.     typedef list<int> li;
  10.     {
  11.         li vli;
  12.         for( size_t i=0; i<LOOP; ++i )
  13.         {
  14.             vli.push_back( i&1 ? 2 : 1 );
  15.         }
  16.         clock_t ret1 = clock();
  17.         vli.remove( 2 );
  18.         clock_t ret2 = clock();
  19.         cout << "list shrink:" << ret2-ret1 << endl;
  20.     }
  21.     {
  22.         li vli;
  23.         for( size_t i=0; i<LOOP; ++i )
  24.         {
  25.             vli.push_back( i&1 ? 2 : 1 );
  26.         }
  27.         clock_t ret1 = clock();
  28.         vli.erase( remove(vli.begin(),vli.end(),2), vli.end() );
  29.         clock_t ret2 = clock();
  30.         cout << "list shrink:" << ret2-ret1 << endl;
  31.     }

  32.     return 0;
  33. }
复制代码

论坛徽章:
0
3 [报告]
发表于 2012-04-09 13:17 |只看该作者
bruceteen 发表于 2012-04-09 11:20
我这人看到烂代码就喜欢改一下,楼主莫怪


我测试了3个版本,remove,remove_if和erase+remove。发现一个比一个慢:

  1. #include"stdafx.h"
  2. #include<windows.h>
  3. #include<algorithm>
  4. #include<iostream>
  5. #include<iterator>
  6. #include<string>
  7. #include<deque>
  8. #include<list>
  9. #include<vector>
  10. using namespace std;
  11. int main(void){
  12. #define LOOP 5000000
  13.         typedef int valuetype;
  14.         typedef list<valuetype> li;
  15.         {
  16.                 li vli;
  17.                 for(int i=0;i<LOOP;++i){
  18.                         vli.push_back(1);
  19.                         vli.push_back(2);
  20.                 }
  21.                 DWORD ret1=GetTickCount();        
  22.                 vli.remove(2);
  23.                 DWORD ret2=GetTickCount();        
  24.                 cout<<"list shrink:"<<ret2-ret1<<endl;
  25.         }
  26.         {
  27.                 li vli;
  28.                 for(int i=0;i<LOOP;++i){
  29.                         vli.push_back(1);
  30.                         vli.push_back(2);
  31.                 }
  32.                 DWORD ret1=GetTickCount();        
  33.                 remove_if(vli.begin(),vli.end(),[=](valuetype i){return i==2;});
  34.                 DWORD ret2=GetTickCount();        
  35.                 cout<<"list shrink:"<<ret2-ret1<<endl;
  36.         }
  37.         {
  38.                 li vli;
  39.                 for(int i=0;i<LOOP;++i){
  40.                         vli.push_back(1);
  41.                         vli.push_back(2);
  42.                 }
  43.                 DWORD ret1=GetTickCount();        
  44.                 vli.erase(remove(vli.begin(),vli.end(),2),vli.end());
  45.                 DWORD ret2=GetTickCount();        
  46.                 cout<<"list shrink:"<<ret2-ret1<<endl;
  47.         }        return 0;
  48. }
复制代码
list shrink:547
list shrink:610
list shrink:1797

这是为什么呢? 我感觉3个时间应该基本一致才对啊

论坛徽章:
0
4 [报告]
发表于 2012-04-09 15:38 |只看该作者
第二个忘记 erase 了。

顶楼的代码也是……

论坛徽章:
0
5 [报告]
发表于 2012-04-09 17:26 |只看该作者
变异老鼠 发表于 2012-04-09 15:38
第二个忘记 erase 了。

顶楼的代码也是……


加上了以后,结果也一样啊

论坛徽章:
0
6 [报告]
发表于 2012-04-09 17:41 |只看该作者
g++ 4.6.3 x86-64
-std=gnu++0x -Wall -Wextra -O2
  1. #include <algorithm>
  2. #include <iostream>
  3. #include <list>

  4. #include <stdint.h>

  5. using namespace std;

  6. inline uint64_t rdtsc()
  7. {
  8.     uint32_t eax, edx;
  9.     asm("rdtsc" : "=a"(eax), "=d"(edx));
  10.     return ((uint64_t)edx << 32) | eax;
  11. }

  12. int main(void){
  13.     int const LOOP = 50000;
  14.     typedef int valuetype;
  15.     typedef list<valuetype> li;
  16.     {
  17.         // CPU warming up
  18.         uint64_t const CLOCKS_TO_WAIT = 1000000000;
  19.         uint64_t start = rdtsc();
  20.         while(rdtsc() - start < CLOCKS_TO_WAIT)
  21.             ;
  22.     }
  23.     {
  24.         li vli;
  25.         for(int i=0;i<LOOP;++i){
  26.             vli.push_back(1);
  27.             vli.push_back(2);
  28.         }
  29.         uint64_t ret1 = rdtsc();
  30.         vli.remove(2);
  31.         uint64_t ret2 = rdtsc();
  32.         cout<<"list shrink:"<<ret2-ret1<<endl;
  33.     }
  34.     {
  35.         li vli;
  36.         for(int i=0;i<LOOP;++i){
  37.             vli.push_back(1);
  38.             vli.push_back(2);
  39.         }
  40.         uint64_t ret1 = rdtsc();
  41.         vli.erase(remove_if(vli.begin(),vli.end(),[=](valuetype i){return i==2;}), vli.end());
  42.         uint64_t ret2 = rdtsc();
  43.         cout<<"list shrink:"<<ret2-ret1<<endl;
  44.     }
  45.     {
  46.         li vli;
  47.         for(int i=0;i<LOOP;++i){
  48.             vli.push_back(1);
  49.             vli.push_back(2);
  50.         }
  51.         uint64_t ret1 = rdtsc();
  52.         vli.erase(remove(vli.begin(),vli.end(),2),vli.end());
  53.         uint64_t ret2 = rdtsc();
  54.         cout<<"list shrink:"<<ret2-ret1<<endl;
  55.     }
  56.     return 0;
  57. }
复制代码
list shrink:2559236
list shrink:4978882
list shrink:4897164

论坛徽章:
0
7 [报告]
发表于 2012-04-09 17:43 |只看该作者
变异老鼠 发表于 2012-04-09 17:41
g++ 4.6.3 x86-64
-std=gnu++0x -Wall -Wextra -O2list shrink:2559236
list shrink:4978882


还是remove最快,erase(remove_if)和erase(remove)都很慢

论坛徽章:
0
8 [报告]
发表于 2012-04-09 19:03 |只看该作者
好吧,忽然发现之前都没看清楚你的问题……

书上说的是:对于 list,用 list::remove_if;对于其他三个容器,用 std::remove_if + std::erase。

这里没有 list::remove 什么事。

如果是 list::remove_if 和 list::remove 相比,只要编译器能把函数对象优化掉,速度应该是差不多的。

std::remove_if 和 std::remove 相比也一样。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP