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

posted @ 2019-05-20 23:00  ggyy198310  阅读(4444)  评论(0编辑  收藏  举报