目录
1. vector的介绍
2. vector的使用
2.1 构造函数
2.2 遍历方式
2.3 reserve与resize
2.4 shrink_to_fit
2.5 insert,erase,find
3. vector模拟实现
3.1 初始结构
3.2 析构函数
3.3 获取容量和元素个数
3.4 扩容reserve
3.5 resize改变有效个数并赋值val
3.6 方括号访问operator[]
3.7 迭代器
3.8 insert在pos前面插入
3.9 尾插push_back
3.10 erase删除pos位置的值
3.11 拷贝构造
3.12 赋值重载
3.13 用迭代器区间构造
3.14 用n个val构造
1. vector的介绍
vector是模板实现的。
Vectors are sequence containers representing arrays that can change in size.
2. vector的使用
使用上分几大部分:默认成员函数,迭代器,容量相关,访问相关,修改。
2.1 构造函数
void test1() { //无参 vector<int> v1; //有参 vector<int> v2(10); //val的缺省值是0。 vector<int> v3(10, 1); //迭代器 vector<int> v4(v3.begin(), v3.end()); //拷贝构造 vector<int> v5(v4); }
2.2 遍历方式
1. 下标加[ ],2. 迭代器,3. 范围for。
void test2() { vector<int> v(10, 5); //下标+[] for (size_t i = 0; i < v.size(); i++) { cout << v[i] << " "; } cout << endl; //迭代器 vector<int>::iterator it = v.begin(); while (it != v.end()) { cout << *it << " "; it++; } cout << endl; //范围for for (auto e : v) { cout << e << " "; } cout << endl; }
2.3 reserve与resize
reserve改变容量。
预先开空间就用reserve,容量改变,有效个数不变。
resize改变有效个数。
【区别】
【扩容机制】
vs:1.5倍扩容,g++:2倍扩容
2.4 shrink_to_fit
缩容:将容量缩到和有效个数一样。
一般是异地缩容。
2.5 insert,erase,find
(1)在pos位置的元素前面插入val。
(2)在pos位置的元素前面插入n个val。
(3)在pos位置的元素前面插入一段迭代器区间。
注意:传入的是迭代器。
找到pos的位置需要借助find,find在算法库里,容器通用。
find传的迭代器区间都是左闭右开,没找到就返回last。
删除某个位置或一段区间。
【结合用法】
void test3() { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); for (auto e : v) { cout << e << " "; } cout << endl; //头插 v.insert(v.begin(), 9); for (auto e : v) { cout << e << " "; } cout << endl; //在3前面插入6 vector<int>::iterator it1 = find(v.begin(), v.end(), 3); if (it1 != v.end()) { v.insert(it1, 6); } for (auto e : v) { cout << e << " "; } cout << endl; //把6删除 auto it2 = find(v.begin(), v.end(), 6); if (it2 != v.end()) { v.erase(it2); } for (auto e : v) { cout << e << " "; } cout << endl; }
vector官方文档:vector - C++ Reference (cplusplus.com)
3. vector模拟实现
3.1 初始结构
_start指向元素开始位置,_finish指向最后一个元素的下一个位置,_end指向最大容量的下一个位置。
namespace lyh { template<class T> class vector { public: typedef T* iterator; typedef const T* const_iterator; //无参构造 vector() {} private: iterator _begin = nullptr; //元素开始位置。 iterator _end = nullptr; //元素末尾的下一个位置。 iterator _capacity = nullptr; //最大容量的下一个位置。 }; }
3.2 析构函数
释放空间,指针置空。
~vector() { delete[] _begin; _begin = nullptr; _end = nullptr; _capacity = nullptr; }
3.3 获取容量和元素个数
利用指针相减。
size_t size() const { return _end - _begin; } size_t capacity() const { return _capacity - _begin; }
3.4 扩容reserve
n小于容量不用管,n大于容量才扩容。
新开一个大空间,拷贝数据,释放原空间,更新成员变量的指向。
memcpy是浅拷贝,这里用赋值重载才能完成深拷贝,内置类型就浅拷贝,自定义类型就调用自己的赋值重载。
void reserve(size_t n) { if (n > capacity()) { size_t sz = size(); T* tmp = new T[n]; //原空间有数据才需要拷贝。 if (_begin) { for (size_t i = 0; i < sz; i++) { tmp[i] = _begin[i]; } //释放原空间。 delete[] _begin; } //更新成员指向。 _begin = tmp; _end = tmp + sz; _capacity = tmp + n; } }
3.5 resize改变有效个数并赋值val
改变有效个数有三种情况。
小于原先size就缩小。
大于size就交给reserve判断要不要扩容,然后不断尾插直到n。
void resize(size_t n, const T& val = T()) { if (n <= size()) { _end = _start + n; } else { reserve(n); while (_end < _begin + n) { *_end = val; ++_end; } } }
3.6 方括号访问operator[]
需要断言传入的下标是否合法,返回下标对应的元素的别名。可以提供const版本,可以访问但不能修改。
T& operator[](size_t pos) { assert(pos < size()); return _begin[pos]; } const T& operator[](size_t pos) const { assert(pos < size()); return _begin[pos]; }
3.7 迭代器
begin指向第一个位置,end指向最后一个位置的下一个。可以提供const版本。
iterator begin() { return _begin; } iterator end() { return _end; } const_iterator begin() const { return _begin; } const_iterator end() const { return _end; }
3.8 insert在pos前面插入
先断言pos在合法范围,再判断是否需要扩容,然后pos位置开始往后挪给pos腾出空间插入。
扩容是异地扩容除了更新原本的成员变量指向还需更新pos的指向,不然pos会变成野指针也就是迭代器失效。
void insert(iterator pos, const T& val) { assert(pos >= _begin && pos <= _end); if (_end == _capacity) { size_t len = pos - _begin; reserve(capacity() == 0 ? 4 : capacity() * 2); pos = _begin + len; } iterator key = _end; while (key > pos) { _start[key] = _start[key - 1]; --key } *key = val; ++_end; }
3.9 尾插push_back
复用insert
void push_back(const T& val) { insert(end(), val); }
3.10 erase删除pos位置的值
先断言pos是否合法,然后将pos之后的位置往前移。
erase之后认为迭代器失效,不能访问。
返回的迭代器指向原本删除元素的下一个元素。
An iterator pointing to the new location of the element that followed the last element erased by the function call.
iterator erase(iterator pos) { assert(pos >= _begin && pos < _end); iterator key = pos + 1; while (key < _end) { *(key-1) = *key; ++key; } --_end; return pos; }
3.11 拷贝构造
先开一个和v一样大的空间,再把v的元素拷贝过来(遍历尾插)。
vector(const vector<T>& v) { reserve(v.capacity()); for (auto& e : v) { push_back(e); } }
3.12 赋值重载
假设v3 = v1,将v1传值拷贝构造给tmp,v3和tmp交换。先拷贝构造给了形参再和形参交换。
void swap(vector<T>& tmp) { std::swap(_begin, tmp._begin); std::swap(_end, tmp._end); std::swap(_capacity, tmp._capacity); } vector<T>& operator=(vector<T> tmp) { swap(tmp); return *this; }
3.13 用迭代器区间构造
当begin不等于end就不断尾插。
vector(InputIterator begin, InputIterator end) { while (begin != end) { push_back(*begin); ++begin; } }
3.14 用n个val构造
复用用resize。
vector(size_t n, const T& val = T()) { resize(n, val); }
Vector/Vector · 林宇恒/code-cpp - 码云 - 开源中国 (gitee.com)