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