C++与传统的C言语有一个很大的区别,便是新增了规范模板库 STL(Standard Template Library),它是 C++ 规范库的一部分,不需求单独装置,只需求 #include 对应的头文件即可。
本文将介绍STL中最根底的一个容器:vector
留意:本文仅从入门和实用角度介绍vector的用法。如有不严谨的当地欢迎指正!
引进头文件
在运用vector之前需求用#include <vector>
来引进头文件。
假如你是竞赛选手,也能够用万能头#include <bits/stdc++.h>
其中包含了<vector>
。
vector简介
vector能够理解为动态数组,它的巨细会跟着元素的添加而主动增大。下标从0
开始,巨细为n
的vector的可用规模是[0, n - 1]
。
vector中不仅能够寄存int, char
等根底数据类型,还能够寄存结构体、类
等等。
可是一个vector中只能寄存一种类型。
初始化
现在咱们能够着手来生成一个vector试试:
vector<int> v(3, 5);//生成一个vector,其中有3个值为5的元素
二维数组后面会讲到。
遍历数组
既然是数组肯定少不了遍历嘛对吧~
思路是,先用v.size()
获取vector的巨细,然后用for循环遍历。
//v.size()回来值为unsigned int
for(int i = 0;i < v.size(); ++ i)
{
printf("%d", v[i]);
}
//成果为: 5 5 5
在C++11之后,能够运用auto
关键字进行遍历,这个在后面会讲到。
刺进元素
void push_back(const T& x)
vector有一个叫push_back()
的方法,能够在数组尾部刺进一个元素且令数组巨细+1。
举个例子:
printf("%d\n", (int)v.size());//v.size() = 3
for(int i = 1;i <= 3; ++ i)v.push_back(i);
//现在 v 是: 5 5 5 1 2 3
//v.size() = 6
一般只向尾部刺进元素,由于向其他方位刺进元素的复杂度较高。
删去元素
void pop_back()
删去最终一个元素。
void clear()
清空vector,巨细变为0
void erase(iter l, iter r)
清空迭代器指向的区间[l,r)[l, r)的元素。
v.pop_back();
//5 5 5 1 2
v.clear();
//null
其他的一般也用不着。
判别是否为空
bool empty()
判别vector是否为空
vector<int> a(3);
//v.empty() == false
a.clear();
//v.empty() == true
一些常用函数(以下 v 指实例对象)
v.resize(n)
将vector巨细修改为n
v.begin()
获取vector第一个元素的迭代器(指针)
v.end()
获取vector最终一个元素的后一个方位的迭代器
v.rbegin()
获取vector倒数第一个元素的迭代器(指针)
v.rend()
获取vector倒数最终一个元素的后一个方位的迭代器
vector<int> v = {1, 2, 3}
cout << *v.begin() << '\n';//1
cout << *v.rbegin() << '\n';//3
cout << *(++ v.begin()) << '\n';//2
留意迭代器只能++
或者--
,不能够做 += n
这种操作!
欢迎在右上角留下邮箱订阅我的博客哦!每周更新优质算法、计算机、互联网文章!
一些实例用法
下面介绍一些vector的实例化用法。
auto关键字遍历vector
有时分用auto
关键字是一件很美的事儿,比如在写dfs的时分,不用管子节点的顺序,直接往下递归即可,用auto
比用下标来写循环更安全。
需求留意一点,auto
默许为浅复制,也便是复制出的一个副原本进行遍历,假如想要遍历vector本身,需求加个&
,看以下的例子就明白了。
vector<int> v = {1, 5, 2, 4, 3};
for(auto i : v)i = 1;
//v = {1, 5, 2, 4, 3}
for(auto &i : v)i = 1;
//v = {1, 1, 1, 1, 1}
当然你也自己测验,把地址打出来看看。
并且,用&
会比直接浅复制更快。
vector排序
给vector排序,需求先引进<algorithm>
头文件:
#include <algorithm>
using namespace std;
int main()
{
vector<int> v = {5, 1, 3, 2, 4};
sort(v.begin(), v.end());//传入vector的首尾迭代器
//v = {1 2 3 4 5}
}
这样排序默许是升序的,能够运用reverse(iterator first, iterator last)
进行翻转,写法和sort相似:
reverse(v.begin(), v.end());
//v = {5, 4, 3, 2, 1}
假如想在排序的时分一步到位排成降序,能够自定义比较函数,这儿不再赘述。
排序并去重
在做离散化时常常用到vector,由于它能够便利的进行排序去重。
unique(iterator first, iterator last)
能够将重复的元素移动到结尾的方位,前提是vector升序。
对于vectorv = {1, 1, 2, 5}
,unique(v.begin(), v,end())
的成果为:v = {1, 2, 5, 1}
并回来v.begin() + 3
表明去重后的终点方位(即有用数组的最终一个元素的下一个方位)。
vector<int> v = {1, 5, 2, 2, 1, 7, 7};
sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end());
//v = {1, 2, 5, 7}
二维数组
起始便是把vector里面存的元素改为vector,便是套娃。
vector<vector<int> > v2;
这样会发生一个巨细为0
的二维数组。
你能够经过resize()
为每一个行设置一个巨细,从而发生每一行都巨细不同的二维数组:
vector<vector<int> > v2;
v2.resize(3);
for(int i = 0;i < 3; ++ i)v2[i].resize(i + 1);
/*
v = {
{0}
{0, 0}
{0, 0, 0}
};
有点奇特
*/
在做邻接表的时分常常运用vector,可是我习惯于开vector数组,即下面这种写法:
vector<int> g[maxn];
值得留意的一点(功能)
vector尽管能够动态拓荒空间,可是这也是有代价的。
vector的空间不是一个一个开的,而是每逢元素个数超出了当时的空间,就会拓荒一个巨细为原先两倍(也有说法是1.5倍)的空间,然后再将原本的数据复制曩昔,这就会增大vector的常数了。
所以假如你的vector巨细或者规模已知,所以建议在初始化的时分就规则好巨细。比如初始化的时分用vector<int> v(n)
,可是留意此刻size()
已经是n
了。