C++中vector的删除

2023-10-27

在vector中有三种涉及删除的方法,第一种是vector::clear(),第二种是vector::erase(),第三种是vector::pop_back()。

clear用来清空整个vector,同时将size变成0,无返回值;

erase通过传入迭代器进行删除,既可以删除单个元素,也可以删除某一范围的元素,删除之后它将返回下一个位置的迭代器;

pop_back用来删除末尾元素,同时将size减1,无返回值。

vector<int> vec{1, 4, 3, 2, 5, 2};
	
for(auto it = vec.begin(); it != vec.end(); it++){
	if(*it < 3){
		cout << "num is " << *it << endl;
		it = vec.erase(it);
		if(it == vec.end()) break;
	}
}

这个代码如果不在for循环里加上最后的判断会导致错误,原因在于,当it指向最后一个2时,满足删除条件,删除后it变成了end,然后又做了++操作,导致越界。

类似的坑还有许多,这里就不一一列举了,总之,它们的共同点在于对vector进行删除时都不够优雅,需要进行一些额外的处理避免误操作。
 

事实上,我们完全可以使用<algorithm>提供的remove和remove_if方法,配合erase进行删除。

remove的作用是将等于value的元素放到vector的尾部,但并不减少vector的size

这两个方法并不是真的删除元素,而是以覆盖的方式将满足删除条件的元素移到容器最后(它们具体的实现方式很有意思,但是这里从略,总之有两点:1)它们并没有真的删除元素;2)它们使用了“覆盖”的方式,将要删除的元素移到最后,因此这些元素可能因为被覆盖过而发生改变,但这已经不重要了),然后返回指向第一个要删除位置的迭代器。这样一来,删除就优雅多了,例如:
 

vec.erase(remove(vec.begin(), vec.end(), 3), vec.end());

如果再用上lambda,看起来会更酷:

Remove_if()有三个参数:

1、   iterator _First:指向第一个数据的迭代指针。

2、   iterator _Last:指向最后一个数据的迭代指针。

3、   predicate _Pred:一个可以对迭代操作的条件函数。

vec.erase(remove_if(vec.begin(), vec.end(), [](int x){return x == 3;}), vec.end());

 

remove   算法描述:查找的得到第一个元素的位置,然后从此位置开始遍历容器,将后面的元素依次前移,跳过和value相同值的元素,也就是说,所有和value相同值的元素都会被覆盖,而其他的元素都会依次前移。最后remove返回"指向最后一个   '有用'   元素的iterator",但是在remove算法过程中,并没有修改原容器的size,以及end()。但是从逻辑角度看,最后的[   从remove得到的iterator---_result,   容器的结尾end()   )   这个区间里面的元素已经没有意义了。所以这些元素不应该属于该容器了。remove算法能做的仅此而已,并没有删除这些无用的元素。    


 结论:移除容器里面的元素不应该使用remove算法,而是容器自己的方法erase()。
erase使用:

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> arr;
    arr.push_back(6);
    arr.push_back(7);
    arr.push_back(8);
    arr.push_back(9);
    for(vector<int>::iterator it=arr.begin(); it!=arr.end(); )
    {
        if(* it == 8)
        {
            it = arr.erase(it);
        }
        else
        {
            ++it;
        }
    }

  //注意上面不能写成
    /*
        for(vector<int>::iterator it=arr.begin(); it!=arr.end(); it ++)
        {
            if(* it == 8)
            {
                arr.erase(it);     //在erase后,it失效,并不是指向vector的下一个元素,it成了一个“野指针”。
            }
        }
    */
}

*******************************************************************************************

条款32:如果你真的想删除东西的话就在类似remove的算法后接上erase

只有容器成员函数可以除去容器元素:如果你真的要删除东西的话,你应该在remove后面接上erase。

