【STL】vector 基础,应用与操作

news2025/2/23 7:00:18

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2146464.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MindShare PCIE 3.0 笔记-第一二章

MindShare 官网&#xff0c;地址如下: MindShare Chapter 1&#xff1a;PCIE 背景介绍 - PCI 总线模型 1. 以 PCI 总线作为外设总线的 SOC 芯片架构 下图展示了一个以 PCI 总线作为外设总线的 SOC 芯片架构(PCI 总线类似 AXI 下的 AHB&#xff1f;)&#xff1a; 由上图可知…

Django Auth组件

文章目录 前言一、使用场景二、使用步骤1.验证用户( authenticate() 方法)2.注册用户3.退出登陆4.装饰器 前言 Django 的用户认证组件基于以下几个核心概念&#xff1a; 1.用户认证&#xff1a;处理用户的登录、注销和密码管理&#xff0c;提供了一个User模型和相关的视图、表…

技术美术一百问(02)

问题 前向渲染和延迟渲染的流程 前向渲染和延迟渲染的区别 G-Buffer是什么 前向渲染和延迟渲染各自擅长的方向总结 GPU pipeline是怎么样的 Tessellation的三个阶段 什么是图形渲染API? 常见的图形渲染API有哪些&#xff1f; 答案 1.前向渲染和延迟渲染的流程 【例图…

图神经网络池化方法

图神经网络池化方法 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 图神经网络池化方法前言一、扁平图池化二、分层图池化1.节点聚类池化2.节点丢弃池化 参考文献 前言 图池化操作根据其池化策略的差异&#xff…

软考(中级-软件设计师)(0919)

软考 一、软件设计师-历年考试考点分布情况-上午-计算机与软件工程知识 知识点分数说明比例软件工程基础知识11开发模型、设计原则、测试方法、质量特性、CMM、Pert图、风险管理14.67%面向对象12面向对象基本概念、面向对象分析与设计、UML、常见算法16.00%数据结构与算法10…

代码随想录算法day37 | 动态规划算法part10 |

今天开始正式子序列系列&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 300.最长递增子序列 本题是比较简单的&#xff0c;感受感受一下子序列题目的思路。 力扣题目链接(opens new window) 给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长…

读mamba有感,自然而然产生的问题及答案。

原文链接&#xff1a;https://arxiv.org/abs/2312.00752 Q&#xff1a;为什么说Mamba可以比肩甚至超越transformer&#xff1f;各自有什么优劣&#xff1f; A&#xff1a;Transformer在处理长序列时&#xff0c;存在着计算效率低下的问题&#xff0c;无法对有限窗口之外的任何…

查询中的行选择

用WHERE子句限制从查询返回的行。一个WHERE子句包含一个必须满足的条件&#xff0c;WHERE子句紧跟着FROM子句。如果条件是true&#xff0c;返回满足条件的行。 在语法中&#xff1a; WHERE 限制查询满足条件的行 condition 由列名、表达式、常数和比较操作组成…

bootstrap application nacos环境配置失效

tmd 环境配置 是yaml &#xff0c;yml 后缀配置不生效 (不&#xff0c;看你取得文件名是什么) 如果 file-extension 配置的是yaml 就读取不到 yml 中的配置 2 . 如果还不行&#xff0c;、nacos 配置只能卸载bootstrap.yml 中&#xff0c;application.yml 不生效 bootstrap.yml…

c/c++语言中extern的用法(VS编译)

c/c语言中extern的用法 前言&#xff1a;1. 声明外部变量2. 声明外部函数3. 在头文件中使用注意事项 效果展示&#xff1a; 前言&#xff1a; extern 关键字不仅在 C 语言中使用&#xff0c;在 C 语言中也同样适用。它主要用于声明一个变量或者函数是在别的文件或翻译单元中定…

怎么操作使http变成https访问?

