C++系列-STL容器之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个空间,值默认为0
	cout << "---------- 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赋值给arr3
	cout << "---------- 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增大,自动扩展capacity
	cout << "---------- 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);	// 在迭代器指示的位置插入666
	cout << "---------- v1.insert(v1.begin()+1,666) ----------" << endl;
	print_vector(v1);

	v1.insert(v1.begin(), 5, 666);	// 在迭代器指示的位置插入5个666
	cout << "---------- 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的值不一定是10000
	for (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(空间大小),系统会先预留一片空间,如果没超出,就不会开辟新的。

  • 8
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STL是指标准模板库(Standard Template Library),它是C++语言的一部分,提供了一系列的模板类和函数,用于支持通用的数据结构和算法。STL的目标是提供高效、可重用和可扩展的组件,以便开发人员能够更轻松地编写高质量的代码。STL包含了许多常见的数据结构,如vector、list、set、map等,以及各种算法,比如排序、查找、遍历等。通过使用STL开发人员可以更加高效地处理各种数据结构和算法的问题,提高代码的开发效率和质量。 在STL中,我们可以使用各种容器来存储和管理数据。例如,我们可以使用std::map来创建一个键值对的映射,其中每个键都有一个与之相关联的值。下面是一个示例代码,展示了如何创建和使用一个std::map对象: std::map<std::string, int> disMap() { std::map<std::string, int> tempMap{ {"C语言教程",10},{"STL教程",20} }; return tempMap; } std::map<std::string, int> newMap(disMap()); 在这个示例中,disMap()函数创建了一个临时的std::map对象,并初始化了其中的一些键值对。然后,使用移动构造函数将这个临时对象移动到了一个新的std::map对象newMap中。最终,我们可以通过newMap对象来访问和操作这些键值对。 综上所述,STLC++中的标准模板库,提供了一系列的模板类和函数,用于支持通用的数据结构和算法。STL的使用可以提高代码的开发效率和质量,并且通过各种容器和算法,可以方便地处理各种数据结构和算法的问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [C++ STL详解超全总结(快速入门STL)](https://blog.csdn.net/qq_50285142/article/details/114026148)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [【C++实验】阅读STL源码并分析](https://blog.csdn.net/qq_35760825/article/details/125311509)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值