C++系列-STL容器之vector

news/2024/9/24 8:06:17/

STL概念

  • vector基本概念
    • vector与数组的区别
    • vector容器的特点
      • 动态大小
      • 连续存储
      • 自动扩容
      • 尾部操作高效
    • vector动态扩展的含义
    • vector常用的接口示意
  • vector的构造函数
  • vector赋值操作
    • =重载赋值
    • assign赋值
  • vector的容量和大小
  • vector的插入和删除
  • vector数据存取
  • vector互换容器
    • vector互换容器的使用方法
    • vector互换容器的用途
  • vector预留空间

vector基本概念

  • vector数据结构和数组非常相似,也称为单端数组。
  • vector也是一种顺序容器,在内存中连续排列。

vector与数组的区别

  • 数组是静态空间,定义好之后,长度确定。
  • vector可以动态扩展。由于其大小(size)可变,常用于数组大小不可知的情况下来替代数组。

vector容器的特点

动态大小

  • vector容器的大小可以根据需要进行动态调整。
  • 可以在运行时根据实际需求添加或删除元素,而无需在编译时确定容器的大小。
  • vector容器会自动处理内存管理。

连续存储

  • vector容器中的元素在内存中是连续存储的。
  • 可以通过下标来访问容器中的元素,并且支持快速的随机访问。

自动扩容

  • 当向vector容器中添加元素时,如果容器的当前大小不足以容纳新元素,容器会自动扩容。
  • 扩容是通过重新分配内存并将原有元素复制到新内存空间中来实现的。
  • 这种自动扩容的特性使得vector容器能够动态地适应元素的增长。

尾部操作高效

  • vector容器中的元素是连续存储的,因此在尾部进行插入和删除操作是高效的。
  • 这是因为在尾部插入或删除元素时,不需要移动其他元素,只需调整尾部指针即可。

vector动态扩展的含义

  • 并不是在在原空间后面续接新的空间,而是开辟一个更大的空间,将原数据拷贝到新空间,并删除原空间。

vector常用的接口示意

  • 迭代器v.begin():起始元素的位置, v.end(): 最后一个元素之后的位置。
  • 迭代器v.rbegin():末尾元素的位置, v.rend(): 第一个元素之前的位置。
  • front(): 第一个元素,back(): 末尾元素。
  • push_back(): 末尾添加元素,pop_back(): 末尾删除元素。
  • vector的迭代器是支持随机访问的迭代器,也就是说迭代器可以一下跳好几个。
    在这里插入图片描述

vector的构造函数

  • vector v: 采用模板类实现,默认构造函数。
  • vector(v.begin(), v.end()): 将v对象从v.begin()到 v.end()之间的元素拷贝给正在创建的对象,包头不包尾。
  • vector(n, elem): 将n个elem拷贝给正在创建的对象。
  • vector(const vector &vec): 拷贝构造函数。
#include <iostream>
#include <vector>
using namespace std;void print_vector(vector<int> &vec)
{for (vector<int>::iterator it = vec.begin(); it < vec.end(); it++){cout << *it << " ";}cout << endl;
}
void test01()
{vector<int> arr1;								// 一个空数组arr1.push_back(11);arr1.push_back(22);cout << "---------- arr1 ----------";print_vector(arr1);vector<int> arr2 {1, 2, 3, 4};					// 包含1、2、3、4这4个元素cout << "---------- arr2 ----------";print_vector(arr2);vector<int> arr3(4);							// 开辟4个空间,值默认为0cout << "---------- arr3 ----------";print_vector(arr3);vector<int> arr4(5, 3);							// 5个值为3的数组cout << "---------- arr4 ----------";print_vector(arr4);vector<int> arr5(arr3);							// 将arr3的所有值复制进去,array5和arr3一样cout << "---------- arr5 ----------";print_vector(arr5);vector<int> arr6(arr2.begin(), arr2.end());		// 将arr2的值从头开始到尾复制cout << "---------- arr6 ----------";print_vector(arr6);vector<int> arr7(arr2.rbegin(), arr2.rend());	// 将arr2的值从尾到头复制cout << "---------- arr7 ----------";print_vector(arr7);
}
int main()
{test01();system("pause");return 0;
}result:
---------- arr1 ----------11 22
---------- arr2 ----------1 2 3 4
---------- arr3 ----------0 0 0 0
---------- arr4 ----------3 3 3 3 3
---------- arr5 ----------0 0 0 0
---------- arr6 ----------1 2 3 4
---------- arr7 ----------4 3 2 1