获取SSL证书 选择证书颁发机构&#xff1a;可以选择受信任的免费或付费证书颁发机构&#xff08;CA&#xff09;如JoySSL 申请和验证域名&#xff1a;注册并填写注册码230920&#xff0c;验证域名所有权。下载SSL证书文件到本地电脑. JoySSL品牌证书 注册享大额优惠JoySSL是网…

Android开发高频面试题之——Android篇

Android开发高频面试题之——Android篇 Android开发高频面试题之——Java基础篇 Android开发高频面试题之——Kotlin基础篇 Android开发高频面试题之——Android基础篇 1. Activity启动模式 standard 标准模式,每次都是新建Activity实例。singleTop 栈顶复用。如果要启动的A…

车市状态喜人,国内海外“两开花”

文/王俣祺 导语&#xff1a;随着中秋假期告一段落&#xff0c;“金九”也正式过半&#xff0c;整体上这个销售旺季的数据可以说十分喜人&#xff0c;各家车企不是发布新车、改款车就是推出了一系列购车权益&#xff0c;充分刺激了消费者的购车热情。再加上政府政策的鼎力支持&a…

Unity 使用Editor工具查找 Prefab 中的指定脚本

在 Unity 项目中&#xff0c;随着项目规模的扩大和 Prefab 数量的增加&#xff0c;管理和定位 Prefab 中的脚本变得更加复杂。为了提高开发效率&#xff0c;所以需要编写一个自定义的 Unity Editor 工具&#xff0c;帮助查找某个 Prefab 中是否使用了指定的脚本。本文将介绍如何…

LIN总线CAPL函数——干扰LIN帧响应段(linInvertRespBit )

&#x1f345; 我是蚂蚁小兵&#xff0c;专注于车载诊断领域&#xff0c;尤其擅长于对CANoe工具的使用&#x1f345; 寻找组织 &#xff0c;答疑解惑&#xff0c;摸鱼聊天&#xff0c;博客源码&#xff0c;点击加入&#x1f449;【相亲相爱一家人】&#x1f345; 玩转CANoe&…

目标检测:滑块验证

最近在做一些爬虫相关的任务&#xff0c;有时候在登录时候需要去做滑块验证&#xff0c;刚好自己是做AI这一块得&#xff0c;就想着使用目标检测去做检测&#xff0c;然后绕过滑块。

AI 时代,大模型产业落地的八大思考

引言 在人工智能领域&#xff0c;大模型技术正逐渐成为推动行业进步的关键力量。随着技术的发展&#xff0c;大模型不仅在学术界引起了广泛的关注&#xff0c;也在产业界展现出巨大的应用潜力。然而&#xff0c;如何将这些强大的模型有效地应用到实际产业中&#xff0c;仍然是…

什么软件可以远程控制电脑?好用的电脑远程控制软件有哪些?这6款可以帮到你!

在如今的数字化办公环境中&#xff0c;远程控制电脑已成为解决问题、协作工作的必备技能。 无论是技术支持、远程办公&#xff0c;还是简单的文件传输&#xff0c;远程控制软件都能让我们随时随地连接其他电脑&#xff0c;省时省力。 那么&#xff0c;有哪些好用的远程控制软…

大数据和代理:揭示它们之间的微妙联系

大数据&#xff0c;顾名思义&#xff0c;是指使用传统数据处理应用程序无法有效处理的极其庞大而复杂的数据集。这些数据集的特点是数量庞大、速度快、种类繁多&#xff0c;有可能提供有价值的见解并支持各个行业的决策过程。 这些数据可能来自各种来源&#xff0c;例如社交媒体…

一文速通calcite结合flink理解SQL从文本变成执行计划详细过程

文章目录 你可以学到啥测试代码背景知识SQL转变流程图问题 你可以学到啥 SQL如何一步步变成执行计划的有哪些优化器&#xff0c;哪些优化规则calcite 和flink 如何结合的 测试代码 EnvironmentSettings settings EnvironmentSettings.inBatchMode(); TableEnvironment tabl…