【C++】标准库类型vector

news2024/9/27 7:23:54

🦄个人主页:修修修也

🎏所属专栏:C++

⚙️操作环境:Visual Studio 2022


目录

vector对象集合简介

vector对象集合常用接口(成员函数)

📌vector对象集合模板默认成员函数

🎏vector对象集合模板构造函数

🎏vector对象集合模板析构函数

🎏vector对象集合模板赋值运算符重载

📌vector对象集合的迭代遍历及元素访问操作

🎏operator[]运算符重载

🎏at访问对象集合某位置元素

🎏顺序迭代器begin+end

🎏反向迭代器rbegin+rend

🎏范围for

🎏data获取指向vector中第一个元素位置的指针

🎏sort排序

1.sort()排升序

2.sort()排降序

3.sort()利用反向迭代器排序

4.利用sort()函数给string排序

5.利用sort()函数给数组排序

📌vector对象集合模板的容量操作

🎏size()函数

🎏capacity()函数

🎏empty()函数

🎏resize()函数

🎏reserve()函数

📌vector对象集合模板的成员修改操作

🎏push_back()函数

🎏pop_back()函数

🎏insert()函数

🎏erase()函数

🎏find()函数及其应用

结语


vector对象集合简介

        标准库类型vector表示对象的集合,其中所有对象的类型都相同.集合中的每个对象都有一个与之对应的索引,索引用于访问对象.因为vector"容纳着"其他对象,所以它也常被称作容器(container).vector 是 C++ 标准模板库(STL)的一部分,提供了灵活的接口和高效的操作,它们都位于<vector>头文件中。

         我们先来看一下cplusplus.com - The C++ Resources Network网站对vector类的文档介绍:vector类文档

总结如下:

  1. C++ 中的 vector 是一种序列容器,它允许你在运行时动态地插入和删除元素。
  2. vector 的大小可以根据需要自动增长和缩小。
  3. vector 中的元素在内存中是连续存储的,这使得访问元素非常快速。
  4. vector 可以被迭代,你可以使用循环(如 for 循环)来访问它的元素。
  5. vector 可以存储任何类型的元素,包括内置类型、对象、指针等。
  6. 要想使用vector ,必须包含适当的头文件,如下using声明:
    #include<vector>
    using std::vector;

vector对象集合常用接口(成员函数)

📌vector对象集合模板默认成员函数

🎏vector对象集合模板构造函数

        如下,C++98标准中对于vector类实现了4个重载的构造函数:

        其参数解析如下:

        接下来我们演示使用这四种vector类构造函数(该部分演示会涉及一部分迭代遍历和元素访问操作,还不太了解的朋友可以先看一下vector的迭代遍历及元素访问操作): 

函数名称功能说明
explicit vector (const allocator_type& alloc = allocator_type());
构造一个没有元素的空容器。
explicit vector 
(size_type n, const value_type& val = value_type(),
const allocator_type& alloc = allocator_type());
构造一个包含 n 个元素的容器。每个元素都是 val 的拷贝。
template <class InputIterator>
vector (InputIterator first,InputIterator last,
const allocator_type& alloc = allocator_type());
构造一个容器,其元素数与范围 [first,last] 一样多,每个元素按相同的顺序由该范围中的相应元素构造。
vector (const vector& x);
构造一个容器,其中包含 x 中每个元素的拷贝,顺序相同。

        注:vector构造函数中出现的alloc参数是空间配置器/内存池,由于vector要频繁的申请和释放空间,为了提高获取和释放空间的效率,就引入了一个内存池变量作为缺省参数.关于内存池的部分我们暂时不在初步学习C++的时候讲解,只在此提及一下,方便大家理解vector的构造函数的组成.

        如下代码,分别按上述构造函数顺序调用了相应构造函数初始化了4个vector对象集合:

#include<vector>
#include<iostream>
using namespace std;