vector赋值操作

=重载赋值

  • 函数原型 vector& operator=(const vector &vec), 重载等号运算符

assign赋值

  • v1.assign(beg迭代器,end迭代器), 将[beg迭代器,end迭代器) 之间的数据拷贝给被赋值的对象。
  • v1.assign(n,elem), 将n个elem的数据拷贝给被赋值的对象。
code:
#include <iostream>
#include <vector>
using namespace std;void print_vector(vector<int>& vec)
{for (vector<int>::iterator it = vec.begin(); it < vec.end(); it++){cout << *it << " ";}cout << endl;
}
void test01()
{vector<int> arr1{0,1,2,3,4,5,6,7,8,9};cout << "---------- arr1 ----------" << endl;print_vector(arr1);vector<int> arr2;arr2 = arr1;			// 直接用cout << "---------- arr2 ----------" << endl;print_vector(arr2);arr2.pop_back();arr2.pop_back();vector<int> arr3;arr3.assign(5, 3);		// 函数重载,将5个3赋值给arr3cout << "---------- arr3 ----------" << endl;print_vector(arr3);vector<int> arr4;arr4.assign(arr1.begin(), arr1.end()-4);	// 函数重载,迭代器参数, 迭代器可以加减操作cout << "---------- arr4 ----------" << endl;print_vector(arr4);
}
int main()
{test01();system("pause");return 0;
}result:
---------- arr1 ----------
0 1 2 3 4 5 6 7 8 9
---------- arr2 ----------
0 1 2 3 4 5 6 7 8 9
---------- arr3 ----------
3 3 3 3 3
---------- arr4 ----------
0 1 2 3 4 5

vector的容量和大小

函数原型用途
empty()判断容器是否为空
capacity()容器的容量,容量>=size
size()返回容器中元素的个数
resize(int num)重新指定容器的长度(size)为num,若容器变长,则以默认数值填充新位置,如果容器变短,则末尾超出容器长度的元素被删除
resize(int num,elem)重新指定容器的长度(size)为num,若容器变长,则以elem填充新位置,如果容器变短,则末尾超出容器长度的元素被删除
#include <iostream>
#include <vector>
using namespace std;void print_vector(vector<int>& vec)
{for (vector<int>::iterator it = vec.begin(); it < vec.end(); it++){cout << *it << " ";}cout << endl;
}
void test01()
{vector<int> arr1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};cout << "---------- arr1 ----------" << endl;print_vector(arr1);vector<int> arr2;cout << "---------- arr2 ----------" << endl;print_vector(arr2);// 判断容器是否为空if (arr1.empty()){printf("arr1 is empty");}else{cout << "arr1.capacity: " <<  arr1.capacity() << ", arr1.size: " << arr1.size() << endl;}if (arr2.empty()){printf("arr2 is empty\n");}	vector<int> arr3;arr3.assign(arr1.begin(), arr1.end());		// assign赋值迭代器参数cout << "---------- arr3 ----------" << endl;print_vector(arr3);cout << "arr3.capacity: " << arr3.capacity() << ", arr3.size: " << arr3.size() << endl;arr3.resize(7);			// resize为7,size比原数组短,超出部分删除,size减小,capacity不变cout << "---------- arr3.resize(7) ----------" << endl;print_vector(arr3);cout << "arr3.capacity: " << arr3.capacity() << ", arr3.size: " << arr3.size() << endl;arr3.resize(9);		// resize为10,size比原数长,超出部分填充0,size增加cout << "---------- arr3.resize(9) ----------" << endl;print_vector(arr3);cout << "arr3.capacity: " << arr3.capacity() << ", arr3.size: " << arr3.size() << endl;arr3.resize(16, 666);	// resize为16,size比原数组长,超出部分填充,size增大,自动扩展capacitycout << "---------- arr3.resize(16, 666); ----------" << endl;print_vector(arr3);cout << "arr3.capacity: " << arr3.capacity() << ", arr3.size: " << arr3.size() << endl;}
int main()
{test01();system("pause");return 0;
}reult:
---------- arr1 ----------
0 1 2 3 4 5 6 7 8 9
---------- arr2 ----------arr1.capacity: 10, arr1.size: 10
arr2 is empty
---------- arr3 ----------
0 1 2 3 4 5 6 7 8 9
arr3.capacity: 10, arr3.size: 10
---------- arr3.resize(7) ----------
0 1 2 3 4 5 6
arr3.capacity: 10, arr3.size: 7
---------- arr3.resize(9) ----------
0 1 2 3 4 5 6 0 0
arr3.capacity: 10, arr3.size: 9
---------- arr3.resize(16, 666); ----------
0 1 2 3 4 5 6 0 0 666 666 666 666 666 666 666
arr3.capacity: 16, arr3.size: 16

