【C++】STL--vector容器(构造、遍历、插入删除、容量大小、数据存取、动态扩容等)

小菜鸟 1年前 (2023-11-11) 阅读数 1142 #编程日记
文章标签 后端

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; }

运行结果:

vector容器构造.png

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; }

运行结果:

vector赋值操作.png

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容量和大小.png

补充:

  • 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; }

运行结果:

vector插入和删除.png

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; }

运行结果:

vector数据存取.png

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; }

运行结果:

vector互换容器.png

补充(重要用途):
我们可以使用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; }

运行结果:

vector收缩内存空间.png

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预留空间.png

vector小结

  • vector容器是最常用的容器之一,大多时候需要用它来存储数据。
  • 构造函数,元素访问,二维容器,遍历获取,插入删除等操作比较常见。
  • 基础常用的是用[]来获取,访问,构造匿名构造和指定大小构造用得较多,push_back()也用的较多。
  • 注意迭代器的访问,因为它能直接指向内存,且较灵活。
  • 构造、赋值操作中的内存原理需要掌握,扩容时机制是重新开一块新的空间,指针重新指向。
  • 匿名对象的地址、内存会被系统自动回收,因此可以巧用swap和匿名对象来收缩空间,另外注意一下预留空间能减少动态扩容开辟次数。

以上就是关于vector容器常见操作和原理的全部内容了,如果文章有什么错误或者遇到什么问题,欢迎随时和我交流联系。

文章源地址:https://juejin.cn/post/7299733832412856355
热门
标签列表