一、vector 简介

在 C++ 中,std::vector 是标准库提供的一个容器类,用于存储动态大小的元素序列(即"动态数组")。它提供了一系列成员函数和操作符,使得元素的访问、插入、删除等操作变得方便和高效。

- vector与数组的区别

  • 扩展:数组的大小在创建时就确定了,无法动态改变,而 std::vector 空间可以动态扩展(不是在原空间后拼接新空间,而是找更大的内存空间,然后将原数据拷贝到新空间,并释放原空间)
  • 内存管理:数组在栈上或静态存储区中分配内存,大小是在编译时确定的。而 std::vector 使用动态内存分配,它在堆上分配内存,并自动处理内存的释放。
  • 访问和操作:数组使用下标操作符 [] 访问元素,而 std::vector 也支持下标操作符,还提供了一些额外的成员函数来方便地操作元素,例如 push_back()pop_back()insert()erase() 等。
  • 大小管理:数组的大小是固定的,无法改变,而 std::vector 可以动态增长或缩小,可以使用 resize() 函数调整大小。
  • 内存开销:由于 std::vector 使用动态内存分配,它可能会引入一些额外的开销,例如内存分配和释放的开销。而数组在编译时就分配了固定大小的内存,因此没有这些开销。
  • 标准库支持std::vector 是 C++ 标准库提供的容器,提供了许多方便的函数和算法来操作和管理元素。而数组是 C++ 的基本数据结构之一,没有提供类似的标准库支持。

总结:

  1. 数组适用于大小固定且事先知道元素数量的情况下使用,尤其是数据集较小或需要静态分配内存的场景。
  2. vector 适用于大小可变的情况,特别是需要动态增长或缩小的场景,并且具有更多的功能和灵活性。

二、vector 构造函数

构造函数原型解释
1vector<T> v默认构造函数, 采用模板类实现
2vector(v.begin(), v.end())将v[begin, end)区间中的元素拷贝给本身
3vector(n, Element)构造函数将n个Element(元素)拷贝给本身
4vector(const vector &v)拷贝构造函数

示例:

#include <iostream>
#include <vector>     //必须包含该头文件
using namespace std;

void printVec(vector<int> &v)
{
	for (vector<int>::iterator At = v.begin(); At != v.end(); At++)
	{
		cout << *At << " ";
	}
	cout << endl;
}
void printVec(vector<double> &v)
{
	for (vector<double>::iterator At = v.begin(); At != v.end(); At++)
	{
		cout << *At << " ";
	}
	cout << endl;
}

void test01()
{
	vector<int> v1;
	v1.push_back(10);  //添加元素
	v1.push_back(20);
	printVec(v1);

	vector<int> v2(v1.begin(), v1.end());
	printVec(v2);

	vector<double> v3(5, 6.32);
	printVec(v3);

	vector<double> v4(v3);
	printVec(v4);
}

int main()
{
	test01();
	system("pause");
	return 0;
}
//result
10 20
10 20
6.32 6.32 6.32 6.32 6.32
6.32 6.32 6.32 6.32 6.32

注意:

std::vector 作为函数的参数或者返回值时,不能缺少其中的“&”。

三、vector 赋值

函数原型: = 、assign解释
1vector& operator=(const vector &vec)重载=操作符
2assign(string str)将字符串str赋值给本身
3assign(begin, end)将[begin, end)区间中的数据拷贝赋值给本身
4assign(n, Element)将n个Element拷贝赋值给本身

示例:

#include <iostream>
#include <vector>     //必须包含该头文件
using namespace std;

void printVec(vector<int> &v)
{
	for (vector<int>::iterator At = v.begin(); At != v.end(); At++)
	{
		cout << *At << " ";
	}
	cout << endl;
}

void test01()
{
	vector<int> v1;
	v1.push_back(10);  //添加元素
	v1.push_back(20);
	printVec(v1);

	vector<int> v2 = v1;
	printVec(v2);

	vector<int> v3;
	v3.assign(v1.begin(), v1.end());
	printVec(v3);

	vector<int> v4;
	v4.assign(6, 1);
	printVec(v4);
}