vector的插入和删除

函数原型用途
push_back(ele)尾部插入元素ele
insert(const_iterator pos, ele)迭代器指向位置pos插入元素ele
insert(const_iterator pos, int count, ele)迭代器指向位置pos插入count元素ele
erase(const_iterator pos)删除迭代器指向的元素
erase(const_iterator start, const_iterator end)删除迭代器从start到end之间的元素
clear()删除容器中所有元素
code:
#include <iostream>
#include <vector>
using namespace std;void print_vector(vector<int>& vec)
{for (vector<int>::iterator it = vec.begin(); it < vec.end(); it++){cout << *it << " ";}cout << endl;
}
void test01()
{vector<int> v1;v1.push_back(11);		// 尾插v1.push_back(22);v1.push_back(33);cout << "---------- v1尾插 ----------" << endl;print_vector(v1);v1.pop_back();			// 尾删cout << "---------- v1尾删 ----------" << endl;print_vector(v1);v1.insert(v1.begin()+1, 666);	// 在迭代器指示的位置插入666cout << "---------- v1.insert(v1.begin()+1,666) ----------" << endl;print_vector(v1);v1.insert(v1.begin(), 5, 666);	// 在迭代器指示的位置插入5个666cout << "---------- v1.insert(v1.begin(), 3, 888) ----------" << endl;print_vector(v1);v1.erase(v1.begin());			// 删除迭代器指示的位置的元素cout << "---------- v1.erase(v1.begin()) ----------" << endl;print_vector(v1);v1.erase(v1.begin(), v1.end()-2);	// 删除迭代器指示的区域cout << "---------- v1.erase(v1.begin(), v1.end()-2) ----------" << endl;print_vector(v1);v1.clear();		// 清空cout << "---------- v1.clear() ----------" << endl;print_vector(v1);
}
int main()
{test01();system("pause");return 0;
}result:
---------- v1尾插 ----------
11 22 33
---------- v1尾删 ----------
11 22
---------- v1.insert(v1.begin()+1,666) ----------
11 666 22
---------- v1.insert(v1.begin(), 3, 888) ----------
666 666 666 666 666 11 666 22
---------- v1.erase(v1.begin()) ----------
666 666 666 666 11 666 22
---------- v1.erase(v1.begin(), v1.end()-2) ----------
666 22
---------- v1.clear() ----------

vector数据存取