你要erase的元素很容易识别。它们是从区间的“新逻辑终点”开始持续到区间真的终点的原来区间的元素。要除去那些元素,你要做的所有事情就是用那两个迭代器调用erase的区间形式(参见条款5)。因为remove本身很方便地返回了区间新逻辑终点的迭代器,这个调用很直截了当:

vector<int> v;						// 正如从前
v.erase(remove(v.begin(), v.end(), 99), v.end());		// 真的删除所有
							// 等于99的元素
cout << v.size();						// 现在返回7

把remove的返回值作为erase区间形式第一个实参传递很常见,这是个惯用法。事实上,remove和erase是亲密联盟,这两个整合到list成员函数remove中。这是STL中唯一名叫remove又能从容器中除去元素的函数:

list<int> li;			// 建立一个list
				// 放一些值进去
li.remove(99);			// 除去所有等于99的元素:
				// 真的删除元素,
				// 所以它的大小可能改变了

坦白地说,调用这个remove函数是一个STL中的矛盾。在关联容器中类似的函数叫erase,list的remove也可以叫做erase。但它没有,所以我们都必须习惯它。我们所处于的世界不是所有可能中最好的世界,但却是我们所处的。(附加一点,条款44指出,对于list,调用remove成员函数比应用erase-remove惯用法更高效。)

一旦你知道了remove不能“真的”从一个容器中删除东西,和erase联合使用就变成理所当然了。你要记住的唯一其他的东西是remove不是唯一这种情况的算法。另外有两种“类似remove”的算法:remove_if和unique。

remove和remove_if之间的相似性很直截了当。所以我不会细讲,但unique行为也像remove。它用来从一个区间删除东西(邻近的重复值)而不用访问持有区间元素的容器。结果,如果你真的要从容器中删除元素,你也必须成对调用unique和erase,unique在list中也类似于remove。正像list::remove真的删除东西(而且比erase-remove惯用法高效得多)。list::unique也真的删除邻近的重复值(也比erase-unique高效)。

 

--------------------- 
作者:lishichengyan 
来源:CSDN 
原文:https://blog.csdn.net/lishichengyan/article/details/82669153 
 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++中vector的删除 的相关文章