int main()
{
	test01();
	system("pause");
	return 0;
}
//result
10 20
10 20
10 20
1 1 1 1 1 1

四、vector 容量与长度

函数原型:empty、capacity、size、resize解释
1empty()判断容器是否为空
2capacity()容器的容量
3size()返回容器中元素的个数
4resize(int num)重新指定容器的长度为num。若容器变长,则以默认值填充新位置; 如果容器变短,则末尾超出容器长度的元素被删除
5resize(int num, Element)重新指定容器的长度为num。若容器变长,则以Element值填充新位置; 如果容器变短,则末尾超出容器长度的元素被删除

示例:

#include <iostream>
#include <vector>     //必须包含该头文件
using namespace std;

void printVec(vector<int> &v)
{
	for (vector<int>::iterator At = v.begin(); At != v.end(); At++)
	{
		cout << *At << " ";
	}
	cout << endl;
}

void test01()
{
	vector<int> v1;
    if(v1.empty())     //判断是否为空
    {
        cout << "当前v1为空!"<< endl;
    }
    
	v1.push_back(10);  //添加元素
	v1.push_back(20);
    v1.push_back(30);
    
    if(! v1.empty())
    {
        cout << "v1中元素个数:"<< v1.size() << endl;
        cout << "v1的容量:"<< v1.capacity() << endl;
        printVec(v1);
    }

    v1.resize(5);
    printVec(v1);

    v1.resize(10,1);
    printVec(v1);
}

int main()
{
	test01();
	system("pause");
	return 0;
}
//result
当前v1为空!
v1中元素个数:3
v1的容量:3
10 20 30
10 20 30 0 0
10 20 30 0 0 1 1 1 1 1

五、vector 插入与删除

函数原型:push_back、pop_back、insert、erase、clear解释
1push_back(Element)尾部插入元素Element
2pop_back()删除最后一个元素
3insert(iterator p, Element)迭代器指向位置p插入元素Element
4insert(iterator p, int n, Element)迭代器指向位置p插入n个元素Element
5erase(iterator p)删除迭代器指向的元素
6erase(iterator start, iterator end)删除迭代器从start到end之间的元素
7clear()删除容器中所有元素

示例:

#include <iostream>
#include <vector>     //必须包含该头文件
using namespace std;

void printVec(vector<int> &v)
{
	for (vector<int>::iterator At = v.begin(); At != v.end(); At++)
	{
		cout << *At << " ";
	}
	cout << endl;
}

void test01()
{
	vector<int> v1;
	v1.push_back(1);  //尾部添加元素
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(3);
	printVec(v1);

	v1.pop_back();    //尾部删除元素
	printVec(v1);

	v1.insert(v1.begin(), 100);      //插入元素100
	printVec(v1);

	v1.insert(v1.begin(), 5, 100);   //插入5个元素100
	printVec(v1);

	v1.erase(v1.begin());    //删除元素
	printVec(v1);

	v1.clear();				 //清空容器
	printVec(v1);
}

int main()
{
	test01();
	system("pause");
	return 0;
}
//result
1 2 3 3
1 2 3
100 1 2 3
100 100 100 100 100 100 1 2 3
100 100 100 100 100 1 2 3

注意:

使用 erase() 函数删除元素后,原来的迭代器会失效,因此在删除元素后继续使用失效的迭代器是不安全的。如果需要在遍历 std::vector 的同时删除元素,应使用更为安全的方式,例如使用迭代器的后置递增运算符来避免迭代器失效,如下:

std::vector<int> vec = { 1, 2, 3, 4, 5 };
for (auto it = vec.begin(); it != vec.end(); /* 迭代器更新放在循环体内 */) 
{
	if (*it == 1) 
	{
		it = vec.erase(it);  // 删除满足条件的元素,并将迭代器指向下一个元素
	}
	else 
	{
		++it;  // 迭代器递增
	}
}

六、vector 数据获取

