vector中高效删除元素

博客围绕Rust中删除元素展开,介绍了三种方法。一是遍历用erase删除,删除后迭代器会变化,大数据量时效率低;二是两次访问用remove_copy_if和remove_if;三是一次访问用stable_partition。还给出三种方法的效率之比为118 : 1.4 : 1。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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)为例,过程和结果见示意图。
    1692249-20190524190740718-1495842824.png

2.3 一次访问grades,使用stable_partition删除元素

  • 前者对grades访问和计算两次,用partionstable_partion可以实现一次访问和计算。
  • partition会在每个分类的内部重新排列元素;stable_partition除了会划分种类以外,还会保持每个种类内部的元素顺序不变。
    1692249-20190525000353680-1061900420.png

3 效率对比

3种方法的效率之比为 118 : 1.4 : 1。

Reference

[1] Accelerated c++. Andrew Koenig

转载于:https://www.cnblogs.com/uarekoalaiamtree/p/10897150.html

在 C++ STL 的 `vector` 容器中,删除元素是常见的操作,常用的方法包括 `erase()` 和 `pop_back()`。这两种方法分别适用于不同的场景,具有不同的行为特性。 ### 使用 `erase()` 删除元素 `erase()` 方法允许从 `vector` 中删除一个或多个指定位置的元素。该方法有两种常见形式: 1. **删除单个元素**: ```cpp iterator erase(const_iterator position); ``` 此形式接受一个迭代器参数,表示要删除元素的位置,返回指向被删除元素之后元素的迭代器。 示例代码: ```cpp #include <iostream> #include <vector> int main() { std::vector<int> vec = {1, 2, 3, 4, 5}; auto pos = vec.begin() + 2; vec.erase(pos); // 删除位置为2的元素(即数字3) for (const auto& elem : vec) { std::cout << elem << " "; } std::cout << std::endl; return 0; } ``` 输出结果为:`1 2 4 5`[^1] 2. **删除一定范围内的元素**: ```cpp iterator erase(const_iterator first, const_iterator last); ``` 此形式接受两个迭代器参数,表示要删除元素范围 `[first, last)`,返回指向最后一个被删除元素之后的迭代器。 示例代码: ```cpp #include <iostream> #include <vector> int main() { std::vector<int> numbers = {10, 20, 30, 40, 50}; numbers.erase(numbers.begin() + 1, numbers.begin() + 4); // 删除从 index=1 到 index=3 的元素 std::cout << "容器的元素为:"; for (const auto& number : numbers) { std::cout << number << " "; } std::cout << std::endl; return 0; } ``` 输出结果为:`10 50`[^4] ### 使用 `pop_back()` 删除元素 `pop_back()` 方法用于删除 `vector` 容器中的最后一个元素。此方法没有参数且不返回任何值,仅适用于需要移除末尾元素的情况。 ```cpp void pop_back(); ``` 示例代码: ```cpp #include <iostream> #include <vector> using namespace std; int main() { int a[] = {1, 2, 3, 4}; vector<int> v(a, a + sizeof(a) / sizeof(int)); vector<int>::iterator it = v.begin(); while (it != v.end()) { cout << *it << " "; ++it; } cout << endl; v.pop_back(); // 删除最后一个元素 v.pop_back(); // 再次删除最后一个元素 it = v.begin(); while (it != v.end()) { cout << *it << " "; ++it; } cout << endl; return 0; } ``` 输出结果为: ``` 1 2 3 4 1 2 ``` ### `erase()` 和 `pop_back()` 的区别与选择 - **`erase()` 的适用场景**: - 需要删除任意位置的元素时使用。 - 支持删除单个元素或多段连续元素。 - 返回新的有效迭代器,便于后续操作。 - **`pop_back()` 的适用场景**: - 仅需删除末尾元素时使用。 - 操作简单高效,但功能有限。 选择合适的方法取决于具体需求。如果目标是删除容器末尾的元素,则优先考虑 `pop_back()`;若需要删除中间或开头的元素,则应使用 `erase()`。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值