【C++第九课 - vector】vector介绍、vector使用,vector的底层实现、杨辉三角、全排列、只出现一次的数字

目录

  • 一、vector的介绍
  • 二、vector的使用
      • 1、vector的构造函数
      • 2、vector的插入和三种遍历方式
      • 3、开空间
      • 4、insert
      • 5、find
      • 6、erase
      • 补充
  • 三、vector的底层实现
      • 1、成员变量
      • 2、构造函数
      • 3、push_back
      • 4、访问方式
      • 5、pop_back
      • 6、insert - pos位置插入x
      • 7、resize
      • 8、拷贝构造
      • 9、赋值
      • 10、erase
  • 四、迭代器失效
      • 1、insert在pos位置插入时,发生扩容,pos这个迭代器就失效了
      • 2、erase进行删除的时候会发生迭代器失效
  • 五、vector和string的优势
  • 四、算法题
      • 1、电话号码的字母组合 -- 全排列问题
      • 2、只出现一次的数字
      • 3、杨辉三角
      • 4、删除排序数组中的重复项
      • 5、数组中出现次数超过一半的数字

上次课回顾
windows和Linux下默认的string类型的大小
(1)windows
按理来说,大小应该是12,但是运行的结果却又28
在这里插入图片描述
在这里插入图片描述
多了个_Buf数组,这个数组大小是16,可以存15个字符
所以s1和s2的大小不是12,而是18
在这里插入图片描述
对于_Buf这个字符数组,如果string的_str的大小小于等于15就存在_Buf里面,如果大于15则_Buf这个字符数组就废弃重新开辟空间。目的:防止频繁开辟小空间
在这里插入图片描述
(2)Linux
Linux默认64位,默认release版本
上述代码放到Linux里面,大小就是八字节,也就是string里面就放了一个指针
在这里插入图片描述
在这里插入图片描述
浅拷贝问题
(1)析构两次 -> 引用计数
当最后一个对象删除时,才会释放这段空间
在这里插入图片描述
(2)一个修改会影响另一个 -> 写时拷贝(也有缺陷)

一、vector的介绍

就是顺序表

string类是一个保存字符的动态数组,由于其中有一个接口c_str,转化成c语言的字符串,要以\0结尾,所以string类最后会有一个\0.
string支持+=
string支持比较大小(通过ascii码)
vector是一个保存T类型的动态数组,vector也是保存字符的动态数组,但是,不会以\0结尾,不保存\0.
vector不支持+=
vector不支持比较大小(也可以通过ascii码比较,但意义不大)
在这里插入图片描述

在这里插入图片描述

二、vector的使用

1、vector的构造函数

在这里插入图片描述
(1)全缺省构造(无参的)

vector<int> v1;

(2)n个value的构造

vector<int> v2(5, 1);

在这里插入图片描述

(3)迭代区间的构造

	vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(5);vector<int> v3(v1.begin(), v1.end());

在这里插入图片描述

2、vector的插入和三种遍历方式

(1)、下标

#include<iostream>
#include<vector>
using namespace std;int main()
{vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);for (int i = 0; i < v1.size(); i++){cout << v1[i];}cout << endl;return 0;
}

(2)、迭代器

#include<iostream>
#include<vector>
using namespace std;int main()
{vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);vector<int>::iterator t = v1.begin();while (t != v1.end()){cout << *t;++t;}cout << endl;return 0;
}

(3)、范围for

#include<iostream>
#include<vector>
using namespace std;int main()
{vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);for (auto e : v1){cout << e;}cout << endl;return 0;
}

3、开空间

(1)、开空间reserve

void test2()
{vector<int> v1;int sz = v1.capacity();for (int i = 0; i < 100; i++){v1.push_back(i);if (sz != v1.capacity()){cout << "capacity: " << v1.capacity() << endl;sz = v1.capacity();}}
}int main()
{test2();return 0;
}

在这里插入图片描述
1.5倍扩容,Linux一般是二倍扩容
减少频繁扩容的方式,使用reserve,而不使用resize,因为resize不仅扩容还会初始化那么再插入的时候还需要扩容
在这里插入图片描述

(2)、开空间加初始化resize

vector的resize不缩容,缩容用Shrink_to_fit

在这里插入图片描述

void test2()
{vector<int> v1;v1.reserve(100);int sz = v1.capacity();for (int i = 0; i < 100; i++){v1.push_back(i);if (sz != v1.capacity()){cout << "capacity: " << v1.capacity() << endl;sz = v1.capacity();}}v1.resize(10);cout << "capacity: " << v1.capacity() << endl;cout << "size: " << v1.size() << endl;
}

在这里插入图片描述

4、insert

在这里插入图片描述
(1)在某一位置插入val

void test3()
{vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(5);for (auto e : v1){cout << e << " ";}cout << endl;v1.insert(v1.begin(), 10);for (auto e: v1){cout << e <<" ";}cout << endl;
}

在这里插入图片描述
2、在某一位置插入n个val

void test3()
{vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(5);for (auto e : v1){cout << e << " ";}cout << endl;v1.insert(v1.begin(), 2,10);for (auto e: v1){cout << e <<" ";}cout << endl;
}

在这里插入图片描述
(3)在某一位置插入一个迭代区间

	v1.insert(v1.begin(), v2.begin(), v2.end());cout << "v1:";for (auto e : v1){cout << e << " ";}cout << endl;

在这里插入图片描述

5、find

vector没有find,用的是算法里面的find

string为何要自己写find
(1)string查找的更为复杂,不仅要查一个字符还有可能查一个字串
(2)string返回下标更合适

在这里插入图片描述

void test4()
{vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);for (auto e : v1){cout << e << " ";}cout << endl;v1.insert(find(v1.begin(), v1.end(), 2), 20);for (auto e : v1){cout << e << " ";}cout << endl;}

在这里插入图片描述

6、erase

补充

vector不支持流插入和流提取
因为vector打印时每个之间用什么隔开自己决定
string如果没有特殊需求一般打印的时候都是连着

三、vector的底层实现

相比于之前string的直接定义_a、_size、_capacity,这里的vector是间接定义的
在这里插入图片描述

1、成员变量

vector不使用下标,只使用迭代器进行访问、插入等

private:iterator start;iterator finish;iterator end_of_storage;

2、构造函数

3、push_back

namespace zyh
{template<class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;vector():start(nullptr),finish(nullptr),end_of_storage(nullptr){}size_t size(){return finish - start;}size_t capacity(){return end_of_storage - start;}void reverse(size_t n){if (n > capacity()){size_t oldsize = size();T* tmp = new T[n];if (start){memcpy(tmp, start, old * sizeof(T));}delete[] start;start = tmp;finish = start + oldsize;end_of_storage = start + n;}}void push_back(const T& x){if (finish == end_of_storage){size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reverse(newcapacity);}*finish = x;finish++;}iterator begin(){return start;}iterator end(){return finish;}const_iterator begin() const{return start;}const_iterator end() const{return finish;}private:iterator start;iterator finish;iterator end_of_storage;

4、访问方式

迭代器

iterator begin(){return start;}iterator end(){return finish;}const_iterator begin() const{return start;}const_iterator end() const{return finish;}
		vector<int>::iterator it1 = v1.begin();while (it1 != v1.end()){std::cout << *it1 << " ";it1++;}std::cout << std::endl;

范围for

		v1.push_back(5);for (auto v : v1){std::cout << v << " ";}std::cout << std::endl;

[]

