vector知识点整理总结
往期目录: STL总目录-超详细
目录
vector
是什么?- 变量声明、元素遍历、迭代器及成员函数
- 代码演示
- 尾声
vector
是什么?
与我们之前介绍过的其他内容一样,vector
也是是一个STL(标准模板库)中的“容器”,能方便的存储各种各样的数据,那么他与其它的STL容器又有什么不同之处呢?
首先,我们看一看他的中文名字:动态数组
。为什么叫这个名字呢?因为他就是一个“动态”的“数组”。(废话连篇) 换一个高级一点的说法:
vector
是表示可以改变大小的数组的序列容器。
名字里既然已经有了“数组”二字,那么动态数组就像数组一样,为它当中的元素提供了连续的存储位置,这意味着,我们可以用和数组一样的方式调取和查看当中的元素。(这个嘛,我们一会慢慢说)
但vector绝对不是简单的数组,他是动态的,它的大小并不固定,换句话说,他就像孙悟空的金箍棒,你想要他多大他就多大(奇妙的比喻又增加了)。需要注意的是,很多OIer似乎并不常用这样一个很好用的容器,这是因为,vector正由于有大小可变这个特性,在他的内部,它实际的大小可能比存入的元素数量要大一些,也就是说,它占用的内存可能比你使用的要多,这就是vector
的一大缺陷,也是它的硬伤。
所以,我们可以说:
vector
消耗了更多的内存以换取用高效的方式管理存储的元素和动态增长长度的能力。
当然,vector
并不是唯一一个动态的STL容器,那么它与其他动态STL容器(比如deque, list等)相比有什么优势和劣势呢?
优势:
vector
可以有效便捷的访问元素vector
可以有效便捷的从末尾添加和删除元素
劣势:
- 对于涉及在末尾以外的位置插入或删除元素的操作,
vector
的性能比其他操作差
变量声明、元素遍历、迭代器及成员函数
头文件
你这头文件保熟吗
#include <vector>
定义一个vector
拥有一个vector
:
用法(格式):vector<类型> 名称
vector<int> vec1;
//定义一个存储int类型数据的动态数组vec1
vector<string> vec2;
//略(懒癌发作)
vector<map<int, int> > vec3;
//套娃当然也可以,注意“> >”不能连在一起,打上空格,不然会报错(编译器识别成输入用的 cin >> )其他类似情况同理
元素的访问及遍历
在刚刚的介绍中,我们已经说过,vector
名字里既然已经有了“数组”二字,那么动态数组就像数组一样,为它当中的元素提供了连续的存储位置,这意味着,我们可以用和数组一样的方式调取和查看当中的元素。也就是说,我们可以轻松的通过名称[位置]
查看vector
中相应位置的元素值。
一如既往的,vector
中位置是从0开始计数的,即第一个元素的位置为0,访问的方法是名称[0]
//假设存在一个依次存有{5,2,0}三个元素的动态数组vec
//我们有:
vec[0] == 5;
vec[1] == 2;
vec[2] == 0;
那么除此之外,STL的传统艺能便是迭代器了:
迭代器
vector
依然是有迭代器的。而且一如既往的,它是vector
的重要组成部分,那我们废话少说,直接开始:
最基本的,我们首先要定义一个迭代器:
用法(格式):vector<类型>::iterator 名称
其中类型与该迭代器所要指向的动态数组的类型保持一致,名称随意。
与其他容器相同的,我们也可以通过*迭代器名称
的方式访问迭代器当前指向的元素。
.begin() & .end()
.begin() 返回集合的首迭代器,即指向集合中最小元素的迭代器。.end() 返回集合的尾迭代器,但需要注意的是它指向的并不是集合中的最大元素而是最大元素的后一位,所以如果我们想得到最大元素,我们应该使用的是–.end()(“–”固定在.end()前而不能放在后面)
emm…vector
的迭代器应该也没什么好说的了,毕竟实际应用意义不大,那我们直接进入下一板块。
成员函数
插入元素 .push_back()
有了一个“容器”,第一步当然要存入元素咯。与数组相同的,vector
当然可以通过下标赋值,但是我们能通过这种方式来插入一个元素吗。
事实证明,不可以,虽然我们的编译器并没有报错,而程序也正常的结束了,但是他并没有给我一个我想要的值,这是为什么呢?难道说我讲错了?其实,vector
可以通过下标“赋值”不错,但前提是,赋值的这个位置必须是已经存在的,当vector
的大小为空的时候,我们向0的位置赋值当然是不成功的,但这并不能算是一个错误,所以c+ +便自动的忽略了这条指令。
所以,其实换种说法的话,我跟习惯于说下标的方式不是赋值,而是改变对应位置的值。
(可以看到,但0的位置已经存在一个元素时,下标可以正常的在这个位置赋值)
那我们再回过头来看看.push_back()
这个成员函数。
他的功能便是在vector
的末尾添加一个新元素,在其当前最后一个元素之后(这就是为什么名字里带有一个“back”)。同时,它也可以将vector
的大小有效的增加一位。这也就是为什么当我们使用过一次.push_back()
后便可以向下标为0的位置赋值了。
用法(格式):名称.push_back(值)
插入元素(2) .insert()
它与.push_back()
相同的,也是向vector
中插入一个元素,但与.push_back()
不同的是,他共需要传入两个参数,第一个是一个迭代器类型的参数,表示插入元素的位置;第二个是与vector
中值的类型相同的元素,表示插入的元素的值。也就是说,.push_back()
只能在vector
的最后一位插入一个元素,而.insert()
可以在任一位置插入一个元素,并且将该位置后面的所有元素后移一位。
用法(格式):名称.insert(迭代器, 值)
弹出元素 .pop_back()
与插入相反的就会有弹出,与.push_back()
相对应的便是.pop_back()
,光从名字便可以看出,它们两个都带有“_ back”这个后缀,所以,我们可以推断出:.pop_back
也是一个对末尾元素做手脚的成员函数。他的功能便是:删除vector
中的最后一个元素,并有效地将容器大小减少一。
用法(格式):名称.pop_back()
擦除元素 .erase()
如果说.pop_back()
是与.push_back()
相对应的,那我们也可以把.erase()
看作是与.insert()
相对应的。.insert()
的功能是在某一特定位置插入一个元素,而.erase()
便与他相反的,在某一特定位置删除一个元素(或一次性删除某一段数据)你是来找茬的吧。同样,它也可以缩小动态数组的大小。他的用法也和.insert()
极为相似(删除单个元素):
用法(格式):
删除单个元素:名称.erase(迭代器)
即删除迭代器位置的元素
删除某段元素:名称.erase(起始位置迭代器,结束位置迭代器)
删除从开始位置到结束位置的所有元素[起始位置元素,结束位置元素)。
清空动态数组 .clear()
rt,他能清空动态数组中的所有元素(销毁),留下一个大小为0(空)的数组。他没有任何的参数。
用法(格式):名称.clear()
查看动态数组的大小 .size()
这个成员函数还是一如既往的挺立着,也没什么好说的吧,就是返回动态数组中元素的个数(即动态数组的大小)。
用法(格式):名称.size()
.front() & .back()
这两个嘛,真的用处不大,我反正从来没用过,在这里简单的说一嘴,他们的用处便是返回动态数组中第一个(.front()
)和最后一个(.back()
)元素的值。
一定要区分.end()
和.back()
他们不论是从返回值的类型还是功能上都不同!用反会报错。别问我怎么知道的
代码演示
#include <iostream>
#include <vector> //头文件
using namespace std;
vector<int> vec; //定义动态数组
vector<int>::iterator it; //定义一个迭代器
int main() {
//存入元素
vec.push_back(5);
it = vec.end(); //将迭代器的位置变为最后
vec.insert(it, 2); //在迭代器位置(最后)插入元素2
//.size()
cout << vec.size() << endl; //通过输出查看此时动态数组中的元素个数(动态数组的大小)
//输出:2
//擦除元素
vec.pop_back(); //弹出动态数组最后一个元素
it = vec.begin();
vec.erase(it); //清除迭代器位置的元素
cout << vec.size() << endl;
//输出:0
vec.push_back(5);//使动态数组大小不为0
cout << vec.size() << endl; //此时数组大小为1
//输出:1
vec.clear();//清空动态数组
cout << vec.size() << endl; //数组已被清空
//输出:0
return 0;
}
emm应该差不多了,有不全的请各位大佬补充!Orz
尾声
CSP结束了,各位大佬考的怎么样,反正我是炸了。。。
没有集训了,更新速度肯定就…咳咳
本篇从 @ghb_zZZ 大佬 的文章 中借鉴了很多,得到了同意后,做了算是一个整理和提升,感谢大佬的支持和帮助!
然后…
牛逼鸭
#### 我是蒟蒻
更
新啦~~😊前排
欢迎~QwQ