当前位置: 首页 > news >正文

【C++语言】vector迭代器与常见oj题

vector迭代器的失效问题

接上篇vector的介绍和使用中最后提到的vector迭代器,我们继续来看vector迭代器的失效问题。

以下代码的功能是删除vector中所有的偶数,请问那个代码是正确的,为什么?
#include <iostream>
using namespace std;
#include <vector>
//第一种方法
int main()
{vector<int> v{ 1, 2, 3, 4 };auto it = v.begin();while (it != v.end()){if (*it % 2 == 0)v.erase(it);++it;}return 0;
}
//第二种方法
int main()
{vector<int> v{ 1, 2, 3, 4 };auto it = v.begin();while (it != v.end()){if (*it % 2 == 0)it = v.erase(it);else++it;}return 0;
}

        答案是第二种,第一种的方法会导致迭代器失效,因为每删除一个,erase迭代器后就不让使用了,而第二种方法在 it = v.erase(it)中解决了,因为erase函数会返回删除元素的下一个位置的迭代器,解决乐迭代器失效的问题。

Linux下g++编译器对迭代器失效的检测

        Linux下,g++编译器对迭代器失效的检测并不是非常严格,处理也没有vs下极端。以下三种情况可以让我们对Linux下g++迭代器失效情况更加了解
// 1. 扩容之后,迭代器已经失效了,程序虽然可以运行,但是运行结果已经不对了
int main()
{vector<int> v{1,2,3,4,5};for(size_t i = 0; i < v.size(); ++i)cout << v[i] << " ";cout << endl;auto it = v.begin();cout << "扩容之前,vector的容量为: " << v.capacity() << endl;// 通过reserve将底层空间设置为100,目的是为了让vector的迭代器失效 v.reserve(100);cout << "扩容之后,vector的容量为: " << v.capacity() << endl;// 经过上述reserve之后,it迭代器肯定会失效,在vs下程序就直接崩溃了,但是linux下不会// 虽然可能运行,但是输出的结果是不对的while(it != v.end()){cout << *it << " ";++it;}cout << endl;return 0;
}
程序输出:
1 2 3 4 5
扩容之前,vector的容量为: 5
扩容之后,vector的容量为: 100
0 2 3 4 5 409 1 2 3 4 5
// 2. erase删除任意位置代码后,linux下迭代器并没有失效
// 因为空间还是原来的空间,后序元素往前搬移了,it的位置还是有效的
#include <vector>
#include <algorithm>
int main()
{vector<int> v{1,2,3,4,5};vector<int>::iterator it = find(v.begin(), v.end(), 3);v.erase(it);cout << *it << endl;while(it != v.end()){cout << *it << " ";++it;}cout << endl;return 0;
}程序可以正常运行,并打印:
4
4 5
// 3: erase删除的迭代器如果是最后一个元素,删除之后it已经超过end
// 此时迭代器是无效的,++it导致程序崩溃
int main()
{vector<int> v{1,2,3,4,5};// vector<int> v{1,2,3,4,5,6};auto it = v.begin();while(it != v.end()){if(*it % 2 == 0)v.erase(it);++it;}for(auto e : v)cout << e << " ";cout << endl;return 0;
}
========================================================
// 使用第一组数据时,程序可以运行
[sly@VM-0-3-centos 20220114]$ g++ testVector.cpp -std=c++11
[sly@VM-0-3-centos 20220114]$ ./a.out
1 3 5
=========================================================
// 使用第二组数据时,程序最终会崩溃
[sly@VM-0-3-centos 20220114]$ vim testVector.cpp
[sly@VM-0-3-centos 20220114]$ g++ testVector.cpp -std=c++11
[sly@VM-0-3-centos 20220114]$ ./a.out
Segmentation fault
        从上述三个例子中可以看到:SGI STL中,迭代器失效后,代码并不一定会崩溃,但是运行结果肯定不对,如果it不在begin和end范围内,肯定会崩溃的。

