1 源码
#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
#include <ctime>
#include "stdlib.h"
using namespace std;
// 判断成绩是否及格
bool pgrade(double x)
{
if(x>=60)
return true;
else
return false;
}
// 判断成绩是否不及格
bool fgrade(double x)
{
return !pgrade(x);
}
int main()
{
vector<double> grades_tmp, grades, fail, pass;
vector<double>::iterator iter;
clock_t time_start, time_end;
// 在0到100中随机生成75000个成绩
for (int i=0; i<75000; i++)
grades_tmp.push_back(rand()%100);
// 循环所有元素,取出不及格成绩后erase
grades.assign(grades_tmp.begin(), grades_tmp.end());
time_start = clock();
iter = grades.begin();
while (iter < grades.end())
{
if(fgrade(*iter))
{
fail.push_back(*iter);
iter = grades.erase(iter);
}
else
iter++;
}
pass.assign(grades.begin(), grades.end());
time_end = clock();
cout << "erase time is: " << double(time_end-time_start) << endl;
// 两次访问,取出及格和不及格成绩(使用remove_copy_if和remove_if)
grades.clear();
fail.clear();
pass.clear();
grades.assign(grades_tmp.begin(), grades_tmp.end());
time_start = clock();
remove_copy_if(grades.begin(), grades.end(), back_inserter(fail), pgrade);
grades.erase(remove_if(grades.begin(), grades.end(), fgrade), grades.end());
pass.assign(grades.begin(), grades.end());
time_end = clock();
cout << "twice visit: " << double(time_end-time_start) << endl;
//一次访问,取出及格和不及格成绩(使用stable_partition)
grades.clear();
fail.clear();
pass.clear();
grades.assign(grades_tmp.begin(), grades_tmp.end());
time_start = clock();
iter = stable_partition(grades.begin(), grades.end(), pgrade);
fail.assign(iter,grades.end());
grades.erase(iter,grades.end());
pass.assign(grades.begin(), grades.end());
time_end = clock();
cout << "single visit: " << double(time_end-time_start) << endl;
}
2 代码解释
2.1 遍历所有元素,使用erase删除元素
- 在
vector
中删除元素时,指向被删除元素和它后面元素的迭代器都失效了;如果添加一个元素,可能导致所有内容重新分配,所有迭代器均失效。因此在循环中使用erase
操作时,要特别注意。不过erase
删除元素后会返回一个迭代器指向删除元素的下一个元素。 - 如果
vector
中的数据量比较大,利用erase
删除元素,效率特别低。
2.2 两次访问grades,使用remove_copy_if和remove_if删除元素
- 对
remove_copy_if
的理解:某些记录if
满足某条件,则remove
,copy
剩下的到指定位置。当然这里的remove
不是真的从vector
中删除。 - 对
remove_if
的理解:某条记录if
满足某条件,则remove
,把紧接着、未移动过的不“删除”元素重写在该位置。以remove_if(grades.begin(), grades.end(), fgrade)
为例,过程和结果见示意图。
2.3 一次访问grades,使用stable_partition删除元素
- 前者对
grades
访问和计算两次,用partion
和stable_partion
可以实现一次访问和计算。 partition
会在每个分类的内部重新排列元素;stable_partition
除了会划分种类以外,还会保持每个种类内部的元素顺序不变。
3 效率对比
3种方法的效率之比为 118 : 1.4 : 1。
Reference
[1] Accelerated c++. Andrew Koenig