vector中高效刪除元素


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滿足某條件,則removecopy剩下的到指定位置。當然這里的remove不是真的從vector中刪除。
  • remove_if的理解:某條記錄if滿足某條件,則remove,把緊接着、未移動過的不“刪除”元素重寫在該位置。以remove_if(grades.begin(), grades.end(), fgrade)為例,過程和結果見示意圖。

2.3 一次訪問grades,使用stable_partition刪除元素

  • 前者對grades訪問和計算兩次,用partionstable_partion可以實現一次訪問和計算。
  • partition會在每個分類的內部重新排列元素;stable_partition除了會划分種類以外,還會保持每個種類內部的元素順序不變。

3 效率對比

3種方法的效率之比為 118 : 1.4 : 1。

Reference

[1] Accelerated c++. Andrew Koenig


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM