C++ vector 的使用

news/2025/3/13 18:32:02/

· CSDN的uu们,大家好。这里是C++入门的第十七讲。
· 座右铭:前路坎坷,披荆斩棘,扶摇直上。
· 博客主页: @姬如祎
· 收录专栏:C++专题

目录

1. 构造函数 

1.1 vector(size_t n, const T& val = T())

1.2  vector (const vector& x)

1.3 无参构造 

2. size_t size() const

3. void resize (size_t n, T val = T())

4. size_t capacity() const

5. bool empty() const

6. void reserve (size_t n)

7. T& operator[] (size_t n)

8. T& front()

9. T& back()

10. void push_back (const T& val)

11. void pop_back() 

12. void insert ()

12.1 iterator insert (iterator pos, const T& val)

12.2 void insert (iterator position, size_t n, const T& val)

13. erase()

13.1 iterator erase (iterator pos)

13.2 iterator erase (iterator first, iterator last)

14. void swap(vector& v)

15. void clear()


1. vector是表示可变大小数组的序列容器。

2. 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。

3. 本质讲,vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小 为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言,这是 一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大 小。

4. vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存 储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是 对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。

5. 因此,vector占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增 长。

6. 与其它动态序列容器相比(deque, list and forward_list), vector在访问元素的时候更加高效,在末 尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起 list (双向链表) 和forward_list (单向链表) 统一的迭代器和引用更好。

1. 构造函数 

 

库里面有很多重载的版本,看看就行,我们学习最常用的!

1.1 vector(size_t n, const T& val = T())

在学习和模拟string的时候没有用到模板,那是因为 string 的出现非常早,并且也没必须做成模板类嘛!但是vector就不一样了,vector里面可以存储各式各样的数据类型,不做成模板那可老难受了!所以这个构造函数里面的 T 就是模板参数,缺省值 val = T() 表示不给 val 传参调用 T 的默认构造当作 val 的缺省值。

这个构造函数表示为 vector 开辟 n 个 T 类型数据大小的实际空间,并初始化为 val。

例如:vector<int> v(10),开辟 10 个整形的空间,并且初始化为 0,为啥是初始化为 0 呢,因为 int() 的结果就是 0。

#include<vector>
#include<iostream>
using namespace std;int main()
{vector<int> a(10, 2); // 10个整形大小的空间,初始化为 2 return 0;
}

1.2  vector (const vector& x)

这是拷贝构造函数,就不用多说啦!支持用一个 vector 对象构造出一个新的 vector 对象。

#include<vector>
#include<iostream>
using namespace std;int main()
{vector<int> a(10, 2);vector<int> b(a);return 0;
}

1.3 无参构造 

在写代码的时候,我们经常习惯这么写:

vector<int> a;

这么写vector会分配空间嘛! 

显然,没有分配空间,无参构造出来的 vector 是不能用下标去访问数据的,因为压根就没有分配空间嘛!

2. size_t size() const

这个函数可以返回一个vector对象实际存储元素的个数!

#include<vector>
#include<iostream>
using namespace std;int main()
{vector<int> a(10);cout << a.size() << endl; //输出:10vector<int> b;cout << b.size() << endl; //输出:0return 0;
}

3. void resize (size_t n, T val = T())

这个函数跟 string 的那个 resize 简直一毛一样。当 n 大于原 vector 的 size,就会用 val 初始化新获得的空间,不传 val 就是用 T 类型的默认构造的值来初始化新获得的空间;当 n 小于原 vector 的 size,直接截断就行啦!

当 n 小于原 vector 的 size 时:

#include<vector>
#include<iostream>
using namespace std;int main()
{vector<int> a(10);for (int i = 0; i < 10; i++)a[i] = i + 1;a.resize(5);return 0;
}

当 n 大于原 vector 的 size 时:

#include<vector>
#include<iostream>
using namespace std;int main()
{vector<int> a(5);for (int i = 0; i < 5; i++)a[i] = i + 1;a.resize(10, 88);return 0;
}

4. size_t capacity() const

这个函数用来返回 vector 实际维护空间的大小,这一点与 string 是十分相似的!size用来维护 实际存储的元素个数,capacity 用来维护实际容量,方便扩容的实现!

不同编译器的扩容逻辑都是不相同的,在不同编译器的结果可能不尽相同!

#include<vector>
#include<iostream>
using namespace std;int main()
{vector<int> a;cout << a.capacity() << endl; //输出:0vector<int> b(10);cout << b.capacity() << endl; //输出:10return 0;
}

5. bool empty() const

这个函数用来判断 vector 的 size 是否等于 0,如果 vector 的size == 0,返回 true 否则返回 false。

#include<vector>
#include<iostream>
using namespace std;int main()
{vector<int> a;cout << a.empty() << endl; //输出:1return 0;
}

6. void reserve (size_t n)

这个函数可以改变 vector 维护的实际空间大小,这个函数和 string 的reserve 相似,即改变capacity的大小!

7. T& operator[] (size_t n)

一个类的对象支持下标访问元素的根本原因就是该类重载了[]运算符!重载 [] 运算符使得我们可以轻松地访问和修改vector 的元素。

T 是模板参数哈,因为 vector 是个模板类,vector 存储的元素类型需要在编译时才能确定!

该函数的实现依然是有 const 和非 const 版本,支持 const 对象的调用 和 非 const 对象的调用。

#include<vector>
#include<iostream>
using namespace std;int main()
{vector<int> a(10, 1);//修改vector中的元素for (int i = 0; i < 10; i++)a[i]++;//访问vector中的元素,输出:2 2 2 2 2 2 2 2 2 2for (int i = 0; i < 10; i++)cout << a[i] << " ";cout << endl;return 0;
}

8. T& front()

 返回 vector 中的第一个元素,很简单哈!

#include<vector>
#include<iostream>
using namespace std;int main()
{vector<int> a(10, 1);cout << a.front() << endl; //输出:1return 0;
}

9. T& back()

返回 vector 数组中最后一个元素,同样比较好理解!

#include<vector>
#include<iostream>
using namespace std;int main()
{vector<int> a(10);for (int i = 0; i < 10; i++)a[i] = i;cout << a.back() << endl; //输出:9return 0;
}

10. void push_back (const T& val)

这个函数就是在 vector 数组的末尾增加一个元素。

比如:你有一个 vector,他的 size 是 10,那么调用 push_back() 函数,就会在 下标为 10 的位置插入一个元素,同时这个vector 的size 变为 11。

#include<vector>
#include<iostream>
using namespace std;int main()
{vector<int> a(10);a.push_back(10);cout << a.back() << endl; //输出:10return 0;
}

11. void pop_back() 

这个函数也是很简单哇!删除 vector 数组最后那个元素,就是 下标为 size - 1 的那个元素。

#include<vector>
#include<iostream>
using namespace std;int main()
{vector<int> a(10);a.push_back(10);a.pop_back();cout << a.back() << endl; //输出:0return 0;
}

12. void insert ()

12.1 iterator insert (iterator pos, const T& val)

这个 iterator 就是 vector 的迭代器哈!在 string 的模拟实现中,我们知道了 string 的迭代器就是一个 char*。那 vector 的迭代器是啥呢?没错就是 T*。在 string 和 vector 中迭代器都是指针,但是我想说的就是迭代器不完全是指针哈,在我们模拟实现 list 以及后面的容器的时候你就知道啦!

这个函数就是在 一个迭代器的位置插入一个值为 val 的元素,并且返回新插入元素位置的迭代器。

如上图,我们要在 pos 位置插入一个新的元素,那么我们就要将包括 pos 在内的所有元素向后移动一个下标,插入新的元素 val 之后,返回 pos 位置的迭代器!

#include<vector>
#include<iostream>
using namespace std;int main()
{vector<int> a;a.push_back(1);a.push_back(2);a.push_back(3);a.push_back(4);a.insert(a.begin() + 2, 5); // 在下标为 2 的位置插入一个元素 5 //输出:1 2 5 3 4for (auto e : a)cout << e << " ";cout << endl;return 0;
}

12.2 void insert (iterator position, size_t n, const T& val)

这个函数就是在 pos 位置插入 n 个 val 元素!原理和上面的差不多哈!举个例子方便大家理解!

#include<vector>
#include<iostream>
using namespace std;int main()
{vector<int> a(3, 1);a.insert(a.begin(), 3, 0); //在下标为 0 的位置插入三个0//输出:0 0 0 1 1 1for (auto e : a)cout << e << " ";cout << endl;return 0;
}

13. erase()

13.1 iterator erase (iterator pos)

这个函数可以删除 pos 位置的元素,然后返回 pos 位置的下一个位置的迭代器!

可以看看例子加深理解,是在理解不了也没关系,下一讲模拟实现 vector 保证你彻彻底底理解erase。

#include<vector>
#include<iostream>
using namespace std;int main()
{vector<int> a;a.push_back(1);a.push_back(2);a.push_back(3);//删除下标为 1 的元素auto it = a.erase(a.begin() + 1);cout << *it << endl;return 0;
}

13.2 iterator erase (iterator first, iterator last)

 这个函数能够删除两个迭代器之间的所有元素,删除的范围是:[first, last)。左闭右开的一个区间哈!

#include<vector>
#include<iostream>
using namespace std;int main()
{vector<int> a;a.push_back(0);a.push_back(1);a.push_back(2);a.push_back(3);a.push_back(4);a.push_back(5);a.push_back(6);//删除下标为 [1, 4) 的所有元素a.erase(a.begin() + 1, a.begin() + 4);//输出:0 4 5 6for (auto e : a)cout << e << " ";cout << endl;return 0;
}

14. void swap(vector<T>& v)

 这个函数可以实现两个 vector 之间的交换,和 string 里面的那个swap 差不多!

#include<vector>
#include<iostream>
using namespace std;int main()
{vector<int> a(3, 1);vector<int> b(3, 2);a.swap(b);//输出:2 2 2for (auto e : a)cout << e << " ";cout << endl;//输出:1 1 1for (auto e : b)cout << e << " ";cout << endl;return 0;
}

15. void clear()

 这个函数可以清空 vector 中存储的所有元素。

我们实现的时候,只需要将 size 置为 0,就可以啦!capacity 是不需要改变的!

vector 的使用相比 string 的使用就简单多了!


http://www.ppmy.cn/news/1167146.html

相关文章

Vue 3.0中Treeshaking特性是什么?

一、是什么 Tree shaking 是一种通过清除多余代码方式来优化项目打包体积的技术&#xff0c;专业术语叫 Dead code elimination 简单来讲&#xff0c;就是在保持代码运行结果不变的前提下&#xff0c;去除无用的代码 如果把代码打包比作制作蛋糕&#xff0c;传统的方式是把鸡…

Java RestTemplate使用TLS1.0(关闭SSL验证)

1. 问题 使用RestTemplate调用Http API时&#xff0c;服务器是TLS1.0&#xff0c;但是客户端Java默认禁止TLS1.0&#xff0c;会报错&#xff1a;org.springframework.web.client.ResourceAccessException: I/O error on POST request for “https://10.255.200.114/health”: …

MATLAB - excel 读取

matlab中excel 读取 1. 写入excel文件 - xlswrite2. 读取excel文件 - xlsread 1. 写入excel文件 - xlswrite xlswrite(filename,A,sheet,xlRange) % 写入字符串 % 注意事项&#xff1a;Str需要是Cell格式&#xff0c;否则一个字母占一格 % Str {‘abc’}&#xff1b; xlswr…

【进阶C语言】C语言文件操作

1. 为什么使用文件 2. 什么是文件 3. 文件的打开和关闭 4. 文件的顺序读写 5. 文件的随机读写 6. 文本文件和二进制文件 7. 文件读取结束的判定 8. 文件缓冲区 一、文件与文件的意义 1.文件的意义 文件的意义&#xff0c;无非就是为什么要使用文件&#xff1f; &#xff08;1&…

扩展某个Vue组件时会怎么做?

答题思路&#xff1a; 按照逻辑扩展和内容扩展来列举&#xff0c;逻辑扩展有&#xff1a;mixins、extends、composition api&#xff1b;内容扩展有slots&#xff1b; 分别说出他们使用方法、场景差异和问题。 作为扩展&#xff0c;还可以说说vue3中新引入的composition api…

接口收费背后的商业伦理

文/明道云创始人任向晖 周末去一家Shopping Mall&#xff0c;先到一个服装品牌店铺买一件秋季外套&#xff0c;结账时收银员说&#xff0c;帅哥&#xff0c;不好意思&#xff0c;衣服499&#xff0c;但是您还需要付五块钱商场管理费。我很惊讶&#xff0c;问为什么&#xff0c;…

LSTM-Attention单维时间序列预测研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

微信小程序进阶——后台交互

目录 一、后台准备 1.1 pom.xml 1.2 配置数据源 1.3 整合mybatis 二、前后端交互 2.1 method1 2.2 method2 2.2.1 封装request 2.2.2 头部引用util 2.2.3 编写方法 2.2.4 展示效果 三、WXS的使用 3.1 会议状态 3.1.2 引入wxs 3.1.3 修改代码 3.1.4 展示效果 3…