vector
前言
这几天在写代码的时候用到STL较多,也感受到了STL的强大,于是我重新温习了一遍STL的内容,并把一些基础的东西,重要的内容总结提炼出来,这篇是vector篇。C++的STL给我们提供了很多可用的容器,vector就是最常用的容器之一,vector应该掌握的基础内容包括构造函数、元素的插入插入删除、赋值、存取等操作。重点内容应该掌握vector的扩容机制、内存大小的变化原理等。
1、vector简介
- vector容器为可变长数组(动态数组),可以随时插入删除元素。
- vector被称为向量容器,因为该容器擅长在尾部插入或删除元素, 在O(1)时间就能够完成;而如果要在容器头部或者中间插入数组元素,则需花费O(N)的时间,因为他需要将后面的元素往后移。(其实原理也就类似于我们在数据结构与算法中学的顺序表)
- vector与普通数组大的区别在于:数组是静态数组(容量固定的数组),而vector可以动态拓展。即可以进行容器的插入和删除,这个过程中,vector会动态调整所占用的空间。
- vector访问元素也同样要遵守不能越界的规则,否则会造成内存的安全隐患。
2、构造函数
(1)功能:用来创建vector容器
(2)方式:
cpp
1. vector<T> v;//默认无参构造
2. vector<T> v{elem1, elem2, elem3 ...}//指定元素构造
3. vector<T> v(n, elem)//将n个elem拷贝为元素构造
4. vector<T> v2(v1)//拷贝另一个vector构造
5. vector<T> v2(v1.begin(), v1.end())//区间构造,将v1区间的begin()到end()的元素赋值给v2;
//二维构造初始化
vector<vector<int>> v;
vector<vector<int>> v(n + 1, vector<int>(m + 1, 0));//二维构造
示例:
cpp
#include<iostream>
#include<vector>
using namespace std;
//打印vector
void printVector(vector<int>& v) {
for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
//vector容器构造
void test01() {
vector<int> v1;
for (int i = 0; i < 10; i++) {
v1.push_back(i);
}
printVector(v1);
vector<int> v2{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
printVector(v2);
vector<int> v3(v1.begin(), v1.end());
printVector(v3);
vector<int> v4(11, 4);
printVector(v4);
vector<int> v5(v4);
printVector(v4);
}
int main() {
test01();
return 0;
}
运行结果:
3、赋值操作
(1)功能:给vector容器赋值
(2)方式:
cpp
1. vector& operator = (const vector &vec);//重载等号运算符
2. v.assign(v1.begin(), v1.end())用assign来区间赋值
3. v.assign(n, elem),将n个elem拷贝赋值给元素
示例:
cpp
#include<iostream>
#include<vector>
using namespace std;
//打印vector
void printVector(vector<int>& v) {
for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
void test02() {
vector <int> v1;
for (int i = 0; i < 10; ++i) {
v1.push_back(i);
}
printVector(v1);
vector<int> v2;
v2 = v1;
printVector(v2);
vector<int> v3;
v3.assign(v1.begin(), v1.end());
printVector(v3);
vector<int> v4;
v4.assign(11, 4);
printVector(v4);
}
int main() {
test02();
return 0;
}
运行结果:
4、容量和大小
(1)功能:对vector容器进行容量和大小的操作
(2)方式:
cpp
1. v.empty();//用来判空
2. v.capacity();//用来获取容器中元素个数的大小
3. v.size();//用来获取容器当前元素个数
4. v.resize(int num);//用来重新指定容器的长度,如果变短则阶段删除
5. v.resize(int num, int elem);//用来重新指定容器的长度,并以elem来填充
示例:
cpp
#include<iostream>
#include<vector>
using namespace std;
//打印vector
void printVector(vector<int>& v) {
for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
//容量、大小
void test03() {
vector<int> v1;
for (int i = 0; i < 10; i++) {
v1.push_back(i);
}
printVector(v1);
if (v1.empty()) {
cout << "v1为空" << endl;
}
else {
cout << "v1不为空" << endl;
cout << "capacity容量:" << v1.capacity() << endl;
cout << "v1的大小为:" << v1.size() << endl;
//重新指定大小
v1.resize(14); //如果重新指定的比原来长了,默认用0填充新的位置
printVector(v1);
v1.resize(11, 45); //重载,参数2可以指定默认填充值
printVector(v1);
v1.resize(4); //如果重新指定的比原来短了,超出的部分会被截断
printVector(v1);
}
}
int main() {
test03();
return 0;
}
运行结果:
补充:
- vector中的capacity指的是容量,即在不分配更多内存的情况下,可以保存的最多个数,而size则是当前容器的大小。
- size 总是小于或等于 capacity
- 当容器中的size == capacity时,此时再向其中插入内容的话,则vector会申请出更多的空间。
- 申请空间时不是直接在原来的空间上连续往下开辟,而是另找一块更大的空间,完成拷贝操作后,然后把当前vector的指针指向新的更大的空间。
5、插入和删除
(1)功能:往vector容器中插入和删除元素 (2)方式:
cpp
1. v.push_back(ele);//尾插元素
2. v.pop_back();//删除最后一个元素
3. v.insert(const_iterator pos, ele);//在迭代器指向位置pos处插入元素ele
4. v.insert(const_iterator pos, count, ele);//在指定位置pos插入count个元素
5. v.erase(const_iterator pos);//删除迭代器指向位置的元素
6. v.erase(const_iterator start, const_iterator end);//删除迭代器从start到end之间的元素
7. v.clear();//删除容器中所有的元素
示例:
cpp
#include<iostream>
#include<vector>
using namespace std;
//打印vector
void printVector(vector<int>& v) {
for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
//插入和删除
void test04() {
vector<int> v1;
//尾插
v1.push_back(11);
v1.push_back(4);
v1.push_back(5);
v1.push_back(14);
printVector(v1);
//尾删
v1.pop_back();
printVector(v1);
//指定位置插入
v1.insert(v1.begin(), 114);
printVector(v1);
//指定位置指定数量插入
v1.insert(v1.begin(), 2, 514);
printVector(v1);
//删除
v1.erase(v1.begin());
printVector(v1);
vector<int> v2(v1);
//删除区间
v1.erase(v1.begin(), v1.end());
printVector(v1);
cout << "v2清空前:";
printVector(v2);
//清空
v2.clear();
cout << "v2清空后: ";
printVector(v1);
}
int main() {
test04();
return 0;
}
运行结果:
6、数据存取操作
(1)功能:对vector中的数据进行存储和拿取操作。
(2)方式:
cpp
1. operator[index];//类似数组中的[],返回索引index所指向的数据
2. at(int index);//用at函数来返回索引index所指向的数据
3. front();//返回容器中的第一个数据
4. back();//返回容器中最后一个元素
示例:
cpp
#include<iostream>
#include<vector>
using namespace std;
//打印vector
void printVector(vector<int>& v) {
for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
void test05() {
vector<int> v1;
for (int i = 0; i < 10; ++i) {
v1.push_back(i);
}
//用[]的方式访问数组中的元素
for (int i = 0; i < v1.size(); ++i) {
cout << v1[i] << " ";
}
cout << endl;
//用at的方式访问数组中的元素
for (int i = 0; i < v1.size(); ++i) {
cout << v1.at(i) << " ";
}
cout << endl;
//获取第一个元素
cout << "第一个元素为:" << v1.front() << endl;
//获取最后一个元素
cout << "最后一个元素为: " << v1.back() << endl;
}
int main() {
test05();
return 0;
}
运行结果:
7、互换容器
(1)功能:将两个容器的元素进行交换 (2)方式:
cpp
v1.swap(v2);//将v2的元素与v1元素互换
示例:
cpp
#include<iostream>
#include<vector>
using namespace std;
//打印vector
void printVector(vector<int>& v) {
for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
void test06() {
cout << "交换前:" << endl;
vector<int> v1;
for (int i = 0; i < 10; ++i) {
v1.push_back(i);
}
printVector(v1);
vector<int> v2;
for (int i = 10; i > 0; i--) {
v2.push_back(i);
}
printVector(v2);
cout << "交换后:" << endl;
v1.swap(v2);
printVector(v1);
printVector(v2);
}
int main() {
test06();
return 0;
}
运行结果:
补充(重要用途):
我们可以使用swap来使两个容器互换,加之匿名对象的性质,可以用来达到收缩内存空间的目的。方式如下:
cpp
void test07() {
vector<int> v;
for(int i = 0; i < 114514; i++) {
v.push_back(i);
}
cout << "v的容量为:" << v.capacity() << endl;
cout << "v的大小为:" << v.size() << endl;
//如果单重新指定大小的话,容量并没有变,导致多余的空间浪费
v.resize(25);
cout << "用resize(): " << endl;
cout << "v的容量为:" << v.capacity() << endl;
cout << "v的大小为:" << v.size() << endl;
//而我们可以巧用swap()来收缩内存
vector<int>(v).swap(v);//vector<int>(v)创建了一个匿名对象,会按照v大的大小初始化这个匿名对象容器的大小
//用swap()会将其与匿名函数进行交换,原容器的指针指向匿名对象的容器,原指向匿名对象容器的指针指向原容器
//系统创建完匿名函数后会对匿名对象的指针(地址、内存)进行回收
cout << "用swap+匿名函数: " << endl;
cout << "v的容量为:" << v.capacity() << endl;
cout << "v的大小为:" << v.size() << endl;
}
int main() {
test07();
return 0;
}
运行结果:
8、预留空间
(1)功能:预先开辟空间,减少vector在动态扩展容量时的扩展次数。
(2)方式:
cpp
reserve(int len);//容器预留len个元素长度,预留位置不初始化,元素不可访问
示例:
cpp
void test08() {
vector<int> v1;
int count = 0;
int* p1 = NULL;
for (int i = 0; i < 114514; i++){
v1.push_back(i);
//每扩容一次就会新开一块内存,则p指向的地址与原来的不同,以此来统计动态开辟的次数。
if (p1 != &v1[0]) {
p1 = &v1[0];
count++;
}
}
cout << "不预留空间时count: " << count << endl;
count = 0;
vector<int> v2;
v2.reserve(114514);
int* p2 = NULL;
for(int i = 0; i < 114514; i++) {
v2.push_back(i);
if (p2 != &v2[0]) {
p2 = &v2[0];
count++;
}
}
cout << "预留空间时count: " << count << endl;
}
int main() {
test08();
return 0;
}
运行结果:
vector小结
- vector容器是最常用的容器之一,大多时候需要用它来存储数据。
- 构造函数,元素访问,二维容器,遍历获取,插入删除等操作比较常见。
- 基础常用的是用[]来获取,访问,构造匿名构造和指定大小构造用得较多,push_back()也用的较多。
- 注意迭代器的访问,因为它能直接指向内存,且较灵活。
- 构造、赋值操作中的内存原理需要掌握,扩容时机制是重新开一块新的空间,指针重新指向。
- 匿名对象的地址、内存会被系统自动回收,因此可以巧用swap和匿名对象来收缩空间,另外注意一下预留空间能减少动态扩容开辟次数。
以上就是关于vector容器常见操作和原理的全部内容了,如果文章有什么错误或者遇到什么问题,欢迎随时和我交流联系。