函数原型用途
at(int idx)返回索引idx所指的数据
operator[]返回索引idx所指的数据
front()返回容器中的第一个数据元素
back()返回容器中的最后一个数据元素
code:
#include <iostream>
#include <vector>
using namespace std;void print_vector(vector<int>& vec)
{for (int i_loop = 0; i_loop < vec.size(); i_loop++){cout << vec[i_loop] << " ";		// 使用[]重载访问}cout << endl;
}void print_vector_at(vector<int>& vec)
{for (int i_loop = 0; i_loop < vec.size(); i_loop++){cout << vec.at(i_loop) << " ";		// 使用v1.at(index)访问元素}cout << endl;
}void test01()
{vector<int> v1{11, 22, 33, 44, 55, 66};print_vector(v1);print_vector_at(v1);cout << "vector容器中的第一个元素: " << v1.front() << endl;cout << "vector容器中的最后一个元素: " << v1.back() << endl;}
int main()
{test01();system("pause");return 0;
}result:
11 22 33 44 55 66
11 22 33 44 55 66
vector容器中的第一个元素: 11
vector容器中的最后一个元素: 66

vector互换容器

  • 实现两个容器内元素互换
  • v1.swap(vec), v1与vec中的元素互换

vector互换容器的使用方法

code:
#include <iostream>
#include <vector>
using namespace std;void print_vector(vector<int>& vec)
{for (vector<int>::iterator it=vec.begin(); it<vec.end(); it++){cout << *it << " ";}cout << endl;
}void test01()
{vector<int> v1{11, 22, 33, 44, 55, 66};vector<int> v2{99, 88, 66, 77};cout << "---------- swap前 ----------" << endl;cout << "v1中的元素:";print_vector(v1);cout << "v1.capacity: " << v1.capacity() << ", v1.size: " << v1.size() << endl;cout << "v2中的元素:";print_vector(v2);cout << "v2.capacity: " << v2.capacity() << ", v2.size: " << v2.size() << endl;cout << "\n---------- swap后 ----------" << endl;v1.swap(v2);cout << "v1中的元素:";print_vector(v1);cout << "v1.capacity: " << v1.capacity() << ", v1.size: " << v1.size() << endl;cout << "v2中的元素:";print_vector(v2);cout << "v2.capacity: " << v2.capacity() << ", v2.size: " << v2.size() << endl;
}
int main()
{test01();system("pause");return 0;
}result:
---------- swap前 ----------
v1中的元素:11 22 33 44 55 66
v1.capacity: 6, v1.size: 6
v2中的元素:99 88 66 77
v2.capacity: 4, v2.size: 4
---------- swap后 ----------
v1中的元素:99 88 66 77
v1.capacity: 4, v1.size: 4
v2中的元素:11 22 33 44 55 66
v2.capacity: 6, v2.size: 6

vector互换容器的用途

  • 可以用来收缩内存空间
    请从以下代码中一窥究竟。
code:
#include <iostream>
#include <vector>
using namespace std;void print_vector(vector<int>& vec)
{for (vector<int>::iterator it = vec.begin(); it < vec.end(); it++){cout << *it << " ";}cout << endl;
}void test01()
{vector<int> v1;// 系统在开辟空间时会不断给尝试,所以capacity的值不一定是10000for (int i_loop = 0; i_loop < 10000; i_loop++)	{v1.push_back(i_loop);}cout << "---------- swap前 ----------" << endl;cout << "v1.capacity: " << v1.capacity() << ", v1.size: " << v1.size() << endl;v1.resize(3);		// 后面的数据删除,size会变小,但是capacity不会cout << "---------- v1.resize(3) ----------" << endl;print_vector(v1);cout << "v1.capacity: " << v1.capacity() << ", v1.size: " << v1.size() << endl;// vector<int>(v1)是创建匿名对象temp(实际没名字),会按照v1的实际size创建匿名对象,会自动将capacity缩小为size,// 然后temp.swap(v1),v1和temp做容器交换,将v1的capacity缩小了。// 当这条语句执行完之后,系统发现是匿名对象,会将其删掉,所以不会一直占用空间。vector<int>(v1).swap(v1);	cout << "\n---------- swap后 ----------" << endl;cout << "v1.capacity: " << v1.capacity() << ", v1.size: " << v1.size() << endl;
}
int main()
{test01();system("pause");return 0;
}result:
---------- swap前 ----------
v1.capacity: 12138, v1.size: 10000
---------- v1.resize(3) ----------
0 1 2
v1.capacity: 12138, v1.size: 3---------- swap后 ----------
v1.capacity: 3, v1.size: 3

vector预留空间

  • 减少vector在动态扩展容量时的扩展次数
    且看下面的代码:
code:
void test01()
{int num = 0;vector<int> v1;int* pt = NULL;// 系统在开辟空间时会不断给尝试,开辟一次不够,就重新开辟,每次开辟是会找一块新的区域for (int i_loop = 0; i_loop < 10000; i_loop++){v1.push_back(i_loop);if (&v1[0] != pt)		// 判断是否是一次重新开辟的空间{pt = &v1[0];num++;}}cout << "num: " << num << endl;
}
int main()
{test01();system("pause");return 0;
}result:
num: 24

从代码中可以看出,空间一共开辟了24次,当然也伴随着旧的空间释放,这些操作其实就是浪费资源。
试问怎么解决呢?且看下面代码

code:
#include <iostream>
#include <vector>
using namespace std;void print_vector(vector<int>& vec)
{for (vector<int>::iterator it = vec.begin(); it < vec.end(); it++){cout << *it << " ";}cout << endl;
}void test01()
{int num = 0;vector<int> v1;v1.reserve(10000);		// reserve找10000大的空间,给v1预留着int* pt = NULL;// 系统在开辟空间时会不断给尝试,开辟一次不够,就重新开辟,每次开辟是会找一块新的区域for (int i_loop = 0; i_loop < 10000; i_loop++){v1.push_back(i_loop);if (&v1[0] != pt)		// 判断是否是一次重新开辟的空间{pt = &v1[0];num++;}}cout << "num: " << num << endl;
}
int main()
{test01();system("pause");return 0;
}result:
num: 1

从代码中可以看出,空间一共开辟了1次,这是因为使用v1.reserve(空间大小),系统会先预留一片空间,如果没超出,就不会开辟新的。


http://www.ppmy.cn/news/1517697.html

相关文章

算法练习题03:分解质因数

【问题描述】 求出区间[a,b]中所有整数的质因数分解,统计一共有多少种不同的分法 【输入格式】 输人两个整数a和b。 【输出格式】 输出一行,一个整数,代表区间内质因数分解方法之和。 【输入样例】 6 10 【输出样例】 10 【样例说明】 6的质因数为2和3,一共有两个。7的质因…

RabbitMQ实战-JavaDemo

目录 前言 消息生产者 消息消费者 消息确认机制 消息持久化 Maven 依赖 总结 前言 在使用 RabbitMQ 进行消息传递时&#xff0c;了解如何在代码中创建和发布消息&#xff08;生产者&#xff09;、接收和处理消息&#xff08;消费者&#xff09;&#xff0c;以及配置消息…

Ubuntu20.04安装 docker和docker-compose环境

Docker简介 Docker 是一个开源的应用容器引擎&#xff0c;它使开发者能够打包他们的应用以及依赖包到一个可移植的容器中&#xff0c;然后发布到任何流行的 Linux 机器上&#xff0c;也可以实现虚拟化。容器是完全使用沙箱机制&#xff0c;相互之间不会有任何接口&#xff08;…

在 CentOS 7 上安装 LNMP 环境:MySQL 8.0、PHP 8.3 和 ThinkPHP 8.0

在 CentOS 7 上安装 LNMP 环境&#xff0c;并配置 MySQL 8.0、PHP 8.3 以及 ThinkPHP 8.0&#xff0c;能够为你的 web 应用程序提供一个强大的开发和运行环境。下面是详细的安装步骤&#xff1a; --- ## 在 CentOS 7 上安装 LNMP 环境&#xff1a;MySQL 8.0、PHP 8.3 和 Thin…

如何处理段错误

在调试代码时&#xff0c;我们会遇到一些状况百出的问题&#xff0c;尤其是段错误&#xff0c;让人头大&#xff1a; 造成段错误的原因主要是内存泄漏&#xff0c;操作空指针&#xff1b; 在很长的代码中&#xff0c;去查找问题是很困难的&#xff0c;这里可以在Linux的ubunt…

Scrapy入门学习

文章目录 Scrapy一. Scrapy简介二. Scrapy的安装1. 进入项目所在目录2. 安装软件包Scrapy3. 验证是否安装成功 三. Scrapy的基础使用1. 创建项目2. 在tutorial/spiders目录下创建保存爬虫代码的项目文件3.运行爬虫4.利用css选择器Scrapy Shell提取数据例如: Scrapy 一. Scrapy…

6个一键生成原创文案实用方法,亲测好用!

在当下的这个自媒体时代&#xff0c;文案创作的需求日益增长。无论是用于社交媒体、广告宣传还是各种内容创作&#xff0c;优质的原创文案都能起到关键作用。但有时候&#xff0c;我们在创作文案的过程中可能会陷入灵感枯竭的困境。但别担心&#xff0c;这里有6个一键生成原创文…

【系统分析师】-缓存

目录 1、常见分类 2、集群切片方式 3、Redis 3.1、分布式存储方式 3.2、数据分片方式 3.3、数据类型 3.4、持久化方案 3.5、内存淘汰机制 3.6、Redis常见问题 4、布隆过滤器 1、常见分类 1、MemCache Memcache是一个高性能的分布式的内存对象缓存系统&#xff0c;用…