[C++再学习系列] STL容器删除操作总结

简介:

由于容器所对应不同的迭代器、指针和引用的失效规则 ,使得容器的删除操作较为复杂。解决问题的最好方法取决于你是怎样鉴别出哪个对象是要被去掉的,储存它们的容器的类型,和当你删除它们的时候你还想要做什么(如果有的话)。为此分 3 种情况讨论:

去除一个容器中有特定值的所有对象:

 1) 如果容器是 vector 、 string 或 deque ,使用 erase-remove 惯用法。

2) 如果容器是 list ,使用 list::remove 。

3) 如果容器是标准关联容器,使用它的 erase 成员函数。 

示例:

Container c;  // 去除值为 1963 的元素

c.erase(remove(c.begin(), c.end(), 1963), c.end()); // 当 c 是 vector 、 string 或 deque 时, erase-remove 惯用法是去除特定值的元素的最佳方法

c.remove(1963);     // 当 c 是 list 时, remove 成员函数是去除特定值的元素的最佳方法

c.erase(1963);        // 当 c 为关联容器

去除一个容器中满足一个特定判定式的所有对象:

1) 如果容器是 vector 、 string 或 deque ,使用 erase-remove_if 惯用法。

2) 如果容器是 list ,使用 list::remove_if 。

3) 如果容器是标准关联容器,使用 remove_copy_if 和 swap( 使用临时容器 ) ,或写一个循环来遍历容器元素,当你把迭代器传给 erase 时记得后置递增它。 

示例:特定判断式 : bool badValue(int x);   // 返回 x 是否是“ bad ”

c.erase(remove_if(c.begin(), c.end(), badValue),  c.end()); // 当 c 是 vector 、 string 或 deque

c.remove_if(badValue);     // 当 c 是 list 时

// 关联容器的删除 使用  后置递增传给 erase 的迭代器  技术

AssocContainer c;

for (AssocContainer::iterator i = c.begin();  // for 循环的第三部分是空的

       i != c.end();  /*nothing*/ ){        // 循环体控制 i 递增

       if (badValue(*i)) {

c.erase(i++);   // 删除 i ,副作用 i 递增

    // logFile << "Erasing " << *i <<'\n';    // 写日志文件 ,or other operators

       }

       else ++i;         // 递增

}

说明:为什么要使用后置递增?后置递增会增加临时副本,效率低。但此处一定要使用后置递增。关联容器的 erase 并不返回删除后的下一个有效迭代器,同时删除后的迭代器是无效迭代器。 为达到删除单前迭代器同时指向后一个迭代器,我们必须在删除前递增迭代器,同时记录当前迭代器并删除。后置递增操作除增加迭代器外,同时返回递增前的对象拷贝,完全满足所需的删除条件。  

在循环内做某些事情并删除对象:

1) 如果容器是标准序列容器,写一个循环来遍历容器元素,每当调用erase时记得都用它的返回值更新你的迭代器。

2) 如果容器是标准关联容器,写一个循环来遍历容器元素,当把迭代器传给erase时记得后置递增它(例子同上) 。 

示例:标准序列容器 ( 标准关联容器,同上 )

for (SeqContainer::iterator i = c.begin();

       i != c.end();){

       if (badValue(*i)){

              logFile << "Erasing " << *i << '\n';

              i = c.erase(i);         // 通过把 erase 的返回值获取有效的迭代器

       }                                

       else

              ++i;

}

说明:对序列容器为什么不使用  后置递增你要传给 erase 的迭代器  技术?原因在于 vector 、 string 和 deque 容器调用erase 后,不仅使所有指向被删元素的迭代器失效,也使被删元素之后 的所有迭代器失效 ( 可能重新分配地址空间 ) 。为了使序列容器的 erase 后,能获得删除后的有效迭代器,其 erase 将迭代器作为返回值:一旦删除完成, erase 返回指向紧接在被删元素之后的元素的有效迭代器。

注意: list 虽是序列容器,但采用节点存储方式,故不存在地址重新分配。因此可以像 vector/string/deque 一样或像关联容器一样对待 list ;两种方法都可以为 list 工作。

---------------------------------------------------

兄弟的公司:立即购--手机购物,诚信网购

兄弟的公司:立即团

欢迎转载,请注明作者和出处

本文转自 zhenjing 博客园博客,原文链接:http://www.cnblogs.com/zhenjing/archive/2011/01/30/STL_remove.html    ,如需转载请自行联系原作者