随机推荐

  • 那些你不知道的表结构设计思路--开源软件诞生9

    ERP表结构的设计 第9篇 用日志记录 开源软件 的诞生 赤龙 ERP 开源地址 点亮星标 感谢支持 与开发者交流 kzca2000 码云 https gitee com redragon redragon erp GitHub https
  • 【JavaScript高级】手写apply()、call()、bind()

    文章目录 手写之前 apply call 封装函数实现apply和call bind 参考 手写之前 我们有一个函数foo 已知 foo的隐式原型是绑定在Function的显式原型上的 Function是一个构造函数 function fo
  • IPSec技术的基本原理详解及应用场景

    IPSec技术的基本原理详解及应用场景 IPSec简介 IPSec的英文是Internet Protocol Security 是一个协议包 通过对IP协议的分组进行加密和认证来保护IP协议的网络传输协议族 一些相互关联的协议的集合 IPs
  • rtx 3060 notebook cuda 与 gpu驱动安装

    cudnn的下载与安装 需要用户登录nvidia 然后再进入该地址 https developer nvidia com rdp cudnn archive https developer download nvidia cn comput
  • 配置Nginx正向代理

    需求 UAT需要在10 xx xx xx部署一个正向代理 端口号是80 要访问的外网域名为http api cn xxx com 1 查看80端口和外网是否畅通 telnet 10 xx xx xx 80 curl http api cn
  • 【Java学习004】Map集合遍历

    方式1使用Map Entry进行遍历 在for循环中使用 Map Entry 对象实现Map对象的遍历 public class Test public static void main String args Map
  • RNN,LSTM,GRU回顾(主要知道代码怎么使用)

    RNN的计算流程 RNN的计算流程图如下图所示 nn RNN的初始化是这样规定的 rnn nn RNN input size hidden size bias False batch first True 这里的input size就是其中
  • libjasper-dev 安装问题

    libjasper dev Depends libjasper1 1 900 1 debian1 2 4 deb8u1 but 1 900 1 debian1 2 4 deb8u3 is to be installed 执行 sudo ap
  • Xpath-helper下载及安装(爬虫必备-Chrome插件)

    一 下载 百度网盘链接下载 xpath helper crx 链接 https pan baidu com s 11IYyYJBGUiR3BY7cS7sLOA 提取码 iefg 二 安装 1 打开chrome页面 点击 右上角三个点 更多工
  • 云计算~Linux的常用命令

    云计算 Linux的常用命令 常用命令 kernels Shell与内核 内部命令与外部命令 ls命令 help man命令 pwd命令 cd命令 alias命令 du命令 touch命令 ln命令 cp命令 rm命令 which 命令 f
  • 机器学习--近邻成分分析(NCA)算法 和 度量学习

    1 近邻成分分析 NCA 算法 以上内容转载自 http blog csdn net chlele0105 article details 13006443 2 度量学习 在机器学习中 对高维数据进行降维的主要目的是找到一个合适的低维空间
  • dz论坛ucenter打不开mysql_Discuz和Ucenter安装出现PHP无法连接MYSQL情况

    安装时出现mysql connect 不支持请检查mysql模块是否正确加载这时候方意识到情况的严重 因为安装MYSQL的时候没有去测试与PHP的连接 PHP测试用测试过没问题 网址 安装时出现mysql connect 不支持 请检查 m
  • pandas常见用法总结:数据筛选,过滤,插入,删除,排序,分组聚合等

    pandas里面的用法相对非常灵活 经常会有一种需求可以采用多种方式实现的情况 为了方便查找与记忆 特此对pandas里面常见的一些用法 1 选择指定列 选择指定列是常见的需求 同样的实现方式也非常多 1 1 pd read csv 常用的
  • vue 键盘(上下左右)快捷键

    keydown 在键盘上按下某个键时触发 如果按住某个键 会不断触发该事件 但是 Opera 浏览器不支持这种连续操作 keypress 按下某个键盘键并释放时触发 如果按住某个键 会不断触发该事件 该事件处理函数返回 false 时 会取
  • error: LNK2001: 无法解析的外部符号 “public: virtual struct QMetaObject const * __cdecl

    Qt系列文章目录 文章目录 Qt系列文章目录 前言 一 QtCreator中qmake命令是什么 2 解决 前言 我在代码中加入了对应的信号和槽 但编译仍然报错 ifndef PROJECTWIN H define PROJECTWIN H
  • 大华、海康rtsp视频流格式

    一 海康威视热眼警戒摄像机DS 2TD1217 3 PA 型号 1号与2号摄像头 Camera 01 Camera 02 方法一 只能读取1号摄像头 rtsp admin 密码 192 168 1 64 554 cam realmonito
  • 美食推荐系统的设计与实现

    1 1 系统的总体目标 该美食推荐系统的总体目标是为用户提供一个全面 准确 方便的美食推荐服务 以满足用户的多样化需求 系统的主要目标如下 1 提供丰富多样的美食信息和推荐内容 为用户提供准确 全面的美食推荐服务 2 实现管理员和用户分离
  • linux文件系统搭建记录

    ubuntu 热插拔挂载 编辑 etc udev 99 xxx rules KERNEL mmcblk1p1 SUBSYSTEMS block ACTION add RUN program usr bin systemd mount no
  • 论文阅读:CVPR 2022 Object Localization under Single Coarse Point Supervision

    任务 point based object localization POL Motivation 具有相同语义信息的点具有不同的标签 而其他方法预先定义的关键点可能是不准确的 因此本文提出来基于粗糙点定位的模式 概述如下 1 采用粗略的点
  • C++中vector的删除

    在vector中有三种涉及删除的方法 第一种是vector clear 第二种是vector erase 第三种是vector pop back clear用来清空整个vector 同时将size变成0 无返回值 erase通过传入迭代器进