当前位置: 首页 > article >正文

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

http://www.kler.cn/news/316733.html

相关文章:

  • Java综合练习题—TCP通信协议+xml操作+序列化反序列化综合题
  • 如何使用ant design vue的a-select下拉框,实现既能输入内容,也可以下拉选择的效果,apiselect同样适用
  • 浅谈spring 后端项目配置logback日志
  • 无人机之4G模块的主要功能和优势
  • 华为HarmonyOS地图服务 1 -- 如何实现地图呈现?
  • Flask高级特性实战
  • 字符串反转
  • 【kafka-04】kafka线上问题以及高效原理
  • HarmonyOS鸿蒙开发实战(5.0)网格元素拖动交换案例实践
  • Go语言并发编程之sync包详解
  • 前后端分离,使用MOCK进行数据模拟开发,让前端攻城师独立于后端进行开发
  • 【Verilog学习日常】—牛客网刷题—Verilog快速入门—VL21
  • Kotlin高阶函数func
  • 计算机毕业设计 美妆神域网站的设计与实现 Java实战项目 附源码+文档+视频讲解
  • 一对一视频通话软件Call-Me
  • 某采招网爬虫数据采集逆向
  • 医学数据分析实训 项目四 回归分析--预测帕金森病病情的严重程度
  • I.MX6U裸机-C语言版LED灯实验
  • ld-linux-x86-64.so.2
  • git 操作远程别名
  • tcpdump使用方法
  • 24. Revit API: 几何对象(五)- (Sur)Face
  • [Linux]Vi和Vim编辑器
  • 修改Git配置信息:用户名
  • linux第三课(linux中安装nginx与redis及SpringBoot集成redis)
  • 颍川陈氏——平民崛起的典范
  • 【AcWing】基础算法
  • Django 数据库配置以及字段设置详解
  • 移情别恋c++ ദ്ദി˶ー̀֊ー́ ) ——14.AVL树
  • C++(学习)2024.9.20