int main()
{
	//构造空的vector对象集合,即空容器
	vector<int> v1;
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	//构造一个包含 10 个元素的容器。每个元素都是 1 的拷贝。
	vector<int> v2(10,1);
	for (auto e : v2)
	{
		cout << e << " ";
	}
	cout << endl;

	//构造一个容器,其元素数与范围 [v2.begin(),v2.end()] 一样多
	//每个元素按相同的顺序由该范围中的相应元素构造。
	vector<int> v3(v2.begin(),v2.end());
	for (auto e : v3)
	{
		cout << e << " ";
	}
	cout << endl;

	//构造一个容器,其中包含 v3 中每个元素的拷贝,顺序相同。
	vector<int> v4(v3);
	for (auto e : v4)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}

        运行程序,构造对象集合结果如下:


        注意,对于vector的迭代器构造还有一些别的玩法,我们可以使用vector自己的迭代器构造vector,如:

        还可以使用别的类型的迭代器构造vector,如:

        甚至可以不用迭代器,使用类似于迭代器的指针也可以构造vector,如:

        但需要注意的是,在使用不同类型的迭代器构造时需要保证它们的基本元素类型与vector对象集合一致,否则将导致数据隐式类型转换.


🎏vector对象集合模板析构函数

    如下,C++中对于vector类实现了1个析构函数:

        该函数没有参数,没有返回值,在类对象生命周期结束后自动调用销毁对象集合.


🎏vector对象集合模板赋值运算符重载

         如下,C++98标准中对于vector类实现了1个赋值运算符重载函数:

        接下来我们演示使用这种常见的vector类赋值运算符重载函数: 

        如下代码,调用了相应赋值运算符重载函数把v1赋值给了vector类对象v2:

int main()
{
	//构造一个包含 10 个元素的容器。每个元素都是 1 的拷贝。
	vector<int> v1(10, 1);
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	vector<int> v2;
	//将v1赋值给v2
	v2 = v1;
	for (auto e : v2)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}

        运行程序,调用赋值运算符重载函数结果如下:


📌vector对象集合的迭代遍历及元素访问操作

        vector对象集合的迭代器相关函数共有8个,如下:

        vector对象集合的元素访问相关函数共有五个,如下:

         接下来我们演示学习几种常见的vector对象集合的迭代遍历及元素访问函数:

🎏operator[]运算符重载

operator[]运算符重载定义:

        注意:operator[]和at()函数的不同之处在于 vector::at 是边界检查的,并在请求的位置超出范围时通过抛出out_of_range异常来发出信号。


operator[]遍历vector对象集合:

int main()
{
	//构造一个数组a
	int a[] = { 1,4,3,2,5 };

	//使用指针构造vector
	vector<int> v1(a, a + 5);

	//使用operator[]遍历vector
	for (int i = 0; i < v1.size(); i++)
	{
		cout << v1[i] << " ";
	}
	cout << endl;

	return 0;
}


operator[]修改vector对象集合:

        因为operator[]返回的是引用类型,因此可以利用其对vector对象集合进行修改:

int main()
{
	//构造一个数组a
	int a[] = { 1,4,3,2,5 };

	//使用指针构造vector
	vector<int> v1(a, a + 5);

	//使用operator[]修改vector
	for (int i = 0; i < v1.size(); i++)
	{
		++v1[i];
		cout << v1[i] << " ";
	}
	cout << endl;

	return 0;
}


🎏at访问对象集合某位置元素

at()函数定义:


at()函数遍历vector对象集合:

int main()
{
	//构造一个数组a
	int a[] = { 1,4,3,2,5 };

	//使用指针构造vector
	vector<int> v1(a, a + 5);

	//使用at()函数遍历vector
	for (int i = 0; i < v1.size(); i++)
	{
		cout << v1.at(i) << " ";
	}
	cout << endl;

	return 0;
}

at()函数遍历对象集合效果如下:


at()函数修改vector对象集合:

        因为at()函数返回的是引用类型,因此可以利用其对vector对象集合进行修改:

int main()
{
	//构造一个数组a
	int a[] = { 1,4,3,2,5 };

	//使用指针构造vector
	vector<int> v1(a, a + 5);

	//使用at()函数修改vector
	for (int i = 0; i < v1.size(); i++)
	{
		++v1.at(i);
		cout << v1.at(i) << " ";
	}
	cout << endl;

	return 0;
}


🎏顺序迭代器begin+end

begin+end迭代器顺序遍历访问vector对象集合:

