目录
4.begin函数和front函数&&end函数和back函数
5.resize(),swap(),sort(),reverse()函数
前言
本文所有编写代码已全部上传到gitee
一:什么是vector
向量(vector)是一个顺序容器,它能存放各种类型的对象。可以简单认为,向量是一个能够存放任意类型的动态数组(也就是说元素的个数可变)。
二:vector常见的函数
1.函数说明表
函数名 | 函数说明 |
push_back(元素) | 增加一个元素到向量后面 |
insert(位置,元素) | 插入元素到向量的指定位置 |
insert(位置,个数n,元素) | 插入n个相同的元素到指定位置 |
insert(位置,头指针,尾指针) | 将另一个向量从头指针的位置开始到尾指针的位置结束(不包括end)之间的内容插入该向量的指定位置 |
erase(位置) | 删除指定位置的元素 |
erase(位置1,位置2) | 删除向量[位置1,位置2)中的元素 |
pop_back() | 弹出(删除)向量的最后一个元素 |
clear() | 清除向量所有元素,size()变为0 |
运算符[i] | 取向量下标为i的元素 |
front() | 取向量第一个元素 |
back() | 取向量最后一个元素 |
begin() | 返回向量头指针 (迭代器),指向第一个元素 |
end() | 返回向量尾指针,指向向量最后一个元素的下一个位置 |
rbegin() | 反向迭代器,指向最后一个元素 |
rend() | 反向迭代器,指向第一个元素之前的位置 |
size() | 返回向量中实际元素的个数 |
resize() | 重新设定向量的大小,也就是可以保存元素的个数 |
max_size() | 得到 vector 最大可以是多大。 |
empty() | 判断向量是否为空,等价于 size()为0 |
swap() | 交换两个同类型向量的数据 |
2.vector的存储和遍历
构造vector的四种方法
(1)vector():创建一个空的vector
#include <bits/stdc++.h> using namespace std; void print(vector<int> v) { for (int i = 0; i < v.size(); i++) { cout << v[i] << " "; } cout << endl; } int main() { //定义方法1:定义vector存储int类型的变量 vector<int> v; cout << v.size() << endl; v.push_back(10); v.push_back(20); v.push_back(30); print(v); return 0; } //输出为: //0 //10 20 30
(2)vector(n):创建一个元素个数为n的vector
#include <bits/stdc++.h> using namespace std; void print(vector<int> v) { for (int i = 0; i < v.size(); i++) { cout << v[i] << " "; } cout << endl; } int main() { //定义方法2:定义一个长度为5的vector,默认值为0 vector<int> v(5); cout << v.size() << endl; print(v); v.push_back(10); v.push_back(20); v.push_back(30); print(v); return 0; } //输出为: //5 //0 0 0 0 0 //0 0 0 0 0 10 20 30
(3)vector(n,t):创建一个元素个数为n且值为t的vector
#include <bits/stdc++.h> using namespace std; void print(vector<int> v) { for (int i = 0; i < v.size(); i++) { cout << v[i] << " "; } cout << endl; } int main() { vector<int> v(5, 20); print(v); v.push_back(10); print(v); return 0; } //输出为: //20 20 20 20 20 //20 20 20 20 20 10
(4)vector(begin,end):复制[begin,end)区间内的另一个数组的元素到vector中
#include <bits/stdc++.h> using namespace std; void print(vector<int> v) { for (int i = 0; i < v.size(); i++) { cout << v[i] << " "; } cout << endl; } int main() { int arr[] = { 0,1,2,3,4 }; int sz = sizeof(arr) / sizeof(arr[0]); vector<int> v(arr, arr + sz); //begin是数组名则从头开始 print(v); return 0; } //输出为: //0 1 2 3 4
需要注意的是,vector<int> v是创建了一个空的vector,不可以用下标去访问,里面有内容的时候可以访问。
vector:可以用下标访问,但不能越界。
3.vector的插入,删除
insert的几种形式
(1)insert(位置,元素)
#include <bits/stdc++.h> using namespace std; void print(vector<int> v) { for (int i = 0; i < v.size(); i++) { cout << v[i] << " "; } cout << endl; } int main() { vector<int> v; v.push_back(10); v.push_back(20); v.push_back(30); print(v); v.insert(v.begin(), 5); print(v); v.insert(v.begin() + 1, 3); print(v); return 0; //输出为: //10 20 30 //5 10 20 30 //5 3 10 20 30 }
(2)insert(位置,个数,元素)
#include <bits/stdc++.h> using namespace std; void print(vector<int> v) { for (int i = 0; i < v.size(); i++) { cout << v[i] << " "; } cout << endl; } int main() { vector<int> v; v.push_back(10); v.push_back(20); v.push_back(30); //向下标为1的位置插入5个50 v.insert(v.begin() + 1, 5, 50); print(v); return 0; //输出为 //10 50 50 50 50 50 20 30 }
(3)insert(位置,位置,位置)
例如v1.insert(v1.begin()+1,v2.begin()+2,v2.end());
可以理解为从v1起始+1的位置插入v2起始+2到v2结束的所有数字
#include <bits/stdc++.h> using namespace std; void print(vector<int> v) { for (int i = 0; i < v.size(); i++) { cout << v[i] << " "; } cout << endl; } int main() { vector<int> v1; v1.push_back(10); v1.push_back(20); v1.push_back(30); vector<int> v2; v2.push_back(100); v2.push_back(200); print(v1); //向v1的开头+1的位置插入从v2的开头到结尾的所有元素 v1.insert(v1.begin() + 1, v2.begin(), v2.end()); print(v1); return 0; //输出为 //10 20 30 //10 100 200 20 30 }
erase的用法
erase(位置1,位置2):删除从位置1到位置2的元素
erase(位置1):删除位置1指向的元素
#include <bits/stdc++.h> using namespace std; void print(vector<int> v) { for (int i = 0; i < v.size(); i++) { cout << v[i] << " "; } cout << endl; } int main() { vector<int> v; v.push_back(10); v.push_back(20); v.push_back(30); v.push_back(40); print(v); //删除v开始的数字 v.erase(v.begin()); print(v); //删除v开头+1到结尾的所有数字 v.erase(v.begin()+1, v.end()); print(v); return 0; //输出为 //10 20 30 40 //20 30 40 //20 }
4.begin函数和front函数&&end函数和back函数
begin() | 返回向量头指针,指向第一个元素 |
end() | 返回向量尾指针,指向向量最后一个元素的下一个位置 |
front() | 取向量的第一个元素 |
back() | 取向量的最后一个元素 |
可以看到,begin函数返回的是指针,如果要访问具体的元素可以使用front函数
也可以使用解引用操作符利用指针访问里面的值
需要注意的是,end函数是指向向量最后一个元素的下一个位置,无法利用解引用操作符进行访问
具体代码实现如下:
#include <bits/stdc++.h> using namespace std; void print(vector<int> v) { for (int i = 0; i < v.size(); i++) { cout << v[i] << " "; } cout << endl; } int main() { vector<int> v; v.push_back(10); v.push_back(20); v.push_back(30); v.push_back(40); //如果选择begin,也可以使用解引用操作符进行访问 cout << v.front() << " " << *v.begin() << endl; cout << v.back() << endl; return 0; //输出为: //10 10 //40 }
5.resize(),swap(),sort(),reverse()函数
resize() | 重新设置向量的大小,也就是保存元素的个数 |
swap() | 实现变量的交换 |
sort() | 对数组/向量排序 |
reverse() | 反转数组/向量 |
需要注意的是,swap,sort,reverse这样的函数,并不是vector中特有的函数,它们对于数组变量等同样适用,因此不需要写v.sort这样的表达式,这是错误的
具体代码实现如下:
#include <bits/stdc++.h> using namespace std; void print(vector<int> v) { for (int i = 0; i < v.size(); i++) { cout << v[i] << " "; } cout << endl; } int main() { int arr[] = {1,6,5,2,3,7,8}; int sz = sizeof(arr) / sizeof(arr[0]); vector<int> v(arr, arr + sz);//创建了vector,内置元素为数组arr sort(v.begin(), v.end());//排序 print(v); reverse(v.begin(), v.end());//反转 print(v); v.resize(10); //改变了v的大小,于是剩下的部分用0补齐 print(v); return 0; //输出为: //1 2 3 5 6 7 8 //8 7 6 5 3 2 1 //8 7 6 5 3 2 1 0 0 0 }
实现swap函数:
#include <bits/stdc++.h> using namespace std; void print(vector<int> v) { for (int i = 0; i < v.size(); i++) { cout << v[i] << " "; } cout << endl; } int main() { vector<int> v1; v1.push_back(10); v1.push_back(20); v1.push_back(30); vector<int> v2; v2.push_back(100); v2.push_back(200); cout << "v1:" << endl; print(v1); cout << "v2:" << endl; print(v2); swap(v1, v2);//交换两个向量 cout << "v1:" << endl; print(v1); cout << "v2:" << endl; print(v2); return 0; //输出为: //v1 : //10 20 30 //v2 : //100 200 //v1 : //100 200 //v2 : //10 20 30 }
6.二维vector
代码实现如下:
#include <bits/stdc++.h> using namespace std; int main() { vector<vector <int> > v(20); //需要注意,这里尽量写vector<vector <int> > v,最外边的两个"<"空开一格 //如果连在一起在旧版的编译器可能无法通过,因为"<<",在c++中定义为右移操作符 //vector<vector <int>> v; 可能无法通过 //vector<vector <int> > v; 一定可以通过 for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { v[i].push_back(i + j); //v[i]确定一行,循环的往每一行后加数字 } } for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { cout << v[i][j]<<" "; } cout << endl; } return 0; //输出为: //0 1 2 3 4 //1 2 3 4 5 //2 3 4 5 6 //3 4 5 6 7 //4 5 6 7 8 }
三:vector迭代器遍历
什么是迭代器?
迭代器是用来指向,遍历,修改容器元素的变量,类似于指针。
A:可以遍历STL容器内全部或部分元素的对象
B:指出容器中的一个特定位置
操作 | 效果 |
* | 返回当前位置上的元素值。如果该元素有成员,可以通过迭代器以 operator ->取用 |
++ | 将迭代器前进至下一个元素 |
==/!= | 判断两个迭代器是否指向同一位置 |
= | 为迭代器赋值(将所指元素的位置赋值过去) |
迭代器函数
操作 | 效果 |
begin() | 返回一个迭代器,指向第一个元素 |
end() | 返回一个迭代器,指向最后一个元素之后 |
具体图示化可以理解为下图:
编辑
那么,既然迭代器的功能和指针类似,那么首先温习一下指针的功能:
利用指针遍历一个字符串方法如下:
#include <bits/stdc++.h> using namespace std; int main() { char str[] = "hello world"; char* p; for (p = str; *p != '\0'; p++) { cout << *p; } return 0; //输出为: // hello world }
那么我们利用迭代器来迭代vector中的元素:
#include <bits/stdc++.h> using namespace std; int main() { int arr[] = { 10,20,30,40,50 }; vector<int> v(arr, arr + 5); //定义了一个向量 //定义一个迭代器,命名为it vector<int>::iterator it; it = v.begin(); //迭代器指向开头元素 (*it)++; //迭代器指向的元素+1 cout << *it << " " << v[0] << endl; for (it = v.begin(); it != v.end(); it++) { cout << *it << " "; } return 0; //输出为 // 11 11 迭代器把begin的元素加一,所以v[0]跟着也变化,体现了迭代器和指针有类似之处 // 11 20 30 40 50 遍历了vector }
值得注意的是,对(*it)++后导致数组v[0]也发生了变化,体现出了迭代器确实和指针一样可以改变值
vector也支持迭代器反向遍历,我们来温习一下rbegin()函数:
#include <bits/stdc++.h> using namespace std; int main() { int arr[] = { 1,2,3,4,5,6 }; vector<int> v(arr, arr + 6); vector<int>::reverse_iterator rit; for (rit = v.rbegin(); rit != v.rend(); rit++) //这里用的是rbegin(),所以用的应该是rit++ { cout << (*rit)<<" "; } return 0; //输出为: // 6 5 4 3 2 1 }
迭代器分类
常用的迭代器按功能强弱分为:输入、输出、正向、双向、随机访问五种,这里介绍常用的三种。
不同容器的迭代器,其功能强弱有所不同。例如,排序算法需要通过随机访问迭代器来访问容器中的元素,因此有的容器就不支持排序算法。
A、正向迭代器
假设 p 是一个正向迭代器,则 p 支持以下操作: ++p,p++,*p。
此外,两个正向迭代器可以互相赋值,还可以用==和!=运算符进行比较
B、双向迭代器
双向迭代器具有正向迭代器的全部功能。
双向选代器p支持--p 和 p--,使得 p 朝和++p 相反的方向移动。
C、随机访问迭代器
随机访问迭代器具有双向迭代器的全部功能
随机访问迭代器 p 还支持以下操作:
p+=i:使得 p往后移动i个元素
p-=i:使得 p往前移动i个元素
p+i:返回 p后面第i个元素的迭代器
p-i:返回 p前面第i个元素的迭代器
p[i]:返回p后面第i个元素的引用两个随机访问迭代器 p1、p2 还可以用< 、>、<=、>= 运算符进行比较
p1<p2 的含义是: p1 经过若干次 (至少一次) ++操作后,就会等于 p2
表达式p2-p1 表示迭代器p2 所指元素和迭代器p1 所指向元素的序号差(p2 和 p1 之间的元素个数减一)
不同容器支持的迭代器
容器 | 迭代器 |
vector | 随机 |
deque | 随机 |
list | 双向 |
set/multiset | 双向 |
map/multimap | 双向 |
stack | 不支持迭代器 |
queue | 不支持迭代器 |
priority_queue | 不支持迭代器 |
四:vector的一些例题
数组存数问题
题目描述
今有N个数组,初始时,N个数组均为空。共有M次操作,每次在第X个数组中加入数字Y.问最终各数组中有多少数,并将它们排序输出。比如,输入如下数据
3 5
1 3
1 2
1 1
2 1
3 1
表示有3个数组,共有5次操作,分别向第1个数组存入3,第1个数组存入2,第1个数组存入1,第2个数组存入1,第3个数组存入1。
输出如下
3 1 2 3
1 1
1 1
第1行表示:第1个数组中有3个数,排序结果为123
第2行表示:第2个数组中有1个数,排序结果为1
第3行表示:第3个数组中有1个数,排序结果为1
解题代码
#include <bits/stdc++.h> using namespace std; vector<int> v[100001]; //本质上是个数组,存储的是vector数据 int main() { int i, j, x, y, m, n; cin >> n >> m; for (i = 0; i < m; i++) { cin >> x >> y; v[x-1].push_back(y); } for (j = 0; j < x; j++) { sort(v[j].begin(),v[j].end()); } for (i = 0; i < n; i++) { cout << v[i].size(); for (j = 0; j < v[i].size(); j++) { cout << " " << v[i][j]; } cout << endl; } return 0; }
字典排序问题
题目描述
给定N个数组,要求先对这N个数组分别进行排序,然后再根据N的数组的字典序对这N个数组进行排序。输出排序的结果。
输入
第一行一个整数N,表示数组数接下来N行,每一行先包含一个整数C,表示数组的大小,接下来C个整数,表示数组中的一个元素。
输出
共N行,每行表示一个数组
#include <bits/stdc++.h> using namespace std; vector<int> a[100]; int n, c,x; int main() { cin >> n; for (int i = 0; i < n; i++) { cin >> c; //输入 for (int j = 0; j < c; j++) { cin >> x; a[i].push_back(x); } //排序 sort(a[i].begin(), a[i].end()); } //数组间字典序排序 sort(a, a + n); //输出 for (int i = 0; i < n; i++) { for (int j = 0; j < a[i].size(); j++) { cout << a[i][j]<<" "; } cout << endl; } return 0; }
约瑟夫问题
题目描述
约瑟夫问题来源于公元1世纪的犹太历史学家Josephus。问题描述,有n个人(分别以编号1,2,3...n表示)围成一个圆圈,从编号为1的人开始进行1~m正向报数,报到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;如此重复下去,直到所有的人全部出列,求最后一个出列人的编号
输入
输入文件仅有一行包含二个用空格隔开的整数N,M
输出
输出文件仅有一行包含一个整数表示一个整数,表示最后一个人在队列中的编号
本题实际上可以看成一个循环数组的问题,但我们使用vector实现,具体分析如下:
编辑
其实可以看出,解决问题的关键就是找到每次要删除的下标,这个下标有这些问题:
1.每次会遇见循环回来下标怎么处理?
2.每次下标怎么加,规律是什么?
我们找规律其实会发现,每次下标都差2,第三个就会删除,而循环回来的情况可以用到取余操作符,由于一开始下标从0开始,于是在设置寻找下标时,我们从-1开始即可。
#include <bits/stdc++.h> using namespace std; int main() { int n = 0; int m = 0; vector<int> v; cin >> n >> m; //8 3 for (int i = 1; i <= n; i++) { v.push_back(i); } //v:1 2 3 4 5 6 7 8 int c = -1; while (v.size() != 1) { c = (c + m) % v.size(); v.erase(v.begin() + c); c -= 1; } cout << v[0]; return 0; }