2.使用STL中通用算法或容器成员函数删除元素的方法
以上手工编写for循环代码删除容器中元素的方法也有一些问题,如果判断条件特别复杂,又有循环判断的话,循环中间又有异常处理的话,++itVect的位置就要小心放置了,稍不留意就要出错。所以手工编写代码删除容器中元素的方法不太安全,代码重复,也不够优雅,要注意的地方很多。
对于这种情况,可以考虑使用STL中通用算法remvoe()和remove_if()帮忙。而remvoe()和remove_if()这两个算法也有一个问题需要程序员特别小心。在通用算法中的 remove(包括remove_if) 函数,并不真正从容器中删除元素,而是“应被删除的元素”被其后的“未被删除的元素”覆盖。返回值ForwardIterator指向经移除后的最后元素的下一位置。如vector{0,1,2,3,3,4},执行remove(),希望移除所有值为3的元素,结果为{0,1,2,4,3,4},返回值ForwardIterator指向第5个元素。即:<o:p></o:p>
0 1 2 3 3 4 移除前<o:p></o:p>
0 1 2 4 3 4 移除后<o:p></o:p>
<o:p></o:p>
移除值为3的元素。移除后3被其后的4替代,最后两位元素为残余数据。<o:p></o:p>
<o:p></o:p>
例 5:<o:p></o:p>
void main() {<o:p></o:p>
vector<int> vectInt;<o:p></o:p>
int i;<o:p></o:p>
for (i = 0; i < 5; i++ ) {<o:p></o:p>
vectInt.push_back( i );<o:p></o:p>
if ( 3 == i ) {<o:p></o:p>
vectInt.push_back( i );<o:p></o:p>
}<o:p></o:p>
}<o:p></o:p>
remove( vectInt.begin(), vectInt.end(), 3 );<o:p></o:p>
cout << " after deleted , size = " << vectInt.size() << endl;<o:p></o:p>
for ( i = 0; i < vectInt.size();; i++ ) {<o:p></o:p>
cout << "i = " << i << " , " << vectInt[i] << endl;<o:p></o:p>
}<o:p></o:p>
}<o:p></o:p>
运行结果为:<o:p></o:p>
after deleted , size = 6 // 从这行可以看出,移除后容器的大小没变<o:p></o:p>
i = 0 , 0<o:p></o:p>
i = 1 , 1<o:p></o:p>
i = 2 , 2<o:p></o:p>
i = 3 , 4 // 从这行可以看出:“应被删除的元素”3 被其后的“未被删除的元素”4覆盖<o:p></o:p>
i = 4 , 3<o:p></o:p>
i = 5 , 4 <o:p></o:p>
<o:p></o:p>
所以要彻底删除还应该把后面的残余数据删除掉,这可以通过调用容器的成员函数erase()做到。<o:p></o:p>
例 6:<o:p></o:p>
void main() {<o:p></o:p>
vector<int> vectInt;<o:p></o:p>
int i;<o:p></o:p>
for (i = 0; i < 5; i++ ) {<o:p></o:p>
vectInt.push_back( i );<o:p></o:p>
if ( 3 == i ) {<o:p></o:p>
vectInt.push_back( i );<o:p></o:p>
}<o:p></o:p>
}<o:p></o:p>
vectInt.erase( remove( vectInt.begin(), vectInt.end(), 3 ), vectInt.end() );<o:p></o:p>
cout << " after deleted , size = " << vectInt.size() << endl;<o:p></o:p>
for ( i = 0; i < vectInt.size();; i++ ) {<o:p></o:p>
cout << "i = " << i << " , " << vectInt[i] << endl;<o:p></o:p>
}<o:p></o:p>
}<o:p></o:p>
运行结果为:<o:p></o:p>
after deleted , size = 4 // 从这行可以看出,删除后容器的大小变化了<o:p></o:p>
i = 0 , 0<o:p></o:p>
i = 1 , 1<o:p></o:p>
i = 2 , 2<o:p></o:p>
i = 3 , 4<o:p></o:p>
从结果可以看出,所有值为3的元素确实被删除了。<o:p></o:p>
对于vector容器存放其他比较复杂的对象,就可以用remove_if()加函数对象(Function Object)的方法。<o:p></o:p>
如:<o:p></o:p>
例7:<o:p></o:p>
#include <iostream><o:p></o:p>
#include <sstream><o:p></o:p>
#include <string><o:p></o:p>
#include <vector><o:p></o:p>
#include <algorithm><o:p></o:p>
#include <list><o:p></o:p>
using namespace std;<o:p></o:p>
class CTest {<o:p></o:p>
public:<o:p></o:p>
CTest( const string& str, int iPrice ) : m_strName( str ), m_iPrice( iPrice ) { }<o:p></o:p>
void vPrint() { cout << "name=" << m_strName << " price = " << m_iPrice << endl;<o:p></o:p>
}<o:p></o:p>
private:<o:p></o:p>
string m_strName;<o:p></o:p>
int m_iPrice;<o:p></o:p>
// 由于两个函数对象要访问CTest类的private成员,所以设为友员。<o:p></o:p>
friend class CStrFunc;<o:p></o:p>
friend class CIntFunc;<o:p></o:p>
};<o:p></o:p>
// 函数对象,根据string比较<o:p></o:p>
class CStrFunc {<o:p></o:p>
string m_str;<o:p></o:p>
public:<o:p></o:p>
CStrFunc( const string& str ) : m_str( str ) {<o:p></o:p>
}<o:p></o:p>
bool operator() ( const CTest& left ) {<o:p></o:p>
return ( m_str == left.m_strName ) ? true : false;<o:p></o:p>
}<o:p></o:p>
};<o:p></o:p>
// 函数对象,根据int比较<o:p></o:p>
class CIntFunc {<o:p></o:p>
int m_iPrice;<o:p></o:p>
public:<o:p></o:p>
CIntFunc( int iPrice ) : m_iPrice( iPrice ) {<o:p></o:p>
}<o:p></o:p>
bool operator() ( const CTest& left ) {<o:p></o:p>
return ( m_iPrice == left.m_iPrice ) ? true : false;<o:p></o:p>
}<o:p></o:p>
};<o:p></o:p>
void main( ) {<o:p></o:p>
<o:p></o:p>
vector< CTest > vectTest;<o:p></o:p>
int i;<o:p></o:p>
for ( i = 0; i < 5 ; i++ ) {<o:p></o:p>
stringstream stream; // 流格式化符,把int转化为string<o:p></o:p>
stream << i;<o:p></o:p>
string str = stream.str();<o:p></o:p>
CTest clTest( str, i );<o:p></o:p>
vectTest.push_back( clTest );<o:p></o:p>
}<o:p></o:p>
for ( i = 0 ; i < vectTest.size(); i++ ) {<o:p></o:p>
vectTest[ i ].vPrint();<o:p></o:p>
}<o:p></o:p>
// 删除所有m_strName = "3"的元素<o:p></o:p>
vectTest.erase( remove_if( vectTest.begin(), vectTest.end(), CStrFunc( "3" ) ),<o:p></o:p>
vectTest.end() );<o:p></o:p>
cout << "delete 3 after : " << endl;<o:p></o:p>
for ( i = 0 ; i < vectTest.size(); i++ ) {<o:p></o:p>
vectTest[ i ].vPrint();<o:p></o:p>
}<o:p></o:p>
// 删除所有m_iPrice = 2的元素<o:p></o:p>
vectTest.erase( remove_if( vectTest.begin(), vectTest.end(), CIntFunc( 2 ) ),<o:p></o:p>
vectTest.end() );<o:p></o:p>
cout << "delete 2 after : " << endl;<o:p></o:p>
for ( i = 0 ; i < vectTest.size(); i++ ) {<o:p></o:p>
vectTest[ i ].vPrint();<o:p></o:p>
}<o:p></o:p>
}<o:p></o:p>
手工编写for循环代码删除STL序列式容器中元素的方法,使用STL中通用算法或容器成员函数删除元素的方法,两者之间的比较:<o:p></o:p>
1. 前者代码重复。<o:p></o:p>
2. 前者容易出错,不够清晰。<o:p></o:p>
3. 效率:<o:p></o:p>
0 1 2 3 2 5 6 7<o:p></o:p>
0 1 3 2 5 6 7<o:p></o:p>
0 1 3 5 6 7<o:p></o:p>
用第一种方法删除所有值为2的元素<o:p></o:p>
从上图可以看出,每删除一个元素,后面的所有元素都到往前移动一位,导致一次内存大搬迁。<o:p></o:p>
<o:p></o:p>
0 1 2 3 2 5 6 7<o:p></o:p>
0 1 3 2 5 6 6 7<o:p></o:p>
0 1 3 5 6 7<o:p></o:p>
<o:p></o:p>
用第二种方法删除所有值为2的元素<o:p></o:p>
从上面可以看出,删除时元素2被后面元素覆盖,不会到元素移位和内存大搬迁,残余数据留到末尾一次全部删除,也不会导致内存大搬迁,所以后者的方法要比前者在效率上好很多。
分享到:
相关推荐
2. **迭代器**:迭代器是STL的核心概念,它是访问容器中元素的一种抽象接口。通过迭代器,程序员可以像操作指针一样遍历容器,但具有更丰富的功能,如前向、双向和随机访问迭代器,支持各种操作如递增、递减、比较和...
对于序列式容器(如`vector`、`deque`),删除操作可能导致后续迭代器失效。 了解这些规则并正确使用迭代器是使用STL时的关键,避免迭代器失效能确保代码的稳定性和安全性。在实际编程中,一定要注意这些细节,以...
4. **容器管理**:C++标准模板库(STL)提供了多种容器,如`vector`动态数组,`list`双向链表,`set`和`map`为关联容器,分别提供有序的元素集合和键值对映射。容器相关的函数如`push_back()`向`vector`末尾添加元素...
- 可能会用到STL库中的容器,如vector,用于表示种群和个体。 4. **优化策略**: - 可以使用各种策略改进遗传算法,例如 elitism(保留最优解)、dithering(适应度阈值)和局部搜索。 - 还可以引入多种交叉和...
技术运维-机房巡检表及巡检说明
第四次算法分析与设计整理
图像处理项目实战
该资源为jaxlib-0.4.18-cp311-cp311-macosx_11_0_arm64.whl,欢迎下载使用哦!
搭建说明. 运行环境 php5.6 mysql5.6 扩展sg11 前置条件: 前后端分离,需要准备两个域名,一个后台域名,一个前端域名 后端源码修改(cs2.ijiuwu.com批量替换改为你的后端域名)数据库修改(cs3.ijiuwu.com批量替换为你的前端域名)1、创建后台站点,上传后台源码并解压到根目录2、创建前端站点,上传前端源码并解压到根目录 3、创建数据库上传并导入数据库文件 4、修改数据库信息: 后台:app/database.php 前端:application/database.php 前端站点设置 伪静态thinkphp 运行目录public 关闭防跨站 访问后台域名/admin.php进入后台管理 admin 123456 系统-》系统设置-》附件设置-》Web服务器URL 改为你的前端域名 系统-》清前台缓存 改为你的前端域名 点击刷新缓存
【毕业答辩】爆款黑板风教育文艺毕业论文答辩通用模板.pptx
1、文件内容:systemd-devel-219-78.el7_9.9.rpm以及相关依赖 2、文件形式:tar.gz压缩包 3、安装指令: #Step1、解压 tar -zxvf /mnt/data/output/systemd-devel-219-78.el7_9.9.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm 4、更多资源/技术支持:公众号禅静编程坊
win32汇编环境,对 WM-MOUSEMOVE 消息的理解
车牌识别项目
UE项目开发过程中的一些快捷脚本
lab1的words.txt文件
python、yolo、pytorch
人工智能、大语言模型相关学习资料
图像处理项目实战
python、yolo、pytorch
车牌识别项目