begin()函数定义如下:

end()函数定义如下:

begin+end迭代器顺序遍历访问vector对象集合:

int main()
{
	//构造一个数组a
	int a[] = { 1,4,3,2,5 };

	//使用指针构造vector
	vector<int> v1(a, a + 5);

	//使用begin+end迭代器顺序遍历vector
	vector<int>::iterator it = v1.begin();

	while (it != v1.end())
	{
		cout << *it << " ";
		++it;
	}

	return 0;
}

begin+end迭代器顺序遍历访问对象集合效果如下:


begin+end迭代器修改vector对象集合:

int main()
{
	//构造一个数组a
	int a[] = { 1,4,3,2,5 };

	//使用指针构造vector
	vector<int> v1(a, a + 5);

	//使用begin+end迭代器修改vector
	vector<int>::iterator it = v1.begin();

	while (it != v1.end())
	{
		++(*it);

		cout << *it << " ";
		++it;
	}

	return 0;
}


🎏反向迭代器rbegin+rend

rbegin+rend逆序遍历访问vector对象集合:

rbegin()函数定义如下:

rend()函数定义如下:


使用rbegin+rend迭代器反向遍历访问vector对象集合:

int main()
{
	//构造一个数组a
	int a[] = { 1,4,3,2,5 };

	//使用指针构造vector
	vector<int> v1(a, a + 5);

	//使用rbegin+rend迭代器反向遍历vector
	vector<int>::reverse_iterator rit = v1.rbegin();

	while (rit != v1.rend())
	{
		cout << *rit << " ";
		++rit;
	}

	return 0;
}

使用rbegin+rend反向迭代器修改vector对象集合:
int main()
{
	//构造一个数组a
	int a[] = { 1,4,3,2,5 };

	//使用指针构造vector
	vector<int> v1(a, a + 5);

	//使用rbegin+rend迭代器修改vector
	vector<int>::reverse_iterator rit = v1.rbegin();

	while (rit != v1.rend())
	{
		++(*rit);

		cout << *rit << " ";
		++rit;
	}

	return 0;
}


🎏范围for

   C++11中引入了基于范围的for循环。for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量, 第二部分则表示被迭代的范围。(注:知道数据类型的情况下可以不使用auto关键字自动推导类型)


范围for顺序访问vector对象集合:

int main()
{
	//构造一个数组a
	int a[] = { 1,4,3,2,5 };

	//使用指针构造vector
	vector<int> v1(a, a + 5);

	//使用范围for遍历vector
	for(auto e : v1)
	{
		cout << e << " ";
	}

	return 0;
}

范围for顺序访问vector对象集合效果如下:


范围for修改vector对象集合:

int main()
{
	//构造一个数组a
	int a[] = { 1,4,3,2,5 };

	//使用指针构造vector
	vector<int> v1(a, a + 5);

	//使用范围for修改vector
	for(auto &e : v1)
	{
		e++;
		cout << e << " ";
	}

	return 0;
}


🎏data获取指向vector中第一个元素位置的指针

data()函数定义如下:

使用data()函数获取vector首元素的位置(演示环境为32位机器,故指针大小为8位):

int main()
{
	//构造一个数组a
	int a[] = { 1,4,3,2,5 };

	//使用指针构造vector
	vector<int> v1(a, a + 5);

	cout << v1.data() << endl;
	cout << *(v1.data()) << endl;
	cout << v1.front() << endl;

	return 0;
}


🎏sort排序

        sort()函数是STL中算法部分的一个接口,其定义如下:

        由定义可知,sort()函数会接收三个参数,分别是待排序区间的初始位置,最终位置决定排序方法的函数指针.功能是对范围内的元素进行排序.

        注意:

  1. 最后一个参数有两种,分别是less对象greater对象
    less  //用来排升序
    
    //使用方法如下
    less<排序元素类型> 变量名
    
    //如
    less<int> le
    
    
    greater   //用来排降序
    
    //使用方法如下
    greater<排序元素类型> 变量名
    
    //如
    greater<int> gt;
  2. 调用sort()函数前需要包含头文件
#include<algorithm>

        接下来我们演示几种sort()排序的情况:

1.sort()排升序

        如下代码,我们创建一个无序的int类型的向量v1,然后使用sort()函数将其排为升序:

//sort()排升序
void test1()
{
	//构造一个数组a
	int a[] = { 1,4,3,2,5 };

	//使用指针构造vector
	vector<int> v1(a, a + 5);
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	//升序
	//less(一般是默认的,不用传)
	less<int> le;

	sort(v1.begin(), v1.end(), le);

	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;
}

//sort()排序
int main()
{
	test1();
	return 0;
}

        注意,sort()函数排升序时,也可以不传最后一个参数,sort()函数也会默认排升序,如:


2.sort()排降序

        如下代码,我们创建一个无序的int类型的向量v1,然后使用sort()函数将其排为降序:

//sort排降序
void test2()
{
	//构造一个数组a
	int a[] = { 1,4,3,2,5 };

	//使用指针构造vector
	vector<int> v1(a, a + 5);
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	//降序 greater
	greater<int> gt;

	//定义一个greater的对象,作为sort函数的参数
	sort(v1.begin(), v1.end(), gt);
	
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;
}

//sort()排序
int main()
{
	test2();
	return 0;
}

        注意:因为此处创建greater变量的作用仅仅是帮助sort()函数识别到底是升序还是降序,变量本身的存在没有多大的意义,所以我们可以在传参的时候使用匿名对象来作为sort()的参数,这样,在这一行结束时匿名对象就会销毁,有助于节省程序运行时的栈空间消耗:

//更好的方式是定义一个匿名对象传过去
sort(v1.begin(), v1.end(), greater<int>());

3.sort()利用反向迭代器排序

        如下代码,我们创建一个无序的int类型的向量v1,然后使用sort()函数,并给其传入待排区间的反向迭代器,将其排为降序:

//sort排降序
void test3()
{
	//构造一个数组a
	int a[] = { 1,4,3,2,5 };

	//使用指针构造vector
	vector<int> v1(a, a + 5);
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	//利用反向迭代器排降序:
	//下面这行代码的含义相当于对待排序列逆向排升序,即排降序
	sort(v1.rbegin(), v1.rend());

	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

}

//sort()排序
int main()
{
	test3();
	return 0;
}


4.利用sort()函数给string排序

        如下代码,我们创建一个string类型的变量s1,然后使用sort()函数将其内部的字符排为升序:

//sort()排序string
void test4()
{
	string s1("hello world");
	cout << s1 << endl;

	sort(s1.begin(), s1.end());
	cout << s1 << endl;

}

//sort()排序
int main()
{
	test4();
	return 0;
}


5.利用sort()函数给数组排序

       如下代码,我们创建一个无序的int类型的数组a,然后使用sort()函数将其排为升序:

//sort()排序数组
void test5()
{
	//构造一个数组a
	int a[] = { 1,4,3,2,5 };
	for (auto e : a)
	{
		cout << e << " ";
	}
	cout << endl;

	sort(a, a + 5);//传入数组的迭代区间

	for (auto e : a)
	{
		cout << e << " ";
	}
}

//sort()排序
int main()
{
	test5();
	return 0;
}


📌vector对象集合模板的容量操作

    vector对象集合容量相关操作函数共有7个,如下:

        接下来我们演示学习几种常见的vector对象集合的容量操作函数:

函数名称功能说明
size返回vector有效元素长度
resize将有效元素的个数改成n个,多出的空间用元素c填充
capacity返回vector容量总大小
empty检测vector是否为空,是返回true,否则返回false
reserve更改vector容量

🎏size()函数

size()函数定义:


使用size()函数获取vector有效元素长度:

int main()
{
	//构造一个数组a
	int a[] = { 1,4,3,2,5 };

	//使用指针构造vector
	vector<int> v1(a, a + 5);

	//使用size()获取有效元素长度
	cout << v1.size() << endl;

	return 0;
}

size()函数效果如下:


🎏capacity()函数

capacity()函数定义:


使用capacity()函数获取vector对象集合当前存储空间总大小:

int main()
{
	//构造一个数组a
	int a[] = { 1,4,3,2,5 };

	//使用指针构造vector
	vector<int> v1(a, a + 5);

	//使用capacity()获取vector当前容量
	cout << v1.capacity() << endl;

	return 0;
}

