【落羽的落羽 C++】vector
文章目录
- 一、vector类介绍
- 二、vector中的常用接口
- 三、迭代器失效问题
- 四、vector的使用实例
- 五、vector模拟实现
一、vector类介绍
vector是STL中的一种容器,本质上是顺序表。它和string类的结构很相似,其也有size、capacity、数组等,不同的是string底层只是字符数组,而vector类的底层是可以存储所有数据类型的数组。有了string的经验,我们理解vector就更轻松了。
vector实际上是一个类模板,在使用时,我们需要根据实际要存储的数据类型用<>表明,如vector<int> v1; vector<char> v2; vector<string> v3;
等等
tip:
vector<char>
和string
看起来似乎没什么区别,但是string会在字符串后自动加\0,而前者不会,同时string中也有一些针对字符串的特殊操作也是vector中没有的。实际中根据我们的需求来选择使用。
二、vector中的常用接口
vector的接口和string中几乎完全一样,使用方法也类似,就简单介绍一下:
vector成员 | 接口说明 |
---|---|
size | 获取数据个数 |
capacity | 获取空间容量大小 |
resize | 改变vector的size |
reserve | 改变vector的capacity |
begin | 获取第一个数据的迭代器iterator/const_iterator |
end | 获取最后一个数据的下一个位置的迭代器iterator/const_iterator |
push_back | 尾部插入数据 |
pop_back | 尾部删除数据 |
insert | 插入数据 |
erase | 删除数据 |
swap | 交换两个vector的数据空间 |
operator[] | 使能像数组一样访问vector存储的数据 |
简单演示:
三、迭代器失效问题
迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际上就是一个指针,或者是对指针进行了封装,比如vector<T>
的迭代器就是原生态指针T*。因此迭代器失效就是迭代器底层对应指针所指向的空间被销毁了,类似野指针的道理,使用可能会造成程序崩溃。对于vector,可能会导致其迭代器失效的操作有:resize、reserve、insert、assign、push_back,这些操作可能会进行扩容操作,vector底层旧空间被释放而开辟了一块新空间,则指向旧空间的迭代器就失效了。因此,在以上操作完成之后,如果还想要通过迭代器操作vector中的元素,需要给迭代器重新赋值。举个例子:
#include<iostream>
#include<vector>
using namespace std;
int main()
{vector<int> v = { 1, 2, 3, 4, 5 };vector<int>::iterator it = v.begin();//将有效元素个数调整至10个,多出的位置用0填充,这个操作底层会进行扩容v.resize(10, 0);//此时原来的迭代器it失效,使用程序会崩溃cout << *it;return 0;
}
#include<iostream>
#include<vector>
using namespace std;
int main()
{vector<int> v = { 1, 2, 3, 4, 5 };vector<int>::iterator it = v.begin();//将有效元素个数调整至10个,多出的位置用0填充,这个操作底层会进行扩容v.resize(10, 0);//此时原来的迭代器it失效,使用程序会崩溃//cout << *it;//给it重新赋值就能解决it = v.begin();while(it != v.end()){cout << *it << ' ';it++;}cout << endl;return 0;
}
除此之外,erase操作也会导致迭代器失效,erase删除pos位置数据后,pos位置之后的元素会往前挪动,没有造成底层空间的改变,理论上迭代器不会失效。但是如果pos位置刚好是最后一个数据,删完之后pos刚好是end的位置,而end位置是没有数据的,那么pos就失效了。因此在VS下,只要使用erase操作后,VS就认为该位置迭代器失效了。解决办法也是一样,重新赋值。
VS对迭代器失效的检查比较严格,程序会直接崩溃。而Linux下g++编译器对迭代器失效的检测较为宽松,程序可能可以运行,但是结果也会出错。
四、vector的使用实例
力扣题目:杨辉三角
杨辉三角想必大家都不陌生,如果想要生成杨慧三角的前numRows行,用vector来实现就很方便了,我们可以定义出vector<vector<int>>
的结构,表示它存储的数据类型是vector<int>
,模拟出杨辉三角的结构:
vector<vector<int>> generate(int numRows)
{vector<vector<int>> vv;vv.resize(numRows);//将每一个元素都初始化成1for(int i = 0; i < vv.size(); i++){vv[i].resize(i+1, 1);}//遍历赋值for(int i = 2; i < numRows; i++){for(int j = 1; j < i; j++){vv[i][j] = vv[i-1][j] + vv[i-1][j-1];}}return vv;
}
结果没有问题
五、vector模拟实现
在我的vector.h中:
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
namespace lydly
{template<class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}vector(){}vector(size_t n, const T& val = T()){reserve(n);for (size_t i = 0; i < n; i++){push_back(val);}}//利用迭代器区间构造template<class InputIterator>vector(InputIterator first, InputIterator last){while (first != last){push_back(*first);first++;}}//使我们可以用{}初始化vector(initializer_list<T> il){reserve(il.size());for (auto& e : il){push_back(e);}}vector(const vector<T>& v){reserve(v.capacity());for (auto& e : v){push_back(e);}}//利用std库中的swap算法void swap(vector<T>& v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_end_of_storage, v._end_of_storage);}vector<T>& operator=(vector<T> v){swap(v);return *this;}~vector(){if (_start){delete[] _start;_start = _finish = _end_of_storage = nullptr;}}size_t capacity() const{return _end_of_storage - _start;}size_t size() const{return _finish - _start;}T& operator[](size_t i){assert(i < size());return _start[i];}void resize(size_t n, T val = T()){if (n > size()){reserve(n);}while (_finish != _start + n){*_finish = val;_finish++;}}void reserve(size_t n){if (n > capacity()){size_t old_size = size();T* tmp = new T[n];if (_start){//深拷贝for (size_t i = 0; i < old_size; i++){tmp[i] = _start[i];}delete[] _start;}_start = tmp;_finish = _start + old_size;_end_of_storage = _start + n;}}void push_back(const T& x){if (_finish == _end_of_storage){size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity);}*_finish = x;_finish++;}void pop_back(){assert(_finish > _start);_finish--;}iterator insert(iterator pos, const T& x){assert(pos >= _start && pos <= _finish);if (_finish == _end_of_storage){size_t len = pos - _start;size_t newcapacity = capacity() == 0 ? 4 : capacity * 2;reserve(newcapacity);pos = _start + pos;}//pos后的数据往后挪一个位置iterator it = _finish - 1;while (it >= pos){*(it + 1) = *it;it--;}*pos = x;_finish++;return pos;}iterator erase(iterator pos){assert(pos >= _start && pos < _finish);//pos后的数据往前挪一个位置iterator it = pos + 1;while (it < _finish){*(it - 1) = *it;it++;}_finish--;return pos;}private:iterator _start = nullptr;iterator _finish = nullptr;iterator _end_of_storage = nullptr;};
}
简单测试:
本篇完,感谢阅读。