		T& operator[](size_t pos){assert(pos < size());return start[pos];//return *(start + pos);}
		v1.push_back(6);for (int i = 0; i < v1.size(); i++){std::cout << v1[i] << " ";}std::cout << std::endl;

5、pop_back

		void pop_back(){assert(size() > 0);--finish;}

6、insert - pos位置插入x

		void insert(iterator pos,const T& x){assert(pos >= start && pos <= finish);if (finish == end_of_storage){reverse(capacity() == 0 ? 4 : capacity() * 2);}memmove(pos + 1, pos, sizeof(T) * (finish - pos));++finish;*pos = x;}

问题:扩容时,pos迭代器失效
在这里插入图片描述

		void insert(iterator pos,const T& x){assert(pos >= start && pos <= finish);int len = pos - start;if (finish == end_of_storage){reverse(capacity() == 0 ? 4 : capacity() * 2);pos = start + len;}memmove(pos + 1, pos, sizeof(T) * (finish - pos));++finish;*pos = x;}

7、resize

capacity和size都要变
在这里插入图片描述

T()是个匿名对象,因为要给一个缺省值,又因为T是不确定的,因此使用匿名对象
在模板里面无论是内置类型还是自定义类型都是可以初始化的

		void resize(size_t n, T val = T()){if (n <= size())finish = start + n;else if (n > size() && n <= capacity()){while (finish != start + n){*finish = val;++finish;}}else{reverse(n);while (finish != start + n){*finish = val;++finish;}}}

8、拷贝构造

		//拷贝构造vector(const vector<T>& v){reverse(v.capacity());for (const auto& i : v){push_back(i);}}

1、因为vconst的,所以在使用范围for进行遍历的时候注意也要是const auto

9、赋值

下面这样写是不对的,全局的swap两个变量都不能有const的
在这里插入图片描述
在这里插入图片描述

		vector<T>& operator=(vector<T> v){//swap(v);std::swap(start, v.start);std::swap(finish, v.finish);std::swap(end_of_storage, v.end_of_storage);return *this;}

10、erase

		void erase(iterator pos){assert(pos < finish);assert(pos >= start);iterator it = pos + 1;while (it < finish){*(it - 1) = *it;++it;}finish--;}

四、迭代器失效

insert和erase形参pos都可能会失效
原则是insert和erase过的迭代器不要使用

1、insert在pos位置插入时,发生扩容,pos这个迭代器就失效了

2、erase进行删除的时候会发生迭代器失效

erase有一个返回值,返回的是刚刚删除元素的下一个位置

删除所以元素中的偶数

五、vector和string的优势

1、尾插和尾删
2、随机访问

四、算法题

1、电话号码的字母组合 – 全排列问题

class Solution {
public:string num2str[10] = {"","","abc","def","ghi","jkl","mno","pqrs","tuv", "wxyz"};void combinstr(string& digits, int dinum, string str, vector<string>& v){if(dinum == digits.size()){v.push_back(str);return;}int num = digits[dinum] - '0';string numstr = num2str[num];for(int i = 0; i < numstr.size(); i++){combinstr(digits, dinum + 1, str + numstr[i], v);}}vector<string> letterCombinations(string digits) {vector<string> v;if(digits.size() == 0)return v;combinstr(digits, 0, "", v);return v;}
};

在这里插入图片描述

2、只出现一次的数字

对于此题的解法:就是异或^
0和任意数a异或还是a:0^a = a
任意数a和其自身异或为0:a^a = 0;

class Solution {
public:int singleNumber(vector<int>& nums) {int res = 0;for(int i = 0; i < nums.size(); i++){res = res ^ nums[i];}return res;}
};

3、杨辉三角

&& :逻辑与,两个结果都为真时才为真
|| :逻辑或,两个结果有一个为真则为真

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

改进:
if(j == 0 || j == i || i == 0) { vv[i][j] = 1; }
对于这行代码可以使用vector里面的frontback

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

也可以把所有的位置都初始化为0vv[i].resize(i+1, 0);
在对v[i][j]进行赋值的时候可以直接判断只给0的位置,因为1的位置已经赋值了

4、删除排序数组中的重复项

在这里插入图片描述
在这里插入图片描述

class Solution {
public:int removeDuplicates(vector<int>& nums) {if(nums.size() == 0)return 0;if(nums.size() == 1)return 1;size_t i = 1;size_t j = 0;int len = 1;while(i < nums.size()){if(nums[i] == nums[j]){i++;}else{nums[len] = nums[i];len++;j = i;i++;}}return len;}
};

对于排序的序列去重使用双指针

5、数组中出现次数超过一半的数字

在这里插入图片描述

使用两个指针遍历数组,当两个指针指向的内容不同时就删除,最后留下的就是多个一样的数或一个数

#include <cstddef>
class Solution {
public:/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可** * @param numbers int整型vector * @return int整型*/int MoreThanHalfNum_Solution(vector<int>& numbers) {// write code heresize_t len = numbers.size();if(len == 1)return numbers[0];auto i = numbers.begin();auto j = numbers.end()-1;while(i != j){if(*i != *j){numbers.erase(j);numbers.erase(i);j = numbers.end() - 1;i = numbers.begin();}else{i++;}}return numbers[0];}
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/850469.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

工具:Linux如何挂载NTFS移动硬盘

从windows平台迁移数据至Linux平台&#xff0c;有时候会用到NTFS文件系统的硬盘&#xff0c;但Linux的file system一般又无法直接兼容NTFS系统。这个就需要用到ntfs-3g插件。 NTFS-3G是一个开源项目&#xff0c; NTFS-3G是为Linux, Android, Mac OS X, FreeBSD, NetBSD, OpenSo…

玩转Matlab-Simscape(初级)- 09 - 在Simulink中创建曲柄滑块机构的控制模型

** 玩转Matlab-Simscape&#xff08;初级&#xff09;- 09 - 在Simulink中创建曲柄滑块机构的控制模型 ** 目录 玩转Matlab-Simscape&#xff08;初级&#xff09;- 09 - 在Simulink中创建曲柄滑块机构的控制模型 前言一、问题描述二、创建模型2.1 识别机构中的刚体2.2 确定刚…

【机器学习】消息传递神经网络(MPNN)在分子预测领域的医学应用

1. 引言 1.1. 分子性质预测概述 分子性质预测是计算机辅助药物发现流程中至关重要的任务之一&#xff0c;它在许多下游应用如药物筛选和药物设计中发挥着核心作用&#xff1a; 1.1.1. 目的与重要性&#xff1a; 分子性质预测旨在通过分子内部信息&#xff08;如原子坐标、原…

11.Spring AOP

文章目录 1.什么是 Spring AOP&#xff1f;2.为什要用 AOP&#xff1f;3.Spring AOP 应该怎么学习呢&#xff1f;3.1 AOP 组成3.1.1 切⾯&#xff08;Aspect&#xff09; 切点 通知3.1.2 连接点&#xff08;Join Point&#xff09;3.1.3 切点&#xff08;Pointcut&#xff09;…

《python程序语言设计》2018版第5章第46题均值和标准方差-下部(本来想和大家说抱歉,但成功了)

接上回&#xff0c;5.46题如何的标准方差 本来想和大家说非常抱歉各位同学们。我没有找到通过一个循环完成两个结果的代码。 但我逐步往下的写&#xff0c;我终于成功了&#xff01;&#xff01; 这是我大前天在单位找到的公式里。x上面带一横是平均值。 我不能用函数的办法…

腾讯医疗大模型,不止大模型

“千呼万唤始出来&#xff0c;腾讯健康终于祭出医疗大模型。但或许这只是新故事的开始。下一步通过应用场景的打磨&#xff0c;全面嵌入生态合作伙伴&#xff0c;才能让医疗行业加速全面拥抱「数智化」工具。 在今年几乎所有企业都卷入AI大模型这场豪赌时&#xff0c;腾讯健康…

Pod之间的通信详解

在Kubernetes集群中&#xff0c;Pod之间的通信是非常核心的功能。Pod是Kubernetes中的最小部署单元&#xff0c;它们之间经常需要进行通信以完成各种任务。本文将深入探讨Pod之间的通信方式&#xff0c;并通过示例代码来进一步解释。 目录 第一章. Pod间通信的实现原理 第二章…

C++做题

我们可以将0——9看成一个一维数组&#xff1a;a[11] #include<cstdio> int a[11],n; int x,p; int main(){scanf("%d",&n);for(int i1;i<n;i){pi;while(p!0){xp%10;a[x];//让下标x每次出现时增加1(描述不清楚)p/10;}}for(int i0;i<9;i){printf(&qu…

IO多路复用详解

1. 概念 IO多路复用也称IO多路转接&#xff0c;它是一种网络通信的手段&#xff08;机制&#xff09;&#xff0c;通过这种方式可以同时监测多个文件描述符并且这个过程是阻塞的&#xff0c;一旦检测到有文件描述符就绪&#xff08; 可以读数据或者可以写数据&#xff09;程序的…

轻NAS玩客云使用Docker部署小雅并挂载到AList详细流程分享

文章目录 前言1. 本地部署AList2. AList挂载网盘3. 部署小雅alist3.1 Token获取3.2 部署小雅3.3 挂载小雅alist到AList中 4. Cpolar内网穿透安装5. 创建公网地址6. 配置固定公网地址 前言 本文主要介绍如何在安装了CasaOS的玩客云主机中部署小雅AList&#xff0c;并在AList中挂…

C语言基础学习之位运算

枚举类型 enum 枚举名 { 枚举常量 //名字 }; 注意: 1.c语言中 对于枚举类型 实际上是 当作整型处理的 2.提高代码可读性&#xff0c; 写成枚举&#xff0c;可以做语法检查 3.枚举常量&#xff0c;之间用逗号隔开 4.枚举常量&#xff0c;可以给初值&#xff0c;给了初值之后&…

当我拿到百度文心智能体大赛top1后,我又开发了...

目录 一、写在前面 二、代码助手 三、关于智能体 四、写在后面 一、写在前面 在不久前结束的文心智能体大赛&#xff08;第一期&#xff09;中&#xff0c;我有幸凭借一款名为恋爱助手的智能体斩获了大赛的桂冠。这个成绩&#xff0c;既是对我努力的认可&#xff0c;也是对…

人工智能_机器学习096_PCA主成分分析降维算法_PCA降维原理_介绍和使用_模式识别_EVD特征值分解_SVD奇异值分解---人工智能工作笔记0221

首先我来看PCA降维,可以看到在图像处理中经常用到PCA,经过对数据进行降维可以去除数据噪声,发现数据中的模式,也就是 发现数据的规律. 这里的模式识别就是 机器学习中的一个分支 就是在数据中找规律的意思 我们使用代码看一下 from sklearn.docomposition import PCA from skl…

考虑风光场景生成的电动汽车并网优化调度【遗传算法】【IEEE33】

目录 主要内容 部分代码 部分结果 下载链接 主要内容 程序主要内容是考虑风光场景生成的电动汽车并网优化调度&#xff0c;采用的方法如下所述&#xff1a; ①采用蒙特卡洛方法&#xff0c;结合copula函数以及fuzzy-kmeans&#xff0c;获取6个典型风光出力场景&…

Linux C语言:输入输出(printf scanf)

一、数据输出 1、C语言I/O操作由函数实现 #include <stdio.h> 2、字符输出函数 格式: int putchar( int c ) 参数: c为字符常量、变量或表达式 功能&#xff1a;把字符c输出到显示器上 返值&#xff1a;putchar函数的返回值是参数的ASCLL码值&#xff1b; #inclu…

1.奖牌的数量

上海市计算机学会竞赛平台 | YACSYACS 是由上海市计算机学会于2019年发起的活动,旨在激发青少年对学习人工智能与算法设计的热情与兴趣,提升青少年科学素养,引导青少年投身创新发现和科研实践活动。https://www.iai.sh.cn/problem/447 题目描述 小爱获得了 𝑎a 枚金牌,…

领导者在沟通中最容易犯的错误

本文讨论了领导者在沟通过程中如何避免成为传声筒&#xff0c;通过筛选、处理和总结信息&#xff0c;在向上、向下沟通时保持相关性和真实性&#xff0c;提高沟通效率和效果。原文: The Dumbest Mistake Leaders Make in Communication 中层管理者作为高层领导、下属团队和其他…

Vue3中的常见组件通信之`$refs`、`$parent`

Vue3中的常见组件通信之$refs、$parent 概述 ​ 在vue3中常见的组件通信有props、mitt、v-model、 r e f s 、 refs、 refs、parent、provide、inject、pinia、slot等。不同的组件关系用不同的传递方式。常见的撘配形式如下表所示。 组件关系传递方式父传子1. props2. v-mod…

Vue数据动态代理机制的实现

Object.defineProperty() &#xff08;1&#xff09;这个方法是ES5新增的 &#xff08;2&#xff09;这个方法的作用是&#xff1a;给对象新增属性&#xff0c;或者设置对象原有的属性 &#xff08;3&#xff09;用法&#xff1a;Object.defineProperty(给哪个对象新增属性,‘…

【虚拟现实】一、AR与VR的基本原理

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 增强现实&#xff08;AR&#xff09;和虚拟现实&#xff08;VR&#xff09;技术已经从科幻小说走入现实&#xf…