capacity()函数效果如下:


🎏empty()函数

empty()函数定义:


使用empty()函数判断vector对象集合是否为空:

int main()
{
	//构造一个数组a
	int a[] = { 1,4,3,2,5 };

	vector<int> v1(a, a + 5);
	vector<int> v2;

	//使用empty()检查v1,v2是否为空
	cout << v1.empty() << endl;
	cout << v2.empty() << endl;

	return 0;
}


🎏resize()函数

resize()函数定义:


使用resize()函数调整vector对象集合有效元素大小:

int main()
{
	//构造一个数组a
	int a[] = { 1,4,3,2,5 };

	vector<int> v1(a, a + 5);
	vector<int> v2;

	//使用size()获取vector当前有效元素数量
	cout << v1.size() << endl;
	cout << v2.size() << endl;

	//使用resize()修改vector当前有效元素数量
	v1.resize(15);
	v2.resize(10);

	//使用size()获取vector当前有效元素数量
	cout << v1.size() << endl;
	cout << v2.size() << endl;

	return 0;
}

resize()函数效果如下:


🎏reserve()函数

reserve()函数定义:


使用reserve()函数更改vector对象集合容量大小:

int main()
{
	//构造一个数组a
	int a[] = { 1,4,3,2,5 };

	vector<int> v1(a, a + 5);
	vector<int> v2;

	//使用capacity()获取vector当前容量
	cout << v1.capacity() << endl;
	cout << v2.capacity() << endl;

	//使用reserve()修改vector当前容量
	v1.reserve(15);
	v2.reserve(10);

	//使用capacity()获取vector当前容量
	cout << v1.capacity() << endl;
	cout << v2.capacity() << endl;

	return 0;
}

reserve()函数效果如下:


reserve()函数使用常见误区:

        如下代码,我们有时会使用reserve()开辟好空间后直接使用operator[]来给vector赋值,这样是完全错误的使用方法,它会导致程序运行报错:

//resever()易错
int main()
{
	vector<int> v1;
	v1.reserve(10);

	for (int i = 0; i < 10; i++)
	{
		v1[i] = i;
		//错误,因为reserve只改变了capacity,没有改变size
		//而operator[]访问时需要断言检查是否<size
	}

	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}

        原因就在于 operator[]只能访问vector的有效数据,即size范围内的数据,而对于capacity范围内但是size范围外的数据,operator[]是不能访问的,如果非要访问,则相当于越界访问,程序就会报错.对于这个问题,有两种解决方案,一种是, 当我们使用reserve()函数修改vector容量时,填入数据就使用push_back()函数,如:
vector<int> v1;
v1.reserve(10);

for (int i = 0; i < 10; i++)
{
	v1.push_back(i);
}

        还有一种方法就是,当我们要使用operator[]来给vector赋值时,前面就要先用resize()调整vector有效元素的数量,便于避免operator[]非法访问,如:

vector<int> v1;
v1.resize(10);

for (int i = 0; i < 10; i++)
{
	v1[i] = i;
}


📌vector对象集合模板的成员修改操作

vector对象集合的成员修改函数共有9个,如下:

常用的vector修改操作:

函数名称功能说明
push_back在字符串后尾插字符c
pop_back删除vector最后一个元素
insert在vector中n位置插入x
erase删除vector中n位置元素

🎏push_back()函数

push_back()函数定义:


使用push_back()函数在vector对象集合后追加元素:

int main()
{
	//构造一个数组a
	int a[] = { 1,4,3,2,5 };

	vector<int> v1(a, a + 5);

	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	v1.push_back(8);
	v1.push_back(6);
	v1.push_back(9);

	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}

push_back()函数效果如下:


🎏pop_back()函数

pop_back()函数定义:


使用pop_back()函数删除vector对象集合最后一个元素:

int main()
{
	//构造一个数组a
	int a[] = { 1,4,3,2,5 };

	vector<int> v1(a, a + 5);

	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	v1.pop_back();

	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}

pop_back()函数删除vector对象集合最后一个元素效果如下:


🎏insert()函数

insert()函数定义:


使用insert()函数在vector对象集合中第三个位置插入1个8:

int main()
{
	//构造一个数组a
	int a[] = { 1,4,3,2,5 };

	vector<int> v1(a, a + 5);

	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	v1.insert(v1.begin() + 2 , 8);

	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}


使用insert()函数在vector对象集合中第三个位置插入3个8:

int main()
{
	//构造一个数组a
	int a[] = { 1,4,3,2,5 };

	vector<int> v1(a, a + 5);

	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	v1.insert(v1.begin() + 2 , 3 , 8);

	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}


🎏erase()函数

erase()函数定义:


使用erase()函数删除vector对象集合中第三个位置的元素:

int main()
{
	//构造一个数组a
	int a[] = { 1,4,3,2,5,8,6,0,9,7 };

	vector<int> v1(a, a + 10);

	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	v1.erase(v1.begin() + 2);

	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}


使用erase()函数删除vector对象集合中第三个位置到第六个位置的元素:

int main()
{
	//构造一个数组a
	int a[] = { 1,4,3,2,5,8,6,0,9,7 };

	vector<int> v1(a, a + 10);

	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	v1.erase(v1.begin() + 2 , v1.begin() + 6 );

	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}


🎏find()函数及其应用

find()函数定义:

        由定义可知,find()函数接收三个参数,分别是代表开始查找范围的迭代器first,和代表结束查找范围的迭代器last(注意,该查找范围并不包含last本身,即查找范围是(first,last]),以及一个待查找的元素val.如果find函数在范围中查找到了val,则返回第一个等于val的元素的迭代器,如果没有找到,则返回迭代器last.


        使用find()函数查找vector中的值:

int main()
{
	//构造一个数组a
	int a[] = { 1,4,3,2,5,8,6,0,9,7 };

	vector<int> v1(a, a + 10);

	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	vector<int>::iterator fit =find(v1.begin(), v1.end(), 8);

	if (fit != v1.end())
	{
		cout << *fit << endl;
	}
	else
	{
		cout << "none" << endl;
	}

	fit = find(v1.begin(), v1.end(), 10);

	if (fit != v1.end())
	{
		cout << *fit << endl;
	}
	else
	{
		cout << "none" << endl;
	}

	return 0;
}

        查找结果如下:


        使用find()函数查找vector对象集合中的某个元素并删除:

int main()
{
	//构造一个数组a
	int a[] = { 1,4,3,2,5,8,6,0,9,7 };

	vector<int> v1(a, a + 10);

	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	v1.erase( find(v1.begin(), v1.end(), 8) );

	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}

        删除结果如下:


        使用find()函数查找并删除vector中多个相同的元素:

        我们有时会有这样的场景,比如我们想删除下面vector中所有的元素8:

1,4,3,2,5,8,6,8,0,8,8,8,9,7

        按照前面的思路,我们一定首先想到的就是将删除和查找操作写成一个循环,如:

vector<int>::iterator fit = find(v1.begin(), v1.end(), 8);

while (fit != v1.end())
{
	v1.erase(fit);
	fit = find(fit+1, v1.end(), 8);
}

        这段代码看似没有什么问题,但实际上运行程序会造成经典的迭代器失效问题:

        迭代器失效问题简单来讲,就是因为底层实现的原因,我们在erase删除fit迭代器时fit就会失效,这时候下一行再用fit+1作为find的参数来查找就会导致程序异常,对于这个问题,目前比较简单的解决方法是:

        每次都从vector的最开始查找我们的目标元素,该方法的缺点是效率很低:

int main()
{
	//构造一个数组a
	int a[] = { 1,4,3,2,5,8,6,8,0,8,8,8,9,7 };
	vector<int> v1(a, a + 14);

	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	vector<int>::iterator fit = find(v1.begin(), v1.end(), 8);

	while (fit != v1.end())
	{
		v1.erase(fit);
		fit = find(v1.begin(), v1.end(), 8);
	}

	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}


结语

希望这篇关于 vector对象集合简介 的博客能对大家有所帮助,欢迎大佬们留言或私信与我交流.

学海漫浩浩,我亦苦作舟!关注我,大家一起学习,一起进步!

相关文章推荐

