C++中的vector

1. 简介

在c++中,vector是一个十分有用的容器
作用:它能够像容器一样存放各种类型的对象,简单地说,vector是一个能够存放任意类型动态数组,能够增加和压缩数据。vector在C++标准模板库中的部分内容,它是一个多功能的,能够操作多种数据结构和算法的模板类函数库

2. 使用注意

1、如果你要表示的向量长度较长(需要为向量内部保存很多数),容易导致内存泄漏,而且效率会很低;

2、Vector作为函数的参数或者返回值时,需要注意它的写法:

1
double Distance(vector<int>&a, vector<int>&b)   // 其中的 “&” 绝对不能少!!!

3. 基本操作

3.1 头文件

1
#include <vector>

3.2 创建vector对象

1
2
3
4
5
6
7
vector<int> v1;         // vec是一个空int类型的vector对象,执行默认初始化
vector<int> v2(v1); // v2包含有v1所有元素的副本
vector<int> v2 = v1; // 等价于上面这条语句
vector<int> v3(n, val); // v3包含了n个int类型值为val的元素
vector<int> v4(n); // v4包含了n个重复地执行了值初始化的对象
vector<int> v5 {1, 2, 3}// v5是一个含有3个int类型的vector,其中每个元素被赋予相应的初始值
vector<int> v5 = {1, 2, 3}// 与上面语句等价

3.3 尾部插入元素 push_back()

1
vec.push_back(1);

3.4 尾部删除元素 pop_back()

1
vec.pop_back();

3.5 使用下标访问元素[]

1
cout << vec[0] << endl;		// 记住下标是从0开始的。

3.6 使用at()方法访问

1
cout << vec.at(0) << endl;	// 使用at方法访问,如果vector为空,会抛出异常,下标法则不会(效率更高)

3.7 使用迭代器访问元素

1
2
3
vector<int>::iterator it;
for(it=vec.begin(); it!=vec.end(); it++)
cout << *it << endl;

3.8 插入元素 insert()

1
vec.insert(vec.begin()+i, a);	// 在第i+1个元素前面插入a;

3.9 删除元素 erase()

1
2
vec.erase(vec.begin()+2);		// 删除第3个元素
vec.erase(vec.begin()+i, vec.end()+j); // 删除区间[i,j-1];区间从0开始

注意:size() 表示vector实际存储元素个数,capacity() 表示vector容量大小,即分配的存储空间的大小。举例记忆:一间房间有100个座位(capacity),当前只坐了40人(size)。

3.10 vectors实际存储元素个数 size()

1
vec.size();

3.11 vectors容量大小 capacity()

1
vec.capacity();

3.12 清空 clear()

1
vec.clear();

3.13 使用 reverse() 将元素翻转

1
2
3
#include <algorithm>
reverse(vec.begin(), vec.end()); // 将元素翻转,即逆序排列
// (在vector中,如果一个函数中需要两个迭代器,一般后一个都不包含) ? 没看懂

3.14 swap() 交换 vector

1
2
3
vector<int> a(3, 100);	// three ints with a value of 100
vector<int> b(5, 100); // five ints with a value of 200
a.swap(b); // swap two vectors

3.15 sort() 排序

1
2
3
4
5
6
7
8
#include <algorithm>
sort(vec.begin(),vec.end()); // 默认是按升序排列,即从小到大

// 可以通过重写排序比较函数按照降序比较,如下定义排序比较函数:
bool Comp(const int &a,const int &b) {
return a>b;
}
// 调用时:sort(vec.begin(),vec.end(),Comp); 这样就降序排序。

注意:vector提供了两个方法 resize()reserve() 分别对 size()capacity() 进行操作.
Reference:C++基础篇 – vector的resize函数和reserve函数

3.16 改变vector的大小 resize()

1
2
3
4
5
6
vector<int> vec;
vec.resize(5); // 将空vector数组大小更改为5
vec.resize(8, 35); // 将vec数组大小更改为8,并将新增加的元素,初始化为指定值35
for (int i=0;i<vec.size();i++)
std::cout << ' ' << vec[i];
// 结果为:0 0 0 0 0 35 35 35
1
2
3
4
5
6
7
1、resize方法被用来改变vector的大小,即vector中元素的数量,我们可以说,resize方法改变了容器的大小,且创建了容器中的对象;

2、如果resize中所指定的n小于vector中当前的元素数量,则会删除vector中多于n的元素,使vector得大小变为n;

3、如果所指定的n大于vector中当前的元素数量,则会在vector当前的尾部插入适量的元素,使得vector的大小变为n,在这里,如果为resize方法指定了第二个参数,则会把后插入的元素值初始化为该指定值,如果没有为resize指定第二个参数,则会把新插入的元素初始化为默认的初始值;

4、如果resize所指定的n不仅大于vector中当前的元素数量,还大于vector当前的capacity容量值时,则会自动为vector重新分配存储空间;

3.17 改变vector容量的大小 reserve()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> vect;
vect.reserve(5);

vect.push_back(1);
vect.push_back(2);
vect.push_back(3);
vect.push_back(4);

cout << vect.size() << endl;
cout << vect.capacity() << endl;

vect.push_back(5);
vect.push_back(6); // 插入两个元素,此时vect的大小大于之前分配的容量5

cout << "size1 = " << vect.size() << endl;
cout << "capacity1 = " << vect.capacity() << endl;

vect.push_back(7);
vect.push_back(8); // 在插入两个元素,和上面的结果进行对比,会有意外收获
cout << "size1_1 = " << vect.size() << endl;
cout << "capacity1_1 = " << vect.capacity() << endl;