与vector类似,string在插入+扩容操作+erase之后,迭代器也会失效

#include <string>
void TestString()
{string s("hello");auto it = s.begin();// 放开之后代码会崩溃,因为resize到20会string会进行扩容// 扩容之后,it指向之前旧空间已经被释放了,该迭代器就失效了// 后序打印时,再访问it指向的空间程序就会崩溃//s.resize(20, '!');while (it != s.end()){cout << *it;++it;}cout << endl;it = s.begin();while (it != s.end()){it = s.erase(it);// 按照下面方式写,运行时程序会崩溃,因为erase(it)之后// it位置的迭代器就失效了// s.erase(it); ++it;}
}

迭代器失效解决办法:在使用前,对迭代器重新赋值即可。

vector常见oj题

1.只出现一次的数字 - 力扣

class Solution {
public:int singleNumber(vector<int>& nums) {int value = 0;for(auto e : nums){value ^= e;}return value;}
};

2.杨辉三角- 力扣(LeetCode) 

 

class Solution {
public:vector<vector<int>> generate(int numRows) {vector<vector<int>> vv;vv.resize(numRows);for(size_t i=0;i<numRows;i++){vv[i].resize(i+1,0);vv[i][0]=vv[i][vv[i].size()-1]=1;}if(numRows<=2)return vv;for(size_t i =2;i<numRows;i++){for(size_t j=1;j<i;j++){vv[i][j]=vv[i-1][j-1]+vv[i-1][j];}}return vv;}
};

 总结:通过上面的练习我们发现vector常用的接口更多是插入和遍历。遍历更喜欢用数组operator[i]的形式访问,因为这样便捷。

http://www.lryc.cn/news/417033.html

相关文章:

  • 高职物联网智慧农业实训室建设方案
  • Pytorch 高效快速加载大规模数据集
  • Spring Boot集成protobuf快速入门Demo
  • SpringBoot+Vue 简单小文章项目开发全过程
  • 如何将发明原理应用于产品设计的概念阶段?
  • 【wsl】wsl + vscode 中使用 typora 打开 markdown 文件
  • AutoDL下huggingface下载模型位置问题
  • SpringBoot基础(一):快速入门
  • 使用Weka进行数据挖掘与机器学习
  • 定时器知识点
  • 桌面日历还能这样玩?这个日历太酷了吧!秒变桌面记事本!
  • 基于深度学习的太阳暗条检测(2020年以来)
  • 【吊打面试官系列-Elasticsearch面试题】Elasticsearch 在部署时,对 Linux 的设置有哪些优化方法?
  • MySQL·C/C++访问数据库
  • python.tkinter设计标记语言(渲染2-渲染器)
  • Cadence学习笔记 Day0 Cadence17.4环境安装
  • k8s创建secret并在container中获取secret
  • Leetcode每日一题之仅仅反转字母(C++)
  • PDF预览:利用vue3-pdf-app实现前端PDF在线展示
  • 【OpenCV C++20 学习笔记】拉普拉斯(Laplace)二阶求导-边缘检测
  • MySQL的下载和安装步骤
  • Java国际版同城服务美容美发到店服务上门服务系统
  • 硬件模拟的基本原理
  • WPF学习(8)- Button按钮
  • Flutter GPU 是什么?为什么它对 Flutter 有跨时代的意义?
  • 第6章>>实验7:PS(ARM)端Linux RT与PL端FPGA之间(通过Memory存储器进行通信和交互)《LabVIEW ZYNQ FPGA宝典》
  • 通用前端的学习
  • git本地仓库关联多个远程仓库时git pull失败问题
  • 人工智能(AI)、Web 3.0和元宇宙三者联系、应用及未来发展趋势的详细分析
  • 【IEEE出版 | 高校主办】第三届人工智能、物联网和云计算技术国际会议(AIoTC 2024)