🦄个人主页:修修修也
🎏所属专栏: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类文档
总结如下:
- C++ 中的 vector 是一种序列容器,它允许你在运行时动态地插入和删除元素。
vector
的大小可以根据需要自动增长和缩小。vector
中的元素在内存中是连续存储的,这使得访问元素非常快速。vector
可以被迭代,你可以使用循环(如for
循环)来访问它的元素。vector
可以存储任何类型的元素,包括内置类型、对象、指针等。- 要想使用
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()函数会接收三个参数,分别是待排序区间的初始位置,最终位置和决定排序方法的函数指针.功能是对范围内的元素进行排序.
注意:
- 最后一个参数有两种,分别是less对象和greater对象
less //用来排升序 //使用方法如下 less<排序元素类型> 变量名 //如 less<int> le greater //用来排降序 //使用方法如下 greater<排序元素类型> 变量名 //如 greater<int> gt;
- 调用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++】什么是类与对象?