vect.reserve(3); // 当程序执行到此处时,vect的容量大小一定是大于3的

cout << "size2 = " << vect.size() << endl;
cout << "capacity2 = " << vect.capacity() << endl;

vect.reserve(12);

cout << "size3 = " << vect.size() << endl;
cout << "capacity3 = " << vect.capacity() << endl;
return 0;
}
/**输出结果
4
5
size1 = 6
capacity1 = 10
size1_1 = 8
capacity1_1 = 10
size2 = 8
capacity2 = 10
size3 = 8
capacity3 = 12
*/
1
2
3
4
5
1、reserve方法被用来重新分配vector的容量大小;

2、只有当所申请的容量大小n大于vector的当前容量时,才会重新为vector分配存储空间;

3、reserve方法对于vector的大小(即size)没有任何影响;

4.一维数组的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
int main() {
vector<int> a; // 创建一个int类型的vector数组 a
a.push_back(1);
a.push_back(2); // 把1和2压入vector
cout << a[0] << endl; // 下标法访问数组,输出为1
cout << a.at(1) << endl; // at法访问数组,输出为2
// at和下标法的区别是,如果vector为空,调at会抛出异常,而operator[]索引的行为为定义

// 使用迭代器访问数组元素
for(vector<int>::iterator it = a.begin(); it != a.end(); it++)
cout << *it << endl;
}

5.二维数组的使用

这里简单叙述一下C++ 构建二维动态数组

1
2
3
4
int **p;
p = new int*[10]; // 注意,int*[10]表示一个有10个元素的指针数组
for (int i = 0; i < 10; ++i)
p[i] = new int[5];

1. 初始化

(1)直接使用初始化方式

1
2
vector<vector<int> > a(5, vector<int>(3, 0));
// 得到一个5行,3列,值全为0的二维数组

(2)先定义好二维数组结构,再直接赋值

1
2
3
4
5
6
7
8
9
10
// 得到一个5行3列的数组
// 由vector实现的二维数组,可以通过resize()的形式改变行、列值
int i, j;
vector<vector<int> > array(5);
for (i = 0; i < array.size(); i++)
array[i].resize(3);

for(i = 0; i < array.size(); i++)
for (j = 0; j < array[0].size();j++)
array[i][j] = (i+1)*(j+1);

(3)利用Vector的push_back函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
vector<vector<int> > vec;

vector<int> a;
a.push_back(1);
a.push_back(2);
a.push_back(3);

vector<int> b;
b.push_back(4);
b.push_back(5);
b.push_back(6);

vec.push_back(a);
vec.push_back(b);

2. 遍历

(1)利用迭代器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void reverse_with_iterator(vector<vector<int>> vec) {
if (vec.empty()) {
cout << "The vector is empty!" << endl;
return;
}

vector<int>::iterator it;
vector<vector<int>>::iterator iter;
vector<int> vec_tmp;

cout << "Use iterator : " << endl;
for(iter = vec.begin(); iter != vec.end(); iter++) {
vec_tmp = *iter;
for(it = vec_tmp.begin(); it != vec_tmp.end(); it++)
cout << *it << " ";
cout << endl;
}
}

(2)得到行、列大小,利用下标进行遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void reverse_with_index(vector<vector<int>> vec) {
if (vec.empty()) {
cout << "The vector is empty!" << endl;
return;
}

int i,j;
cout << "Use index : " << endl;
for (i = 0; i < vec.size(); i++) { // 注意,当内层每个vector没有存满时,这个样会出错
for(j = 0; j < vec[0].size(); j++)
cout << vec[i][j] << " ";
cout << endl;
}
}

注意: vector的元素不仅仅可以是int,double,string,还可以是结构体,但是要注意:结构体要定义为全局的,否则会出错。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<iostream>
using namespace std;

typedef struct rect {
int id;
int length;
int width;

  // 对于向量元素是结构体的,可在结构体内部定义比较函数,下面按照id,length,width升序排序。
  bool operator< (const rect &a) const {
if(id!=a.id)
return id<a.id;
else {
if(length!=a.length)
return length<a.length;
else
return width<a.width;
}
}
}Rect;

int main() {
vector<Rect> vec;
Rect rect;
rect.id=1;
rect.length=2;
rect.width=3;
vec.push_back(rect);
vector<Rect>::iterator it=vec.begin();
cout<<(*it).id<<' '<<(*it).length<<' '<<(*it).width<<endl;

return 0;
}

6. begin()end()front()back()区别

  • begin()

函数原型:

1
2
iterator begin();
const_iterator begin();

功能:返回一个当前vector容器中起始元素的迭代器

  • end()

函数原型:

1
2
iterator end();
const_iterator end();

功能:返回一个当前vector容器中末尾元素的迭代器

  • front()

函数原型:

1
2
reference front();
const_reference front();

功能: 返回当前vector容器中起始元素的引用

  • back()

函数原型:

1
2
reference back();
const_reference back();

功能: 返回当前vector容器中末尾元素的引用

例题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<char> v1;
vector<char>::iterator iter1;
vector<char>::iterator iter2;
v1.push_back('m');
v1.push_back('n');
v1.push_back('o');
v1.push_back('p');

cout << "v1.front() = " << v1.front() << endl;
cout << "v1.back() = " << v1.back() << endl;

iter1 = v1.begin();
cout << *iter1 << endl;
iter2 = v1.end()-1; // 注意v1.end()指向的是最后一个元素的下一个位置,所以访问最后一个元素
// 的正确操作为:v1.end() - 1;
cout << *iter2 << endl;
return 0;
}

/*
最后输出结果:
v1.front() = m
v1.back() = p
m
p
*/

7. resize()reserve()

8. Reference