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中只能寄存一种类型。

初始化

[C++STL教程]1.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了。