【STL】vector 基础,应用与操作
vector 是 C++ 标准库中最常用的顺序容器之一,提供了动态数组的功能。与普通数组相比,vector 能够根据需求自动扩展或收缩,为程序员提供了更灵活的数据存储方案。本文将详细介绍 vector 的相关操作,并结合实例代码帮助读者深入理解。
1.vector基础操作汇总
1.vector构造函数:创建vector容器
vector<T> v;
//采用模板实现类实现,默认构造函数
vector(v.begin(), v.end());
//将v[begin(), end())区间中的元素拷贝给本身。
vector(n, elem);
// 构造函数将n个elem拷贝给本身。
vector(const vector& vec);
//拷贝构造函数
2.vector赋值操作:给vector容器进行赋值
vector& operator=(const vector& vec);
//重载等号操作符
assign(beg, end);
//将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem);
//将n个elem拷贝赋值给本身
3.vector容量和大小:对vector容器的容量和大小操作
empty();
//判断容器是否为空
capacity();
//容器的容量(注意:capacity永远大于等于size)
size();
//返回容器中元素的个数
resize(int num);
//重新指定容器的长度为num,若容器变长,则以默认值填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删除。
resize(int num, elem);
//重新指定容器的长度为num,若容器变长,则以elem值填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删
4.vector插入和删除:对vector容器进行插入、删除操作
push_back(ele);
// 尾部插入元素ele
pop_back();
// 删除最后一个元素
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();
//删除容器中所有元素
5.vector数据存取: 对vector中的数据的存取操作
at(int idx);
//返回索引idx所指的数据
operator[];
//返回索引idx所指的数据
front();
//返回容器中第一个数据元素
back();
//返回容器中最后一个数据元素
6.vector互换容器:实现两个容器内元素进行互换
swap(vec);
// 将vec与本身的元素互换
7.vector预留空间:减少vector在动态扩展容量时的扩展次数
reserve(int len);
//容器预留len个元素长度,预留位置不初始化,元素不可访问。
2. vector 的基本介绍
vector 是一种动态数组,它能够根据需要自动调整自身的大小。它允许快速随机访问,并且能在末尾进行高效的插入和删除操作。
特点:
- 支持随机访问,时间复杂度为 O(1)。
- 动态分配内存,自动扩展存储空间。
- 插入和删除操作在末尾处效率最高。
3. vector 的创建与基本操作
vector 容器提供了多种创建方式,方便用户根据不同的需求进行初始化。
- 默认构造: 创建一个空的 vector。
vector<int> v;
- 指定大小构造: 创建一个指定大小的 vector,并用默认值填充。
vector<int> v(10); // 创建一个包含10个元素的vector,初始值为0
- 指定初始值构造: 创建一个指定大小的 vector,并用给定的初始值填充。
vector<int> v(10, 5); // 创建一个包含10个元素的vector,初始值为5
- 列表初始化(C++11 新特性): 通过列表直接初始化 vector。
vector<int> v = {1, 2, 3, 4, 5};
4. vector赋值操作:给vector容器进行赋值
-
vector& operator=(const vector& vec);
//重载等号操作符 -
assign(beg, end);
//将[beg, end)区间中的数据拷贝赋值给本身。 -
assign(n, elem);
//将n个elem拷贝赋值给本身
//2.vector赋值操作:给vector容器进行赋值
void test2()
{
vector<int>v1;
for (int i = 0; i < 6; i++)
{
v1.push_back(i + 1);
}
print(v1);
//赋值:
//重载等号运算符
vector<int>v2;
v2 = v1;
print(v2);
//assign:注意左开右闭
vector<int>v3;
v3.assign(v1.begin(), v1.end()-1);//这里赋值了v1的所有元素
print(v3);
//assign:n个elem赋值
vector<int>v4;
v4.assign(10, 100);//向v4插入10个100
print(v4);
}
5.vector容量和大小:对vector容器的容量和大小操作
-
empty();
//判断容器是否为空 -
capacity();
//容器的容量(注意:capacity永远大于等于size) -
size();
//返回容器中元素的个数 -
resize(int num);
//重新指定容器的长度为num,若容器变长,则以默认值填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删除。 -
resize(int num, elem);
//重新指定容器的长度为num,若容器变长,则以elem值填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删
//3.vector容量和大小:对vector容器的容量和大小操作
void test3()
{
vector<int> v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
print(v1);
//判断v1是否为空
if (v1.empty())
{
cout << "v1为空" << endl;
}
else
{
cout << "v1不为空" << endl;
cout << "v1的容量 = " << v1.capacity() << endl;//capacity永远大于等于size
cout << "v1的大小 = " << v1.size() << endl;
}
//resize 重新指定大小 ,若指定的更大,默认用0填充新位置,可以利用重载版本替换默认填充
v1.resize(15, 10);
print(v1);
//resize 重新指定大小 ,若指定的更小,超出部分元素被删除
v1.resize(5);
print(v1);
}
6.vector插入和删除:对vector容器进行插入、删除操作
-
push_back(ele);
// 尾部插入元素ele -
pop_back();
// 删除最后一个元素 -
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();
-
等价于:
erase(v.begin(),v.end());
//删除容器中所有元素
//4.vector插入和删除:对vector容器进行插入、删除操作
void test4()
{
vector<int> v1;
//尾插
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
v1.push_back(40);
v1.push_back(50);
print(v1);
//尾删
v1.pop_back();
print(v1);
//插入:第一个参数是迭代器
v1.insert(v1.begin(), 100);//头部插入100
print(v1);
//从传入的迭代器开始,插入2个1000
v1.insert(v1.begin(), 2, 1000);//头部插入两个1000
print(v1);
//删除:参数也是迭代器
v1.erase(v1.begin());//删除第一个元素
print(v1);
//清空
//v1.erase(v1.begin(), v1.end());等价于下面语句
v1.clear();
print(v1);
}
7.vector数据存取: 对vector中的数据的存取操作
-
at(int idx);
//返回索引idx所指的数据 -
operator[];
//返回索引idx所指的数据 -
front();
//返回容器中第一个数据元素 -
back();
//返回容器中最后一个数据元素
//5.vector数据存取: 对vector中的数据的存取操作
void test5()
{
//数据的访问
vector<int>v1;
for (int i = 0; i < 5; i++)
{
v1.push_back(i + 1);
}
//获取方式1:中括号的方式[]
for (int i = 0; i < v1.size(); i++)
{
cout << v1[i] << " ";
}
cout << endl;
//获取方式2:利用成员函数at来访问
for (int i = 0; i < v1.size(); i++)
{
cout << v1.at(i) << " ";
}
cout << endl;
//获取vector容器的首尾元素
cout << "第一个元素为:"<<v1.front() << endl;
cout << "最后一个元素为:" << v1.back() << endl;
}
8.vector互换容器:实现两个容器内元素进行互换
swap(vec);
// 将另一个vector容器vec与本身的元素互换
巧用swap()可以收缩内存空间
//6.vector互换容器:实现两个容器内元素进行互换
void test6()
{
//构建两个内容不同的vector容器
vector<int>v1;
for (int i = 0; i < 6; i++)
{
v1.push_back(i * 2);
}
vector<int>v2;
for (int i = 0; i < 4; i++)
{
v2.push_back(i + 2);
}
cout << "交换前:" << endl;
cout << "v1:";
print(v1);
cout<<endl<<"v2:";
print(v2);
//进行交换操作
v1.swap(v2);
cout << endl;
cout << "交换后:" << endl;
cout << "v1:";
print(v1);
cout << endl << "v2:";
print(v2);
//核心与实际应用:巧用swap()可以收缩内存空间
vector<int>v3;
for (int i = 0; i < 10000; i++)
{
v3.push_back(i);//这里尾插了10000个元素,数据量非常大
}
//注意这里编译器自动分配容量,它一定大于等于size
cout << "v3的容量是:" << v3.capacity() << endl;
cout << "v3的大小是:" << v3.size() << endl;
cout << endl;
//当我们重新指定v3的大小时(这里是收缩),实际上v3的容量不会收缩,只是将size缩小当前指定的大小
v3.resize(3);
cout << "v3的容量是:" << v3.capacity() << endl;
cout << "v3的大小是:" << v3.size() << endl;
cout << endl;
//巧用swap()收缩内存空间
vector<int>(v3).swap(v3);
//详细分析见杂谈
cout << "v3的容量是:" << v3.capacity() << endl;
cout << "v3的大小是:" << v3.size() << endl;
}
9.vector预留空间:减少vector在动态扩展容量时的扩展次数
reserve(int len);
//容器预留len个元素长度,预留位置不初始化,元素不可访问。
用于减少vector容器扩容次数
//7.vector预留空间:减少vector在动态扩展容量时的扩展次数
//注意与resize不同,reserve(加长时)预留的新位置不会初始化,元素不可访问
void test7()
{
//统计开辟次数:
vector<int> v1;
int num = 0;
int* p = NULL;
for (int i = 0; i < 10000; i++)
{
v1.push_back(i);
//如果p不指向v1的首地址,说明发生了扩容操作,计数器加1
if (p != &v1[0])
{
p = &v1[0];
num++;
}
}
//通过以上方法我们就获得了插入10000个数据之后,扩容的总次数。
cout << "v1一共开辟了多少次:" << num << endl;
//通过结果我们就了解了插入10000个数据一定会扩容好多次
//为了减少扩容的次数,我们就可以尝试使用reserve();
vector<int> v2;
//直接通过reserve()来为vector预留10000个数据量的空间
//这样,最终只会扩容1次,就将所有数据插入到v2中了
v2.reserve(10000);
int num1 = 0;
int* p1 = NULL;
for (int i = 0; i < 10000; i++)
{
v2.push_back(i);
//如果p不指向v1的首地址,说明发生了扩容操作,计数器加1
if (p1 != &v1[0])
{
p1 = &v1[0];
num1++;
}
}
cout << "v2一共开辟了多少次:" << num1 << endl;
}
10.一维vector的综合应用:
//1.一维vector的综合应用
void test01()
{
//1.创建了一个vector容器(可理解为一维数组)
vector<int>v;
vector<int> x; // 构造int数组,长度为0,没有初值
vector<int> x1(100); // 构造初始长100的int数组,初值默认为0
vector<int> x2(200, 5); // 构造初始长200的int数组,初值为5
vector<int>mm = { 1,2,3,4 }; //构建并初始化一维数组:
//2.向容器尾部插入一些数据
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
//3.删除尾部的一些数据
v.pop_back();
v.pop_back();
//4一维vector的遍历
//4.1通过迭代器访问容器中的数据
//暂时把迭代器想象成指针
vector<int>::iterator itbegin = v.begin();//起始迭代器,指向容器中第一个元素
vector<int>::iterator itend = v.end();//结束迭代器,指向容器中最后一个元素的下一个位置
//4.1.1while遍历:(不推荐使用)
while (itbegin != itend)
{
cout << *itbegin << " ";
itbegin++;//迭代器自增,向后走一个元素的位置
}
cout << endl;
//4.1.2.for遍历:(比较常用)
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
//4.1.3.stl的遍历算法(回调函数遍历方法,暂时不懂)
for_each(v.begin(), v.end(), myprint);
cout << endl;
//4.1.4.用auto简化迭代器的使用
for (auto it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
//4.3.基于范围的for循环
//4.3.1
for (int it : v)
//for(int & it:v) 加引用
//for(const int &it:v) 加只读操作
{
cout << it << " ";
}
cout << endl;
//4.3.2.
//for (auto it:v)
//for(auto & it:v) 加引用
for (const auto& it : v) //加只读操作
{
cout << it << " ";
}
cout << endl;
//5.求长度,清空,判空,更新长度
cout << "v的长度为:" << v.size() << endl;
v.clear();//清空
cout << "v的长度为:" << v.size() << endl;
if (v.empty())
{
cout << "v为空" << endl;
}
v.resize(10);//更新v长度变为10,新元素均为默认值0(旧元素不变)
for (int& coll : v)
{
cout << coll << " ";
}
cout << endl;
v.resize(12, 2);//更新v长度变为12,初始化新元素为2(旧元素不变)
for (int& coll : v)
{
cout << coll << " ";
}
cout << endl;
v.resize(3);//更新v长度变为3,删除多余的值
for (int& coll : v)
{
cout << coll << " ";
}
}
11.vector容器的嵌套使用:
二维vector<vector<类型>v> 的每个元素都是vector<类型>;
//二维vector的综合应用
void test02()
{
//1.创建了一个嵌套vector容器(可理解为二维数组)
vector<vector<int>>v;
vector<vector<int>> ma;// 构造二维数组,行列为0,没有初值
vector<vector<int>> mat(100, vector<int>()); // 100行,不指定列数,没有初值
vector<vector<int>> mat2(10, vector<int>(10, 30)); // 10行,10列,初值为30
//创建小容器
vector<int>v1;
vector<int>v2;
vector<int>v3;
vector<int>v4;
//小容器中添加数据
for (int i = 0; i < 4; i++)
{
v1.push_back(i + 1);
v2.push_back(i + 1);
v3.push_back(i + 1);
v4.push_back(i + 1);
}
//添加小容器到大容器中
v.push_back(v1);
v.push_back(v2);
v.push_back(v3);
v.push_back(v4);
//2.二维容器的遍历
//这里的*it是一个 vector<int>容器
for (vector<vector<int>>::iterator it = v.begin(); it != v.end(); it++)
{
for (vector<int>::iterator vit = (*it).begin(); vit != (*it).end(); vit++)
{
cout << *vit << " ";
}
cout << endl;
}
cout << endl;
//auto进行简化
for (auto it = v.begin(); it != v.end(); it++)
{
for (auto vit = (*it).begin(); vit != (*it).end(); vit++)
{
cout << *vit << " ";
}
cout << endl;
}
cout << endl;
//基于范围for循环
for (vector<int> it : v)
{
for (int vit : it)
{
cout << vit << " ";
}
cout << endl;
}
cout << endl;
//auto进行简化
for (auto it : v)
{
for (auto vit : it)
{
cout << vit << " ";
}
cout << endl;
}
cout << endl;
//也可以加引用
for (auto& it : v)
{
for (auto& vit : it)
{
cout << vit << " ";
}
cout << endl;
}
// 3.求二维数组的长度
cout << mat2.size() << endl;//二维数组中,.size()只返回行数,这里输出10
//求二维数组长度
int total_elements = 0;
for (vector<int> row : mat2)
{
total_elements += row.size();//求每行的长度,并累加
}
cout << total_elements << endl; // 这将输出 100
}
12.总结与杂谈
12.1使用for_each();
进行遍历的相关剖析
std::for_each()
是 C++ 中的一个函数模板,用于遍历容器中的元素并对每个元素执行指定的操作。 它通常与 std::vector 等容器结合使用。下面我将详细解释其原理和使用方式。
12.1.1std::for_each() 的工作原理
std::for_each() 的基本作用是将某个操作应用到范围 [first, last) 内的每个元素。 它的原型定义如下:
template <class InputIterator, class Function>
Function for_each(InputIterator first, InputIterator last, Function fn);
- first:表示容器的起始迭代器(通常是 begin())。
- last:表示容器的终止迭代器(通常是 end())。
- fn:这是一个函数对象或函数指针,它对范围内的每个元素执行某个操作。
for_each() 依次从起始迭代器 first 开始,直到终止迭代器 last 之前,将 fn 这个函数应用到每个元素上。 这个函数本身不会改变容器的元素(除非 fn 函数修改了传递给它的元素的值)。
12.1.2std::for_each() 的基本用法
我们通过一个简单的例子来说明 for_each() 的使用:
#include <iostream>
#include <vector>
#include <algorithm> // 包含for_each
// 定义一个打印函数
void print(int x)
{
std::cout << x << " ";
}
int main()
{
std::vector<int> v = {1, 2, 3, 4, 5};
// 使用for_each遍历vector并打印每个元素
std::for_each(v.begin(), v.end(), print);
return 0;
}
解释:
-
v.begin() 和 v.end():begin() 返回向量中第一个元素的迭代器,end() 返回向量最后一个元素之后的位置。std::for_each() 遍历 [v.begin(), v.end()) 范围内的所有元素。
-
print 函数:这是传递给 for_each() 的函数对象,它在遍历过程中对每个元素调用并将其打印出来。
运行结果:for_each() 函数遍历 v 中的每个元素,依次打印出 1 2 3 4 5。
12.2使用swap();
收缩内存空间的相关应用
std::vector
容器会动态分配内存来存储元素,并通常分配比实际需要更多的内存以便减少频繁的重新分配。 这意味着即使你删除了一些元素,vector 实际占用的内存空间可能不会立刻减少。为了手动收缩 vector 的内存,可以使用 swap() 函数来达到这个目的。
12.2.1. std::vector 内存管理
std::vector 的底层是一个动态数组,它根据需要自动增长。当 vector 增加元素时,如果现有容量不足,它会分配一个更大的内存块并将旧数据复制到新的内存中;但当你删除元素时,vector 的容量不会自动缩小,它只会减少逻辑上的元素数量(即 size 减少),但内存空间(capacity)保持不变。
这会导致如下情况:
std::vector<int> vec = {1, 2, 3, 4, 5};
vec.pop_back(); // 删除最后一个元素,vec的size为4,但capacity仍为5
即便你删除了元素,vector 仍然会保留多余的内存,这在某些情况下可能是低效的。因此,如果你希望减少 vector 的实际占用内存,可以使用以下技术。
12.2.2 使用 swap() 函数来收缩内存
你可以通过使用 swap() 函数和 一个临时空 vector 来强制 vector 释放多余的内存空间。 这种技术的原理是利用 C++ 中 vector 的移动语义。当 vector 被 swap() 交换时,它的内存和元素被转移到另一个对象,原 vector 的容量会被设置为与其元素数量相匹配的最小值。
核心语句为:std::vector<int>(vec).swap(vec);
std::vector<int>(vec).swap(vec);
是一种常见的技术,用来通过临时对象和 swap() 函数对 std::vector 进行内存收缩操作。 为了更好地理解这一语句的原理,让我们逐步分解它的执行过程并分析其工作机制。
1. 拆解语句:std::vector(vec).swap(vec);
这条语句分为两部分:
std::vector<int>(vec)
:创建一个新的临时 vector,并使用已有的 vec 初始化它。.swap(vec)
:使用 swap() 函数将这个临时 vector 和原来的 vec 进行交换。
逐步分析其含义:- std::vector(vec):这个部分使用了 vector 的拷贝构造函数。它创建了一个新的临时 vector,该临时对象的内容与 vec 一致,但是它的容量将被缩减到与 vec.size() 相同。
- .swap(vec):swap() 函数交换两个 vector 的内部数据结构,**包括指针、容量、大小等。**交换之后,原 vec 现在变成了临时 vector 的状态,临时 vector(内存已收缩)成为新的 vec。原 vec 的冗余内存得到了释放。
2. 工作原理解析
我们通过一个简单的例子演示这条语句的实际执行流程:
std::vector<int> vec = {1, 2, 3, 4, 5}; // 初始状态,容量为5
vec.pop_back(); // 删除一个元素,vec的size为4,capacity仍为5
这时,vec 的容量是 5,但只有 4 个元素(size 为 4,capacity 仍为 5)。接下来,我们执行 std::vector(vec).swap(vec);。
1. 拷贝构造临时 vector:std::vector(vec)
这一部分会创建一个新的临时 vector。 具体步骤如下:
拷贝构造函数:通过调用 std::vector(vec),我们构造了一个新的 vector,它的内容与 vec 相同,但是临时 vector 的容量(capacity)是根据当前 vec 的大小(size)来分配的。
例如,vec.size() 是 4,因此临时 vector 的 capacity 也会是 4(这是动态内存分配的特性,临时 vector 只分配与 size 相匹配的最小容量)。
2. 交换两个 vector:.swap(vec)
swap() 函数的作用是 交换两个 vector 的内部数据成员(指针、大小、容量等),而不是实际交换元素的内容。
在这个步骤中,swap() 会做以下事情:
-
交换指针:vec 和临时 vector 的指针会互相交换,这意味着:
-
临时 vector(容量为 4)将取代 vec。
-
原始的 vec(容量为 5)的内部指针现在指向临时 vector 的数据(即容量为 4 的数据块)。
-
交换容量与大小:size 和 capacity 等信息也会互换,
因此:
现在 vec 的容量被缩小到了 4(与 size 一致),而不再是原先的 5。
临时 vector 被替换为原 vec,但由于它是一个临时对象,不会再被使用,并且会立即被销毁。
3. 释放临时 vector
一旦 swap() 操作完成,临时 vector 就会被销毁。 当这个临时对象析构时,原 vec(即具有更大容量的 vector)的内存会被释放。因此,原来多余的内存空间就得到了有效的释放。
- 为什么 swap() 能释放内存?
swap() 的核心原理是指针交换,而不是逐个元素的拷贝或移动。它交换的是 vector 内部的指针、size 和 capacity,而不是 vector 中的具体数据。
当 swap() 发生时,vec 和临时 vector 的底层数据指针被交换了。原 vec 的冗余内存随临时对象的销毁而释放。
具体流程如下:
原始 vec(容量 5):
size = 4,capacity = 5,指向 5 个元素的内存空间。
临时 vector(容量 4):
size = 4,capacity = 4,指向刚好 4 个元素的内存空间。
执行 swap() 后:
原始 vec 指向的是 4 个元素的内存空间,并且 capacity 被缩小为 4。
临时 vector 持有原来 vec 的内存空间,但马上会被销毁,释放它所占的内存。
3. 总结 std::vector(vec).swap(vec) 的原理
- 创建临时 vector:创建一个新的临时 vector,它仅分配了与 vec.size() 相同的内存(即刚好能存储当前的元素),而不保留多余的空间。
- swap() 交换内部结构:使用 swap() 交换原 vector 和临时 vector 的内部结构(指针、大小、容量等),以达到调整内存的目的。
- 释放冗余内存:临时 vector 在 swap() 后被销毁,从而释放原始 vector 占用的多余内存。
这种方法通过临时对象和 swap() 技术来手动收缩 vector 的容量,在确保数据不丢失的情况下,释放多余的内存空间,非常高效。
13.整体代码一览:
//单端数组vector
#include<iostream>
#include<vector>//包含vector数组的头文件
#include<algorithm>//包含stl基本算法的头文件
using namespace std;
//1.vector构造函数:创建vector容器
//vector<T> v; //采用模板实现类实现,默认构造函数
//vector(v.begin(), v.end()); //将v[begin(), end())区间中的元素拷贝给本身。
//vector(n, elem); // 构造函数将n个elem拷贝给本身。
//vector(const vector& vec); //拷贝构造函数
//2.vector赋值操作:给vector容器进行赋值
//vector& operator=(const vector& vec); //重载等号操作符
//assign(beg, end); //将[beg, end)区间中的数据拷贝赋值给本身。
//assign(n, elem); //将n个elem拷贝赋值给本身
//3.vector容量和大小:对vector容器的容量和大小操作
//empty(); //判断容器是否为空
//capacity(); //容器的容量(注意:capacity永远大于等于size)
//size(); //返回容器中元素的个数
//resize(int num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。
// //如果容器变短,则末尾超出容器长度的元素被删除。
//
//resize(int num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。
// //如果容器变短,则末尾超出容器长度的元素被删
//4.vector插入和删除:对vector容器进行插入、删除操作
//push_back(ele); // 尾部插入元素ele
//pop_back(); // 删除最后一个元素
//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(); //删除容器中所有元素
//5.vector数据存取: 对vector中的数据的存取操作
//at(int idx); //返回索引idx所指的数据
//operator[]; //返回索引idx所指的数据
//front(); //返回容器中第一个数据元素
//back(); //返回容器中最后一个数据元素
//6.vector互换容器:实现两个容器内元素进行互换
//swap(vec); // 将vec与本身的元素互换
//7.vector预留空间:减少vector在动态扩展容量时的扩展次数
//reserve(int len); //容器预留len个元素长度,预留位置不初始化,元素不可访问。
void myprint(int val)
{
cout << val << " ";
}
//遍历默认排序的vector容器
void print(vector<int>& v)
{
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
//2.vector赋值操作:给vector容器进行赋值
void test2()
{
vector<int>v1;
for (int i = 0; i < 6; i++)
{
v1.push_back(i + 1);
}
print(v1);
//赋值:
//重载等号运算符
vector<int>v2;
v2 = v1;
print(v2);
//assign:注意左开右闭
vector<int>v3;
v3.assign(v1.begin(), v1.end()-1);//这里赋值了v1的所有元素
print(v3);
//assign:n个elem赋值
vector<int>v4;
v4.assign(10, 100);//向v4插入10个100
print(v4);
}
//3.vector容量和大小:对vector容器的容量和大小操作
void test3()
{
vector<int> v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
print(v1);
//判断v1是否为空
if (v1.empty())
{
cout << "v1为空" << endl;
}
else
{
cout << "v1不为空" << endl;
cout << "v1的容量 = " << v1.capacity() << endl;//capacity永远大于等于size
cout << "v1的大小 = " << v1.size() << endl;
}
//resize 重新指定大小 ,若指定的更大,默认用0填充新位置,可以利用重载版本替换默认填充
v1.resize(15, 10);
print(v1);
//resize 重新指定大小 ,若指定的更小,超出部分元素被删除
v1.resize(5);
print(v1);
}
//4.vector插入和删除:对vector容器进行插入、删除操作
void test4()
{
vector<int> v1;
//尾插
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
v1.push_back(40);
v1.push_back(50);
print(v1);
//尾删
v1.pop_back();
print(v1);
//插入:第一个参数是迭代器
v1.insert(v1.begin(), 100);//头部插入100
print(v1);
//从传入的迭代器开始,插入2个1000
v1.insert(v1.begin(), 2, 1000);//头部插入两个1000
print(v1);
//删除:参数也是迭代器
v1.erase(v1.begin());//删除第一个元素
print(v1);
//清空
//v1.erase(v1.begin(), v1.end());等价于下面语句
v1.clear();
print(v1);
}
//5.vector数据存取: 对vector中的数据的存取操作
void test5()
{
//数据的访问
vector<int>v1;
for (int i = 0; i < 5; i++)
{
v1.push_back(i + 1);
}
//获取方式1:中括号的方式[]
for (int i = 0; i < v1.size(); i++)
{
cout << v1[i] << " ";
}
cout << endl;
//获取方式2:利用成员函数at来访问
for (int i = 0; i < v1.size(); i++)
{
cout << v1.at(i) << " ";
}
cout << endl;
//获取vector容器的首尾元素
cout << "第一个元素为:"<<v1.front() << endl;
cout << "最后一个元素为:" << v1.back() << endl;
}
//6.vector互换容器:实现两个容器内元素进行互换
void test6()
{
//构建两个内容不同的vector容器
vector<int>v1;
for (int i = 0; i < 6; i++)
{
v1.push_back(i * 2);
}
vector<int>v2;
for (int i = 0; i < 4; i++)
{
v2.push_back(i + 2);
}
cout << "交换前:" << endl;
cout << "v1:";
print(v1);
cout<<endl<<"v2:";
print(v2);
//进行交换操作
v1.swap(v2);
cout << endl;
cout << "交换后:" << endl;
cout << "v1:";
print(v1);
cout << endl << "v2:";
print(v2);
//核心与实际应用:巧用swap()可以收缩内存空间
vector<int>v3;
for (int i = 0; i < 10000; i++)
{
v3.push_back(i);//这里尾插了10000个元素,数据量非常大
}
//注意这里编译器自动分配容量,它一定大于等于size
cout << "v3的容量是:" << v3.capacity() << endl;
cout << "v3的大小是:" << v3.size() << endl;
cout << endl;
//当我们重新指定v3的大小时(这里是收缩),实际上v3的容量不会收缩,只是将size缩小当前指定的大小
v3.resize(3);
cout << "v3的容量是:" << v3.capacity() << endl;
cout << "v3的大小是:" << v3.size() << endl;
cout << endl;
//巧用swap()收缩内存空间
vector<int>(v3).swap(v3);
//vector<int>(v3):这里创建了一个匿名对象,匿名对象和v3指向同一块内存空间,所以v3为空,容量为0
cout << "v3的容量是:" << v3.capacity() << endl;
cout << "v3的大小是:" << v3.size() << endl;
}
//7.vector预留空间:减少vector在动态扩展容量时的扩展次数
//注意与resize不同,reserve(加长时)预留的新位置不会初始化,元素不可访问
void test7()
{
//统计开辟次数:
vector<int> v1;
int num = 0;
int* p = NULL;
for (int i = 0; i < 10000; i++)
{
v1.push_back(i);
//如果p不指向v1的首地址,说明发生了扩容操作,计数器加1
if (p != &v1[0])
{
p = &v1[0];
num++;
}
}
//通过以上方法我们就获得了插入10000个数据之后,扩容的总次数。
cout << "v1一共开辟了多少次:" << num << endl;
//通过结果我们就了解了插入10000个数据一定会扩容好多次
//为了减少扩容的次数,我们就可以尝试使用reserve();
vector<int> v2;
//直接通过reserve()来为vector预留10000个数据量的空间
//这样,最终只会扩容1次,就将所有数据插入到v2中了
v2.reserve(10000);
int num1 = 0;
int* p1 = NULL;
for (int i = 0; i < 10000; i++)
{
v2.push_back(i);
//如果p不指向v1的首地址,说明发生了扩容操作,计数器加1
if (p1 != &v1[0])
{
p1 = &v1[0];
num1++;
}
}
cout << "v2一共开辟了多少次:" << num1 << endl;
}
//1.一维vector的综合应用
void test01()
{
//1.创建了一个vector容器(可理解为一维数组)
vector<int>v;
vector<int> x; // 构造int数组,长度为0,没有初值
vector<int> x1(100); // 构造初始长100的int数组,初值默认为0
vector<int> x2(200, 5); // 构造初始长200的int数组,初值为5
vector<int>mm = { 1,2,3,4 }; //构建并初始化一维数组:
//2.向容器尾部插入一些数据
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
//3.删除尾部的一些数据
v.pop_back();
v.pop_back();
//4一维vector的遍历
//4.1通过迭代器访问容器中的数据
//暂时把迭代器想象成指针
vector<int>::iterator itbegin = v.begin();//起始迭代器,指向容器中第一个元素
vector<int>::iterator itend = v.end();//结束迭代器,指向容器中最后一个元素的下一个位置
//4.1.1while遍历:(不推荐使用)
while (itbegin != itend)
{
cout << *itbegin << " ";
itbegin++;//迭代器自增,向后走一个元素的位置
}
cout << endl;
//4.1.2.for遍历:(比较常用)
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
//4.1.3.stl的遍历算法(回调函数遍历方法,暂时不懂)
for_each(v.begin(), v.end(), myprint);
cout << endl;
//4.1.4.用auto简化迭代器的使用
for (auto it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
//4.3.基于范围的for循环
//4.3.1
for (int it : v)
//for(int & it:v) 加引用
//for(const int &it:v) 加只读操作
{
cout << it << " ";
}
cout << endl;
//4.3.2.
//for (auto it:v)
//for(auto & it:v) 加引用
for (const auto& it : v) //加只读操作
{
cout << it << " ";
}
cout << endl;
//5.求长度,清空,判空,更新长度
cout << "v的长度为:" << v.size() << endl;
v.clear();//清空
cout << "v的长度为:" << v.size() << endl;
if (v.empty())
{
cout << "v为空" << endl;
}
v.resize(10);//更新v长度变为10,新元素均为默认值0(旧元素不变)
for (int& coll : v)
{
cout << coll << " ";
}
cout << endl;
v.resize(12, 2);//更新v长度变为12,初始化新元素为2(旧元素不变)
for (int& coll : v)
{
cout << coll << " ";
}
cout << endl;
v.resize(3);//更新v长度变为3,删除多余的值
for (int& coll : v)
{
cout << coll << " ";
}
}
//二维vector的综合应用
void test02()
{
//1.创建了一个嵌套vector容器(可理解为二维数组)
vector<vector<int>>v;
vector<vector<int>> ma;// 构造二维数组,行列为0,没有初值
vector<vector<int>> mat(100, vector<int>()); // 100行,不指定列数,没有初值
vector<vector<int>> mat2(10, vector<int>(10, 30)); // 10行,10列,初值为30
//创建小容器
vector<int>v1;
vector<int>v2;
vector<int>v3;
vector<int>v4;
//小容器中添加数据
for (int i = 0; i < 4; i++)
{
v1.push_back(i + 1);
v2.push_back(i + 1);
v3.push_back(i + 1);
v4.push_back(i + 1);
}
//添加小容器到大容器中
v.push_back(v1);
v.push_back(v2);
v.push_back(v3);
v.push_back(v4);
//2.二维容器的遍历
//这里的*it是一个 vector<int>容器
for (vector<vector<int>>::iterator it = v.begin(); it != v.end(); it++)
{
for (vector<int>::iterator vit = (*it).begin(); vit != (*it).end(); vit++)
{
cout << *vit << " ";
}
cout << endl;
}
cout << endl;
//auto进行简化
for (auto it = v.begin(); it != v.end(); it++)
{
for (auto vit = (*it).begin(); vit != (*it).end(); vit++)
{
cout << *vit << " ";
}
cout << endl;
}
cout << endl;
//基于范围for循环
for (vector<int> it : v)
{
for (int vit : it)
{
cout << vit << " ";
}
cout << endl;
}
cout << endl;
//auto进行简化
for (auto it : v)
{
for (auto vit : it)
{
cout << vit << " ";
}
cout << endl;
}
cout << endl;
//也可以加引用
for (auto& it : v)
{
for (auto& vit : it)
{
cout << vit << " ";
}
cout << endl;
}
// 3.求二维数组的长度
cout << mat2.size() << endl;//二维数组中,.size()只返回行数,这里输出10
//求二维数组长度
int total_elements = 0;
for (vector<int> row : mat2)
{
total_elements += row.size();//求每行的长度,并累加
}
cout << total_elements << endl; // 这将输出 100
}
int main()
{
test01();
test02();
test2();
test3();
test4();
test5();
test6();
test7();
return 0;
}