外贸最大电子元器件交易网站,开发微信小程序需要什么软件,十大购物网站排名,可以做h5的网站有哪些大家好我是沐曦希#x1f495; 文章目录一.vector介绍二、构造函数三、遍历1.[]2.迭代器3.范围for四、容量操作1.扩容机制五、增删查改六、迭代器失效问题一.vector介绍 vector是表示可变大小数组的序列容器。就像数组一样#xff0c;vector也采用的连续存储空间来存储元素。… 大家好我是沐曦希 文章目录一.vector介绍二、构造函数三、遍历1.[]2.迭代器3.范围for四、容量操作1.扩容机制五、增删查改六、迭代器失效问题一.vector介绍 vector是表示可变大小数组的序列容器。就像数组一样vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问和数组一样高效。但是又不像数组它的大小是可以动态改变的而且它的大小会被容器自动处理。本质讲vector使用动态分配数组来存储它的元素。当新元素插入时候这个数组需要被重新分配大小为了增加存储空间。其做法是分配一个新的数组然后将全部元素移到这个数组。就时间而言这是一个相对代价高的任务因为每当一个新的元素加入到容器的时候vector并不会每次都重新分配大小。vector分配空间策略vector会分配一些额外的空间以适应可能的增长因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何重新分配都应该是对数增长的间隔大小以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。因此vector占用了更多的存储空间为了获得管理存储空间的能力并且以一种有效的方式动态增长。与其它动态序列容器相比deque, list and forward_list vector在访问元素的时候更加高效在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作效率更低。比起list和forward_list统一的迭代器和引用更好。 二、构造函数
(constructor)构造函数声明接口说明vector()重点无参构造vectorsize_type n, const value_type val value_type()构造并初始化n个valvector (const vector x);重点 拷贝构造vector (InputIterator first, InputIterator last);使用迭代器进行初始化构造已经有了使用和模拟实现string的经验直接上代码。
void test_vector1()
{vectorint v1; //无参构造vectorint v2(5, 1); //构造并初始化5个1vectorint v3(v2); //拷贝构造vectorint v4(v3.begin(), v3.end()); //使用迭代器进行初始化构造
}此外对于vector和string的关系是无法替代的string类中有一个接口c_str()转化成C语言的字符串要以\0结尾所以string类最后会有一个\0,在操作上,,等。而vector是保存字符的动态数组不会以\0结尾不保存\0且vector是T泛型所以并不存在谁替代谁。
三、遍历
1.[] void test(const vectorint v)
{for (size_t i 0; i v.size(); i){//只读cout v[i] ;}cout endl;
}
void test_vector2()
{vectorint v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);for (size_t i 0; i v1.size(); i){//可读可写v1[i];cout v1[i] ;}cout endl;test(v1);
}2.迭代器
正向迭代器和反向迭代器
iterator的使用接口说明begin end重点获取第一个数据位置的iterator/const_iterator 获取最后一个数据的下一个位置的iterator/const_iteratorrbegin rend获取最后一个数据位置的reverse_iterator获取第一个数据前一个位置的reverse_iteratorvoid PrintVector(const vectorint v)
{// const对象使用const迭代器进行遍历打印vectorint::const_iterator it v.begin();while (it ! v.end()){cout *it ;it;}cout endl;
}void test_vector3()
{// 使用push_back插入4个数据vectorint v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);// 使用迭代器进行遍历打印vectorint::iterator it v.begin();while (it ! v.end()){cout *it ;it;}cout endl;// 使用迭代器进行修改it v.begin();while (it ! v.end()){*it * 2;it;}// 使用反向迭代器进行遍历再打印// vectorint::reverse_iterator rit v.rbegin();auto rit v.rbegin();while (rit ! v.rend()){cout *rit ;rit;}cout endl;PrintVector(v);
}3.范围for
void test1(const vectorint v)
{for (auto e : v){//只读cout e ;}cout endl;
}
void test_vector4()
{vectorint v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);for (auto e : v){//可读可写e;cout e ;}cout endl;test1(v);
}四、容量操作
容量空间接口说明size获取数据个数capacity获取容量大小empty判断是否为空resize重点改变vector的sizereserve 重点改变vector的capacity其中最重要的两个函数是 reserve 和 resizereserve 只用于扩容它不改变 size 的大小而 resize 是扩容加初始化既会改变 capacity也会改变 size 注意reserve 和 resize包括后面的 clear 函数都不会缩容因为缩容需要开辟新空间、拷贝数据、释放旧空间而对于自定义类型又有可能存在深拷贝问题时间开销极大vector 中唯一可能缩容的函数就只有 shrink_to_fit对于它来说如果 capacity 大于 size它会进行缩容让二者相等。
void test_vector5()
{vectorint v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);for (auto e : v){cout e ;}cout endl;cout v.size() endl;cout v.capacity() endl;v.resize(10, 1);for (auto e : v){cout e ;}cout endl;cout v.size() endl;cout v.capacity() endl;v.resize(3, 1);for (auto e : v){cout e ;}cout endl;cout v.size() endl;cout v.capacity() endl;v.reserve(10);for (auto e : v){cout e ;}cout endl;cout v.size() endl;cout v.capacity() endl;v.reserve(3);cout v.size() endl;cout v.capacity() endl;
}1.扩容机制 capacity的代码在vs和g下分别运行会发现vs下capacity是按1.5倍增长的g是按2倍增长的。具体增长多少是根据具体的需求定义的。vs是PJ版本STLg是SGI版本STL。 void test_vector6()
{size_t sz;vectorint 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;}}
}vs下: Linux的g下:
五、增删查改
vector增删查改接口说明push_back重点尾插pop_back 重点尾删find查找。注意这个是算法模块实现不是vector的成员接口insert在position之前插入valerase删除position位置的数据swap交换两个vector的数据空间
push_back和pop_back使用
void test_vector7()
{vectorint 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 find查找函数由算法库函数提供的一个函数模板使用时需要包含algorithm头文件。
void test2()
{vectorint v;v.push_back(10);v.push_back(20);v.push_back(30);v.push_back(40);v.push_back(50);vectorint::iterator pos find(v.begin(), v.end(), 30);//auto pos find(v.begin(), v.end(), 30);if (pos ! v.end()){cout 找到了 endl;cout pos - v.begin() endl;}else{cout 没找到 endl;}}insert和erase
void test_vector8()
{// 使用列表方式初始化C11新语法vectorint v{ 1, 2, 3, 4 };// 在指定位置前插入值为val的元素比如3之前插入30,如果没有则不插入// 1. 先使用find查找3所在位置// 注意vector没有提供find方法如果要查找只能使用STL提供的全局findauto pos find(v.begin(), v.end(), 3);if (pos ! v.end()){// 2. 在pos位置之前插入30v.insert(pos, 30);}vectorint::iterator it v.begin();while (it ! v.end()){cout *it ;it;}cout endl;pos find(v.begin(), v.end(), 3);// 删除pos位置的数据v.erase(pos);it v.begin();while (it ! v.end()) {cout *it ;it;}cout endl;
}swap 交换两个vector类对象的值。
void test_vector9()
{vectorint v{ 1, 2, 3, 4 };for (size_t i 0; i v.size(); i)cout v[i] ;cout endl;vectorint swapv;swapv.swap(v);cout v data:;for (size_t i 0; i v.size(); i)cout v[i] ;cout endl;cout swapv data:;for (auto e : swapv){cout e ;}cout endl;
}六、迭代器失效问题 迭代器的主要作用就是让算法能够不用关心底层数据结构其底层实际就是一个指针或者是对指针进行了封装比如vector的迭代器就是原生态指针T* 。因此迭代器失效实际就是迭代器底层对应指针所指向的空间被销毁了而使用一块已经被释放的空间造成的后果是程序崩溃(即如果继续使用已经失效的迭代器程序可能会崩溃)。 vector可能引起迭代器失效操作
1.会引起其底层空间改变的操作都有可能是迭代器失效比如resize、reserve、insert、assign、push_back等。
#includeiostream
#includevector
using namespace std;
int main()
{vectorint v{ 1,2,3,4,5,6 };auto it v.begin();// 将有效元素个数增加到100个多出的位置使用8填充操作期间底层会扩容//v.resize(100, 8);// reserve的作用就是改变扩容大小但不改变有效元素个数操作期间可能会引起底层容量改变//v.reserve(100);// 插入元素期间可能会引起扩容而导致原空间被释放//v.insert(v.begin(), 0);//v.push_back(8);// 给vector重新赋值可能会引起底层容量改变v.assign(100, 8);while (it ! v.end()){cout *it ;it;}cout endl;return 0;
}出错原因以上操作都有可能会导致vector扩容也就是说vector底层原理旧空间被释放掉而在打印时it还使用的是释放之间的旧空间在对it迭代器操作时实际操作的是一块已经被释放的空间而引起代码运行时崩溃。
解决方式在以上操作完成之后如果想要继续通过迭代器操作vector中的元素只需给it重新赋值即可。
it v.begin();while (it ! v.end()){cout *it ;it;}cout endl;2.指定位置元素的删除操作–erase
#include iostream
using namespace std;
#include vector
int main()
{int a[] { 1, 2, 3, 4 };vectorint v(a, a sizeof(a) / sizeof(int));// 使用find查找3所在位置的iteratorvectorint::iterator pos find(v.begin(), v.end(), 3);// 删除pos位置的数据导致pos迭代器失效。v.erase(pos);cout *pos endl; // 此处会导致非法访问return 0;
}erase删除pos位置元素后pos位置之后的元素会往前搬移没有导致底层空间的改变理论上讲迭代器不应该会失效但是如果pos刚好是最后一个元素删完之后pos刚好是end的位置而end位置是没有元素的那么pos就失效了。因此删除vector中任意位置上元素时vs就认为该位置迭代器失效了。
3.Linux下g编译器对迭代器失效的检测并不是非常严格处理也没有vs下极端
#includeiostream
#includevector
using namespace std;
// 1. 扩容之后迭代器已经失效了程序虽然可以运行但是运行结果已经不对了
int main()
{vectorint v{1,2,3,4,5};for(size_t i 0; i v.size(); i)cout v[i] ;cout endl;auto it v.begin();cout 扩容之前vector的容量为: v.capacity() endl;// 通过reserve将底层空间设置为100目的是为了让vector的迭代器失效v.reserve(100);cout 扩容之后vector的容量为: v.capacity() endl;// 经过上述reserve之后it迭代器肯定会失效在vs下程序就直接崩溃了但是linux下不会// 虽然可能运行但是输出的结果是不对的while(it ! v.end()){cout *it ;it;}cout endl;return 0;
}// 2. erase删除任意位置代码后linux下迭代器并没有失效
// 因为空间还是原来的空间后序元素往前搬移了it的位置还是有效的
#includeiostream
#include vector
#include algorithm
using namespace std;
int main()
{vectorint v{1,2,3,4,5};vectorint::iterator it find(v.begin(), v.end(), 3);v.erase(it);return 0;
}// 3: erase删除的迭代器如果是最后一个元素删除之后it已经超过end
// 此时迭代器是无效的it导致程序崩溃
#includeiostream
#includevector
using namespace std;
int main()
{vectorint v{1,2,3,4,5};// vectorint v{1,2,3,4,5,6};auto it v.begin();while(it ! v.end()){if(*it % 2 0)v.erase(it);it;}for(auto e : v)cout e ;cout endl;return 0;
}从上述三个例子中可以看到SGI STL中迭代器失效后代码并不一定会崩溃但是运行结果肯定不对如果it不在begin和end范围内肯定会崩溃的。
4.与vector类似string在插入扩容操作erase之后迭代器也会失效
#includeiostream
#include string
using namespace std;
void TestString()
{string s(hello);auto it s.begin();// 放开之后代码会崩溃因为resize到20会string会进行扩容// 扩容之后it指向之前旧空间已经被释放了该迭代器就失效了// 后序打印时再访问it指向的空间程序就会崩溃//s.resize(20, !);while (it ! s.end()){cout *it;it;}cout endl;it s.begin();while (it ! s.end()){it s.erase(it);// 按照下面方式写运行时程序会崩溃因为erase(it)之后// it位置的迭代器就失效了// s.erase(it);it;}
}
int main()
{TestString();return 0;
}迭代器失效解决办法在使用前对迭代器重新赋值即可,或者尽量避免使用传参给resize、reserve、insert、assign、push_back等迭代器。