文章目录
前言一、vector的定义二、vector中元素的访问三、vector中空间增长三、vector中增删查改总结
前言
在本篇文章中,我们将会学到关于C++中vector的使用方法
其中包括成员函数(构造,析构),迭代器相关的知识,容量(size,resize,capacity,reverse),以及vector的增删查改
vector
进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。本质讲,vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小。为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言,这是一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大小。vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存
储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。因此,vector占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增
长。与其它动态序列容器相比(deque, list and forward_list), vector在访问元素的时候更加高效,在末
尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起list和forward_list
统一的迭代器和引用更好
一、vector的定义
单独定义一个vector:
vector < typename > name;
上面这个定义其实相当于是一维数组name[size],只不过其size可以根据需要进行变化,这就是“变长数组”的名字的由来。
这里的typename可以是任何基本类型,例如int、double、char、结构体等,也可以是STL标准容器,例如set、queue、vector等。
下面我们以int为例子:
??v1一个空的vector
vector < int > v1
??v2这个vector中包含10个int,并且默认初始化为0
vector < int > v2(10);
??v3这个vector中包含10个int,并且手动初始化为1
vector < int > v3(10,1);
??v4这个vector中采用v2迭代器区间进行开空间和初始化
并且空间大小和初始化内容与v2相同,即v4包含10个int,初始化为0
vector < int > v4(v2.begin(),v2,end())
??v5这个vector中采用拷贝构造初始化,并且空间大小和初始化内容与v3相同,即v5包含10个int,初始化为1
vector < int > v5(v3)
??v6这个vector中采用了初始化列表初始化,{}中有几个元素就代表开了几个空间,{}中内容表示初始化的值。这是c++11中的语法
vector < int >v6{1,2,3,4};
二、vector中元素的访问
vector库中提供了两种访问访问方式
✨ ✨operator [ ] 像数组一样进行访问
✨ ✨使用at进行访问,at访问不到元素是抛异常
vector v1{ 1,2,3,4 };
cout << v1[0] << endl;
cout << v1.at(1) << endl;
✨ ✨vecctor::begin() 指向第一个元素
✨ ✨vecctor::end() 指向第最后一个元素的下一个位置
✨ ✨vecctor::rbegin() 反向迭代器,指向元素最后一个元素
✨ ✨vecctor::rend() 反向迭代器,指向元素第一个位置
✨ ✨vector::front() 返回首元素的引用
✨ ✨vector::back() 返回最后一个元素的引用
vector中元素的遍历
??.正常for循环
vector <int> v1{1,2,3,4};//1.循环遍历for (int i = 0; i < v1.size(); i++){cout << v1[i] << " ";}cout << endl;
??.范围for
//2.范围forvector <int> v1{1,2,3,4};///依次取v1中的值赋值给e,自动判断结束,自动++往后走for (auto& e : v1){cout <<e << " ";}cout << endl;
??.迭代器,也可以使用反向迭代器
//3.迭代器 vector <int>::iterator it = v1.begin();while(it!=v1.end()){(*it) += 2;cout << *it << " ";it++;}cout << endl;
vector < int >::iterator it1=v1.begin();//正向迭代器
vector < int >::reverse_iterator it2=v2.rbegin();//反向迭代器
vector < int >::const_iterator it3=v3.begin();//const正向迭代器
vector < int >::const_reverse_iterator it3=v3.begin();//const反向迭代器
这些我们也可以用auto来代替,自动推倒类型
这三种方式不仅能访问vector的每一个元素,并且还可以对元素进行修改
三、vector中空间增长
在vector中有空间的大小,容量等概念,我们来一一学习一下
??size 用于计算vector中数据个数
vector<int> v(10);cout << v.size() << endl;
最终结果输出10
??resize 改变size的大小,开空间同时进行初始化
vector<int> v; for (int i = 1; i < 10; i++) v.push_back(i); v.resize(5); //剩下的初始化为100 v.resize(8, 100); //剩下的初始化为0 v.resize(12); cout << "v contains:"; for (size_t i = 0; i < v.size(); i++) cout << ' ' << v[i];
最终输出结果为v contains: 1 2 3 4 5 100 100 100 0 0 0 0
resize变小时不会改变capacity的大小,resize变大时,capacity也会跟着相应的调整
??capacity 获取容量大小
我们来看一下扩容机制
void TestVectorExpand(){size_t sz;vector<int> v;sz = v.capacity();cout << "making v grow:\n";for (int i = 0; i < 100; ++i){v.push_back(i);if (sz != v.capacity()){sz = v.capacity();cout << "capacity changed: " << sz << '\n';}}}
vs2022输出结果为
g++下输出结果
我们发现不同平台扩容机制不同,vs按照1.5倍增长,g++按照两倍增长,我们不要固化的认为vector增容就是两倍,具体增长是根据具体需求决定的,vs是PJ版本STL,g++是SGI版本STL。
??resreve 只负责开空间,不负责初始化工作
一般用于知道需要多少空间,用reverse一次性开好,这样就可以缓解vector增容的代价缺陷
void TestVectorExpandOP(){ vector<int> v; size_t sz = v.capacity(); v.reserve(100); // 提前将容量设置好,可以避免一遍插入一遍扩容 cout << "making bar grow:\n"; for (int i = 0; i < 100; ++i) { v.push_back(i); if (sz != v.capacity()) { sz = v.capacity(); cout << "capacity changed: " << sz << '\n'; } }}
一次性开好需要的空间大小,就可以避免边插入边扩容的问题了
??empty 判断vector中是否为空
??shrink_to_fit 在size发生巨大变化时,采用shrink_to_fit 调整capacity的大小,使capacity可以与size的大小进匹配
三、vector中增删查改
??push_back 尾插 pop_back尾删
void TestVector4(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);auto it = v.begin();while (it != v.end()){cout << *it << " ";++it;}cout << endl;v.pop_back();v.pop_back();it = v.begin();while (it != v.end()){cout << *it << " ";++it;}cout << endl;}
输出结果为
??find 查找这个并不是在vector库里的,而是算法模块实现的
??insert 进行插入
❤️❤️在pos插入value
iterator insert (pos,val);
vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);auto pos = find(v.begin(), v.end(), 3);//插入一个数if (pos != v.end()){v.insert(pos, 10);}pos = find(v.begin(), v.end(), 2);
❤️❤️在pos位置插入n个相同的值value
void insert ( pos, n, val);
//插入多个值if (pos != v.end()){v.insert(pos, 2,100);}
❤️❤️在pos位置插入一段迭代器区间
void insert (pos, first, last);
//插入一个迭代器区间 vector<int>vv{ 20,30,40 }; pos = find(v.begin(), v.end(), 1); if (pos != v.end()) { v.insert(pos, vv.begin(), vv.end()); }
??erase 删除值
❤️❤️删除pos位置的值
erase (pos);
pos = find(v.begin(), v.end(), 30); v.erase(pos);
❤️❤️删除一段迭代器区间
erase (first,last);
v.erase(v.begin(), v.begin() + 3);
??swap 交换两个vector
void swap (vector& x);
void test6() { vector<int>v1{ 1,2,3,4 }; vector<int>v2{ 10,20,30,40 }; v1.swap(v2); }
??clear 将size设置为零,capacity不变
总结
以上就是今天要讲的内容,本文仅仅详细介绍了C++vector库的系列使用方法,希望对大家的学习有所帮助,仅供参考 如有错误请大佬指点我会尽快去改正 欢迎大家来评论~~ ? ? ? ?