函数原型:at、operator[]、front()、back解释
1at(int idx)返回索引idx所指的数据
2operator[int idx]返回索引idx所指的数据
3front()返回容器中第一个数据元素
4back()返回容器中最后一个数据元素

示例:

#include <iostream>
#include <vector>     //必须包含该头文件
using namespace std;

void test01()
{
	vector<int> v1 = { 1, 2, 3, 4, 5, 6 };
	cout << "v1.at(0) = " << v1.at(0) << endl;
	cout << "v1[0] = " << v1[0] << endl;
	cout << "v1.front() = " << v1.front() << endl;
	cout << "v1.back() = " << v1.back() << endl;
}

int main()
{
	test01();
	system("pause");
	return 0;
}
//result
v1.at(0) = 1
v1[0] = 1
v1.front() = 1
v1.back() = 6

七、vector 互换

函数原型:swap解释
1swap(vec)将vec中元素与本身的元素互换

示例:

#include <iostream>
#include <vector>     //必须包含该头文件
using namespace std;

void printVec(vector<int> &v)
{
	for (vector<int>::iterator At = v.begin(); At != v.end(); At++)
	{
		cout << *At << " ";
	}
	cout << endl;
}

void test01()
{
	vector<int> v1 = { 1, 2, 3, 4, 5, 6 };
	vector<int> v2 = { 6, 5, 4, 3, 2, 1 };
   
    v1.swap(v2);   //互换v1与v2中的元素
    printVec(v1);
    printVec(v2);
}

int main()
{
	test01();
	system("pause");
	return 0;
}
//result
6 5 4 3 2 1
1 2 3 4 5 6

八、vector 预留空间

描述:减少vector在动态扩展容量时的扩展次数

函数原型:reserve解释
1reserve(int len)容器预留len个元素长度,预留位置不初始化,元素不可访问

示例:

#include <iostream>
#include <vector>     //必须包含该头文件
using namespace std;

void printVec(vector<int> &v)
{
	for (vector<int>::iterator At = v.begin(); At != v.end(); At++)
	{
		cout << *At << " ";
	}
	cout << endl;
}

void test01()
{
	vector<int> v1 = { 1, 2, 3, 4, 5, 6 };
	v1.reserve(100);

	printVec(v1);
	cout << "v1.size() = "  << v1.size() << endl;
	cout << "v1.capacity() = " << v1.capacity() << endl;
}

int main()
{
	test01();
	system("pause");
	return 0;
}
//result
1 2 3 4 5 6
v1.size() = 6
v1.capacity() = 100

注意:

在 C++ 中,std::vector 类提供了 reserve()resize() 两个函数,用于调整 std::vector 的容量和大小。它们的区别如下:

  1. reserve() 函数用于预留 std::vector 的容量,即为 std::vector 分配内存空间,但不会改变 std::vector 的大小。可以通过 reserve() 提前分配足够的内存空间,以减少插入元素时的内存重新分配次数,提高性能。调用 reserve() 后,std::vector 的容量将大于或等于指定的值,但实际大小仍然为 0。例如:
std::vector<int> vec;
vec.reserve(10);  // 预留容量为 10
  1. resize() 函数用于改变 std::vector 的大小,即调整 std::vector 中元素的个数。当指定的大小大于当前大小时,将在末尾插入新的元素;当指定的大小小于当前大小时,将删除末尾的元素。如果在扩大 std::vector 大小时,新添加的元素将使用默认构造函数进行初始化。例如:
std::vector<int> vec;
vec.resize(5);  // 将 vec 的大小调整为 5,新增的元素值为 0

需要注意的是,resize() 函数可能会导致元素的构造和析构操作,因此在调整大小时要谨慎考虑性能开销。

综上所述,reserve() 函数用于预留容量,而 resize() 函数用于调整大小。reserve() 不会改变 std::vector 的大小,而 resize() 会改变 std::vector 的大小,并可能触发元素的构造和析构操作。


如果这篇文章对你有所帮助,渴望获得你的一个点赞!

如果这篇文章对你有所帮助,渴望获得你的一个点赞!

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