【C++】9道经典面试题带你玩转string类

【C++】模拟实现string类

【C++】详解深浅拷贝的概念及其区别

【C++】动态内存管理

【C++】标准库类型string

【C++】构建第一个C++类:Date类

【C++】类的六大默认成员函数及其特性(万字详解)

【C++】函数重载

【C++】什么是类与对象?


​​

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

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

相关文章

【vue3|第18期】Vue-Router路由的三种传参方式

日期:2024年7月17日 作者:Commas 签名:(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释:如果您觉得有所帮助,帮忙点个赞,也可以关注我,我们一起成长;如果有不对的地方,还望各位大佬不吝赐教,谢谢^ - ^ 1.01365 = 37.7834;0.99365 = 0.0255 1.02365 = 1377.408…

HarmonyOS入门-状态管理

View(UI)&#xff1a;UI渲染&#xff0c;指将build方法内的UI描述和Builder装饰的方法内的UI描述映射到界面。 State&#xff1a;状态&#xff0c;指驱动UI更新的数据。用户通过触发组件的事件方法&#xff0c;改变状态数据。状态数据的改变&#xff0c;引起UI的重新渲染。 装…

<PLC><HMI><汇川>在汇川HMI画面中,如何为UI设置全局样式?

前言 汇川的HMI软件是使用了Qt来编写的,因此在汇川的HMI程序编写过程,是支持使用qt的样式来自定义部件样式的,即qss格式。 概述 汇川的软件本身提供三个系统的style样式,我们可以直接使用,但是,如果系统提供的样式不符合你的需求,那么你可以对其进行修改,或者自己新建…

Pytorch使用教学4-张量的索引

1 张量的符号索引 张量也是有序序列&#xff0c;我们可以根据每个元素在系统内的顺序位置&#xff0c;来找出特定的元素&#xff0c;也就是索引。 1.1 一维张量的索引 一维张量由零维张量构成 一维张量索引与Python中的索引一样是是从左到右&#xff0c;从0开始的&#xff…

读写给大家的AI极简史笔记07读后总结与感想兼导读

1. 基本信息 写给大家的AI极简史&#xff1a;从图灵测试到智能物联 [德]托马斯拉姆齐 著 中国友谊出版公司,2019年9月出版 1.1. 读薄率 书籍总字数&#xff1f;&#xff1f;千字&#xff0c;笔记总字数16382字。 读薄率16382&#xff1f;&#xff1f;000≈&#xff1f;&a…

如何解决 Nginx 与虚拟现实设备的集成问题?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01; 文章目录 如何解决 Nginx 与虚拟现实设备的集成问题&#xff1f; 如何解决 Nginx 与虚拟现实设备的集成问题&#xff1f; 在当今科技飞速发展的时代&#xff0c;虚拟现实…

钡铼网关实时数据互联,加速IEC104与MQTT云平台对接

随着工业4.0时代的到来&#xff0c;电力系统中的数据采集、监控与远程控制需求日益增长。IEC 104&#xff08;IEC 60870-5-104&#xff09;作为国际电工委员会&#xff08;IEC&#xff09;制定的电力自动化通信协议&#xff0c;广泛应用于电力系统的状态监测、数据采集和设备控…

硅纪元视角 | Stability AI推出Stable Video 4D,40秒生成8角度动态视频!

在数字化浪潮的推动下&#xff0c;人工智能&#xff08;AI&#xff09;正成为塑造未来的关键力量。硅纪元视角栏目紧跟AI科技的最新发展&#xff0c;捕捉行业动态&#xff1b;提供深入的新闻解读&#xff0c;助您洞悉技术背后的逻辑&#xff1b;汇聚行业专家的见解&#xff0c;…

Sqli-labs-master的21—25通关教程

目录 Less-21(闭合) 查询数据库名 查询数据库中的表 查询表中字段名 查询表中数据 Less-22&#xff08;"闭合&#xff09; 查询数据库名 查询数据库中的表 查询表中字段名 查询表中数据 Less-23 查询数据库名 查询数据库中的表 查询表中字段名 查询表中数据…

基于OSS前端直传的分片上传以及断点续传

一、大文件分片上传 原型 大文件如果直接上传的话由于nginx的限制会导致响应500报错&#xff0c;或者响应时间过长导致响应超时 并且大文件上传有如下缺点 上传时间长: 对于大文件&#xff0c;直接上传可能需要较长时间&#xff0c;特别是在网络速度较慢或不稳定的情况下。这…

深入搞懂Checkpoint调优基础及原理

前言 在执行大量写操作的系统上,调优检查点对于获得良好的性能至关重要。然而,检查点是我们经常发现混淆和配置问题的地方之一,无论是在社区邮件列表中,还是在为客户提供支持和咨询期间。这篇文章旨在解释检查点是什么——目的和数据库如何实现它——以及如何调优它们。 注…

Leetcode—74. 搜索二维矩阵【中等】

2024每日刷题&#xff08;149&#xff09; Leetcode—74. 搜索二维矩阵 实现代码 class Solution { public:bool searchMatrix(vector<vector<int>>& matrix, int target) {int m matrix.size();int n matrix[0].size();int l 0;int r m * n;int mid -1…

如何解决 Nginx 与无服务器架构的集成问题?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01; 文章目录 如何解决 Nginx 与无服务器架构的集成问题&#xff1f; 如何解决 Nginx 与无服务器架构的集成问题&#xff1f; 在当今的云计算时代&#xff0c;无服务器架构因…

AI有关的学习和python

一、基本概念 AIGC&#xff08;AI Generated content AI 生成内容&#xff09; AI生成的文本、代码、图片、音频、视频。都可以成为AIGC。 Generative AI&#xff08;生成式AI&#xff09;所生成的内容就是AIGC AI指代计算机人工智能&#xff0c;模仿人类的智能从而解决问题…

JAVA中的泛型机制详解

1.泛型的概念 java泛型是java5引入的一个特性&#xff0c;它允许我们为类&#xff0c;接口&#xff0c;方法指定类型参数&#xff0c;从而提供编译时类型安全检查。泛型的本质是参数化类型&#xff0c;即在声明类&#xff0c;接口或者方法时不指定具体的类型&#xff0c;而是使…

sed利用脚本处理文件

一、sed是什么 sed 命令是利用脚本来处理文本文件。它可以依照脚本的指令来处理、编辑文本文件。主要用来自动编 辑一个或多个文件、简化对文件的反复操作、编写转换程序等。 二、sed的原理 读入新的一行内容到缓存空间&#xff1b; 从指定的操作指令中取出第一条指令&…

C++ 列式内存布局数据存储格式 Arrow

Apache Arrow 优点 : 高性能数据处理&#xff1a; Arrow 使用列式内存布局&#xff0c;这特别适合于数据分析和查询操作&#xff0c;因为它允许对数据进行高效批量处理&#xff0c;减少CPU缓存未命中&#xff0c;从而提升处理速度。 零拷贝数据共享&#xff1a; Arrow …

【PyTorch】基于YOLO的多目标检测项目(一)

【PyTorch】基于YOLO的多目标检测项目&#xff08;一&#xff09; 【PyTorch】基于YOLO的多目标检测项目&#xff08;二&#xff09; 目标检测是对图像中的现有目标进行定位和分类的过程。识别的对象在图像中显示有边界框。一般的目标检测方法有两种&#xff1a;基于区域提议的…

javaEE-02-servlet

文章目录 Servlet 技术servlet程序示例通过实现Servlet接口实现Servlet程序通过继承 HttpServlet 实现 Servlet 程序 Servlet的声明周期 ServletConfig 类ServletContext 类HttpServletRequest 类请求的转发 HttpServletResponse 类请求重定向 HTTP 协议GET 请求Post请求常用请…

三维影像系统PACS源码,图像存储与传输系统,应用于医院中管理医疗设备如CT,MR等产生的医学图像的信息系统

PACS&#xff0c;即图像存储与传输系统&#xff0c;是应用于医院中管理医疗设备如CT&#xff0c;MR等产生的医学图像的信息系统。目标是支持在医院内部所有关于图像的活动&#xff0c;集成了医疗设备&#xff0c;图像存储和分发&#xff0c;数字图像在重要诊断和会诊时的显示&a…