相关文章
|
4月前
|
缓存 算法 程序员
C++STL底层原理:探秘标准模板库的内部机制
🌟蒋星熠Jaxonic带你深入STL底层:从容器内存管理到红黑树、哈希表,剖析迭代器、算法与分配器核心机制,揭秘C++标准库的高效设计哲学与性能优化实践。
C++STL底层原理:探秘标准模板库的内部机制
|
4月前
|
NoSQL 算法 Redis
【Docker】(3)学习Docker中 镜像与容器数据卷、映射关系!手把手带你安装 MySql主从同步 和 Redis三主三从集群!并且进行主从切换与扩容操作,还有分析 哈希分区 等知识点!
Union文件系统(UnionFS)是一种**分层、轻量级并且高性能的文件系统**,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem) Union 文件系统是 Docker 镜像的基础。 镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
636 5
|
11月前
|
编译器 C++ 容器
【c++丨STL】基于红黑树模拟实现set和map(附源码)
本文基于红黑树的实现,模拟了STL中的`set`和`map`容器。通过封装同一棵红黑树并进行适配修改,实现了两种容器的功能。主要步骤包括:1) 修改红黑树节点结构以支持不同数据类型;2) 使用仿函数适配键值比较逻辑;3) 实现双向迭代器支持遍历操作;4) 封装`insert`、`find`等接口,并为`map`实现`operator[]`。最终,通过测试代码验证了功能的正确性。此实现减少了代码冗余,展示了模板与仿函数的强大灵活性。
314 2
|
11月前
|
存储 算法 C++
【c++丨STL】map/multimap的使用
本文详细介绍了STL关联式容器中的`map`和`multimap`的使用方法。`map`基于红黑树实现,内部元素按键自动升序排列,存储键值对,支持通过键访问或修改值;而`multimap`允许存在重复键。文章从构造函数、迭代器、容量接口、元素访问接口、增删操作到其他操作接口全面解析了`map`的功能,并通过实例演示了如何用`map`统计字符串数组中各元素的出现次数。最后对比了`map`与`set`的区别,强调了`map`在处理键值关系时的优势。
607 73
|
存储 缓存 C++
C++ 容器全面剖析:掌握 STL 的奥秘,从入门到高效编程
C++ 标准模板库(STL)提供了一组功能强大的容器类,用于存储和操作数据集合。不同的容器具有独特的特性和应用场景,因此选择合适的容器对于程序的性能和代码的可读性至关重要。对于刚接触 C++ 的开发者来说,了解这些容器的基础知识以及它们的特点是迈向高效编程的重要一步。本文将详细介绍 C++ 常用的容器,包括序列容器(`std::vector`、`std::array`、`std::list`、`std::deque`)、关联容器(`std::set`、`std::map`)和无序容器(`std::unordered_set`、`std::unordered_map`),全面解析它们的特点、用法
C++ 容器全面剖析:掌握 STL 的奥秘,从入门到高效编程
|
11月前
|
存储 算法 C++
【c++丨STL】set/multiset的使用
本文深入解析了STL中的`set`和`multiset`容器,二者均为关联式容器,底层基于红黑树实现。`set`支持唯一性元素存储并自动排序,适用于高效查找场景;`multiset`允许重复元素。两者均具备O(logN)的插入、删除与查找复杂度。文章详细介绍了构造函数、迭代器、容量接口、增删操作(如`insert`、`erase`)、查找统计(如`find`、`count`)及`multiset`特有的区间操作(如`lower_bound`、`upper_bound`、`equal_range`)。最后预告了`map`容器的学习,其作为键值对存储的关联式容器,同样基于红黑树,具有高效操作特性。
496 3
|
C++ 容器
【c++丨STL】stack和queue的使用及模拟实现
本文介绍了STL中的两个重要容器适配器:栈(stack)和队列(queue)。容器适配器是在已有容器基础上添加新特性或功能的结构,如栈基于顺序表或链表限制操作实现。文章详细讲解了stack和queue的主要成员函数(empty、size、top/front/back、push/pop、swap),并提供了使用示例和模拟实现代码。通过这些内容,读者可以更好地理解这两种数据结构的工作原理及其实现方法。最后,作者鼓励读者点赞支持。 总结:本文深入浅出地讲解了STL中stack和queue的使用方法及其模拟实现,帮助读者掌握这两种容器适配器的特性和应用场景。
347 21
|
12月前
|
存储 算法 C++
【c++丨STL】priority_queue(优先级队列)的使用与模拟实现
本文介绍了STL中的容器适配器`priority_queue`(优先级队列)。`priority_queue`根据严格的弱排序标准设计,确保其第一个元素始终是最大元素。它底层使用堆结构实现,支持大堆和小堆,默认为大堆。常用操作包括构造函数、`empty`、`size`、`top`、`push`、`pop`和`swap`等。我们还模拟实现了`priority_queue`,通过仿函数控制堆的类型,并调用封装容器的接口实现功能。最后,感谢大家的支持与关注。
773 1
|
算法 网络安全 区块链
2023/11/10学习记录-C/C++对称分组加密DES
本文介绍了对称分组加密的常见算法(如DES、3DES、AES和国密SM4)及其应用场景,包括文件和视频加密、比特币私钥加密、消息和配置项加密及SSL通信加密。文章还详细展示了如何使用异或实现一个简易的对称加密算法,并通过示例代码演示了DES算法在ECB和CBC模式下的加密和解密过程,以及如何封装DES实现CBC和ECB的PKCS7Padding分块填充。
322 4
2023/11/10学习记录-C/C++对称分组加密DES
|
C++ 开发者
C++学习之继承
通过继承,C++可以实现代码重用、扩展类的功能并支持多态性。理解继承的类型、重写与重载、多重继承及其相关问题,对于掌握C++面向对象编程至关重要。希望本文能为您的C++学习和开发提供实用的指导。
198 16