厦门做网站培训,中国包装设计网,普陀集团网站建设,wordpress用户密码重置vector的介绍 文档介绍 vector是表示可变大小数组的序列容器。就像数组一样#xff0c;vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问#xff0c;和数组一样高效。但是又不像数组#xff0c;它的大小是可以动态改变的#xff0c;…vector的介绍 文档介绍 vector是表示可变大小数组的序列容器。就像数组一样vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问和数组一样高效。但是又不像数组它的大小是可以动态改变的而且它的大小会被容器自动处理。本质讲vector使用动态分配数组来存储它的元素。当新元素插入时候这个数组需要被重新分配大小为了增加存储空间。其做法是分配一个新的数组然后将全部元素移到这个数组。就时间而言这是一个相对代价高的任务因为每当一个新的元素加入到容器的时候vector并不会每次都重新分配大小。vector分配空间策略vector会分配一些额外的空间以适应可能的增长因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何重新分配都应该是对数增长的间隔大小以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。因此vector占用了更多的存储空间为了获得管理存储空间的能力并且以一种有效的方式动态增长。与其它动态序列容器相比deque, list and forward_list vector在访问元素的时候更加高效在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作效率更低。比起list和forward_list统一的迭代器和引用更好。 vector的使用
下面是对于vector的基本用法的讲解
vector的初始化
(constructor)构造函数声明接口说明vector()重点无参构造vectorsize_type n, const value_type val value_type()构造并初始化n个valvector (const vector x); 重点拷贝构造vector (InputIterator first, InputIterator last);使用迭代器进行初始化构造
主要使用的是无参构造和拷贝构造其他两种不常用下面代码一并介绍
void test1()
{//1.vector()重点 | 无参构造 vectorint v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);for (auto c : v1){cout c ;}cout endl;//2.vectorsize_type n, const value_type val value_type() | 构造并初始化n个valvectorint v2(10, 0);for (auto c : v2){cout c ;}cout endl;//3.vector(const vector x); 重点 | 拷贝构造 vectorint v3(v1);for (auto c : v3){cout c ;}cout endl;//4.vector(InputIterator first, InputIterator last);vectorint v4(v2.begin(), v2.end());for (auto c : v4){cout c ;}cout endl;
}
int main()
{test1();return 0;
}vector iterator迭代器的使用
vector的迭代器有两种正向和反向迭代器
正向begin() 和 end() 分别表示获取第一个数据的位置获取最后一个数据的下一个位置
反向rbegin() 和 rend() 分别表示获取最后一个数据的位置获取第一个元素的前一个位置
//迭代器的名称分别为 iterator 和reverse_iterator
void test2()
{vectorint v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);vectorint::iterator it v.begin();while (it ! v.end()){cout *it ;it;}cout endl;//auto ritv.rbegin();vectorint::reverse_iterator rit v.rbegin();while (rit ! v.rend()){cout *rit ;rit;}cout endl;for (auto c : v){cout c ;}cout endl;
}
int main()
{test2();return 0;
}vector 空间增长问题
使用几种函数来管理和查看vector的空间
容量空间接口说明size获取数据个数capacity获取容量大小empty判断是否为空resize改变vector的sizereserve改变vector的capacity
主要是对于resize和reserve的使用empty就是判别是否为空size和capacity是查看当前vector的数据个数和容量
void test3()
{vectorint v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);cout v.size() endl;cout v.capacity() endl;v.resize(20);cout 更改size为20 endl;cout v.size() endl;cout v.capacity() endl;v.reserve(40);cout 更改capacity为40 endl;cout v.size() endl;cout v.capacity() endl;v.resize(50);cout 更改size为50 endl;cout v.size() endl;cout v.capacity() endl;
}
void test4()
{vectorint v;size_t ans v.capacity();for (int i 0; i 200; i){v.push_back(i);if (ans ! v.capacity()){cout capacity为 ans endl ;}ans v.capacity();}
}int main()
{test4();return 0;
}注意capacity的增长倍数是由环境决定的vs下在1.5倍数左右在Linux下近乎2倍且关于resize和reserve我们只需要知道resize底层是调用reserve的满足sizecapacity
vector的增删改查
vector的增删改查接口说明push_back尾插pop_back尾删find查找指定的数据返回下标在算法模块不在vector的成员函数中insert在pos位置上插入指定数值valerase删除指定pos位置上的数据swap交换两个vector对象的数据空间operator[ ]和数组一样通过下标方括号来访问vector的数据
STL分为两大模块容器和算法容器例如vector、list、set等算法是在头文件algorithm中是将容器中通用的函数归档在algorithm中按照迭代器的不同不同容器能使用相同或不同的函数。
push_back 和 pop_back 以及operator[ ]的使用
简单理解不必做详解
void test5()
{vectorint v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);//push_back的使用传参val const value_type val value_type实际就是T 模板类for (auto c : v){cout c ;}cout endl;//pop_back 的使用不必传参尾删v.pop_back(); for (auto c : v){cout c ;}cout endl;//operator[]的使用 可以访问指定下标位置元素也可赋值cout v[2] endl;v[2] 10;cout v[2] endl;
}
int main()
{test5();return 0;
}find
在algorithm算法中InputIterator find (InputIterator first, InputIterator last, const T val);
#includealgorithm
void test6()
{vectorint v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);auto it find(v.begin(), v.end(), 5);if (it ! v.end()){cout *it endl;}else if(it v.end()){cout 没有找到val返回的是v.end() endl;}
}
int main()
{test6();return 0;
}insert
insert的插入实际上就是先得到要插入的数值个数n然后将vector中的元素后移n位然后依次填入插入的数据
void test7()
{vectorint v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);for (auto c : v){cout c ;}cout endl;//1.iterator insert (iterator position, const value_type val); auto itv.insert(v.begin() 1, 10);cout 返回迭代器指向的数值为 *it endl;for (auto c : v){cout c ;}cout endl;//2.void insert (iterator position, size_type n, const value_type val);v.insert(v.begin(), 5, 6);for (auto c : v){cout c ;}cout endl;//3.void insert(iterator position, InputIterator first, InputIterator last);v.insert(v.begin(), v.begin(), v.end());for (auto c : v){cout c ;}cout endl;vectorint v1; //后两个参数只要是迭代器即可可以是其他容器的迭代器数据插入过来v1.insert(v1.begin(), v.begin(), v.begin()6);for (auto c : v1){cout c ;}cout endl;}
int main()
{test7();return 0;
}erase
void test8()
{vectorint v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);//指定pos迭代器删除auto it v.erase(v.begin()); //返回的是删除之后的v.begin()cout *it endl;for (auto c : v){cout c ;}cout endl; //区间删除itv.erase(v.begin() 1, v.begin()2);cout *it endl; //返回的是删除之后的v.begin() 1 但是要注意越界问题for (auto c : v){cout c ;}cout endl;
}
int main()
{test8();return 0;
}迭代器失效
迭代器的主要作用就是让算法能够不用关心底层数据结构其底层实际就是一个指针或者是对指针进行了封装所以迭代器失效实际上就是迭代器底层对应指针所指向的空间被销毁了而使用一窥啊已经倍释放的空间当继续使用已经失效的迭代器会造成程序崩溃。 迭代器失效的情景 引起底层空间的改变都有可能是造成迭代器失效如resize、reserve、insert、push_back等。他们的同意特性就是会在底层调用reserve来判断增加元素时是否需要扩容。指定位置元素的删除操作erasepos 第一种场景统一导致迭代器失效的是由于增加元素或者手动扩容导致vector扩容然而扩容机制底层是新建一个T指针数组拷贝原有数据到新数组中然后释放原来的数组空间所以迭代器会失效此时的迭代器指向的是一块被释放的空间导致程序崩溃
void test9()
{vectorint v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);//底层的改变实际上就是是否扩容了//先获得当前vector的首元素的迭代器vectorint::iterator it v.begin(); cout *it endl;//1.如果经历了resize 触发扩容迭代器失效 代码为 -1073741819。//v.resize(50, 0);//cout *it endl;//2.如果使用reserve手动扩容的话也会导致迭代器失效//v.reserve(100);//cout *it endl; //代码为 -1073741819。//3.如果是插入元素导致扩容也会导致迭代器失效//v.insert(v.begin(), 100, 1);//cout *it endl; //代码为 -1073741819。//4.如果是push_back 导致扩容也会发生迭代器失效for (int i 0; i 100; i){v.push_back(i);}cout *it endl; //代码为 -1073741819。
}
int main()
{test9();return 0;
}第二种场景erase函数删除指定pos位置数据或者删除迭代器区间的数据。我们先用auto itv.begin()5获得迭代器然后我们删除一个元素删除之后有两种可能1.it指向的位置还有元素那么按照道理来说 cout一下还是能正常输出数值 2.it位置已经没有元素了此时it指向的空间已经是vector.end()之后了再次访问it的时候就会报错相当于越界了。
综合上述两种可能因此删除vector中任意位置上元素时vs就认为该位置迭代器失效了。
void test10()
{vectorint v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);auto it v.begin();v.erase(v.begin());//v.erase(v.begin(), v.end());cout *it endl; //代码为 -1073741819
}
int main()
{test10();return 0;
}迭代器失效解决办法在使用前对迭代器重新赋值即可。
总结
vector的优点
1.支持随机访问以[]的方式
2.cpu高速缓存效率高
vector的缺点
1.中间和头部删除元素效率低要移动数组元素
2.扩容问题扩容会导致迭代器失效 总结 vector的使用实际上大部分的函数与string中的用法相似我们只需要知道一点的是vector是一个可变长的连续有序序列即可不管是空间还是物理上数据是连续的。vector的初始的capacity的大小和初始化的数据个数有关然后依次为基点在VS平台以近似1.5倍扩容在Linux下以2倍扩容。在vector中我们初步认识到了**的存在这是算法包含在STL中STL分为容器和算法**中是总结所有容器所需要的接口通过迭代器来实现。不同的容器有不同的迭代器能实现不同的算法接口。迭代器失效问题是string以及vector在涉及到扩容或者erase中会发生的问题但是erase返回参数为iterator所以只需要再次赋值即可而扩容导致的迭代器失效我们只能再次对迭代器重新赋值取得新的迭代器。随用随取在使用前对迭代器重新赋值。综上我们可以通过vector不必顾忌数组的长度问题通过相应的便捷的接口来实现更多可能性的操作。