讨论顺序表
- C++中的`vector`
- 模拟实现
- 成员变量
- 尾插数据`push_back`
- 扩容`reserve`
- 构造函数和析构函数
- 拷贝构造函数
- 指定位置插入数据
- 指定位置删除数据
- 迭代器失效
- 完整代码
C++中,
vector
是可以改变大小的数组的序列容器。可以看做底层就是一个数组,容量满时扩容。
C++中的vector
- C++标准库中的
vector
是个模板类,可以存放不同数据类型的数据。
vector<int> v1;
vector<string> v2;
vector<double> v3;
vector<vector<int>> v4;
模拟实现
成员变量
-
采用底层是数组模拟实现
vector
,参考stl_vector
源码 -
protected: typedef simple_alloc<value_type, Alloc> data_allocator; iterator start; iterator finish; iterator end_of_storage;
-
使用指针指向数组起始位置,结束位置下一个以及容量位置。
template<class T>
class vector {
private:
iterator _first;
iterator _finish;
iterator _end_of_storage;
};
尾插数据push_back
扩容reserve
- 插入数据,首先还是需要判断容量是否满足条件。
_finish == _end_of_storage
即容量已满,需要扩容。 - 防止浅拷贝,就不能拷贝地址空间,需要再次动态申请空间。
void reserve(size_t n) {
if(n > capacity()) {
T* tmp = new T[n];
size_t len = size();
if(_first) {
for (size_t i = 0; i < len; ++i) {
tmp[i] = _first[i];
}
delete[] _first;
}
_first = tmp;
_finish = _first + len;
_end_of_storage = _first + n;
}
}
void push_back(const T& val) {
// 判断扩容
if(_finish == _end_of_storage) {
reserve(capacity() == 0 ? 5 : 2 * capacity());
}
*_finish = val;
++_finish;
}
构造函数和析构函数
- 针对初始化
n
个元素的构造函数,可以复用尾插push_back
函数。
vector() {}
vector(size_t n, const T &val = T()) {
reserve(n);
for (size_t i = 0; i < n; ++i) {
push_back(val);
}
}
- 析构函数只需要释放
_first
所指向的空间即可。
~vector() {
delete[] _first;
_first = _finish = _end_of_storage = nullptr;
}
拷贝构造函数
- 同样复用尾插
push_back
即可。
vector(const vector<T> &v) {
reserve(v.capacity());
for (auto &e: v) {
push_back(e);
}
}
- 赋值构造。
vector<T> &operator=(vector<T> tmp) {
swap(tmp);
return *this;
}
- 迭代器构造函数
template<class InputIterator>
vector(InputIterator first, InputIterator last) {
while(first != last) {
push_back(*first);
++first;
}
}
指定位置插入数据
- 指定位置插入数据不仅要判断容量,还需要判断位置是否满足要求,需要在
_first
和_finish
之间。
iterator insert(iterator pos, const T &x) {
assert(pos >= _first);
assert(pos <= _finish);
// 判断容量
if (_finish == _end_of_storage) {
size_t len = pos - _first;
reserve(capacity() == 0 ? 5 : 2 * capacity());
pos = _first + len; // 防止异地扩容时,pos位置失效
}
iterator end = _finish - 1;
while (end >= pos) {
*(end + 1) = *end;
--end;
}
*pos = x;
++_finish;
return pos;
}
指定位置删除数据
iterator erase(iterator pos) {
assert(pos >= _first);
assert(pos < _finish);
iterator start = pos;
while (start < _finish - 1) {
*start = *(start + 1);
++start;
}
--_finish;
return pos;
}
迭代器失效
- 在特定位置插入或者删除元素时,都有可能造成迭代器失效。
- 如在插入数据时,如果不对
pos
位置做检查,异地扩容后还在原有pos
位置插入数据,则数据无效,因此需要重新检查pos
位置是否有效。 - 而在删除元素时,如果循环删除特定数据,随着元素的移动,迭代器也会失效导致结果不正确,因此在编写指定位置删除数据的代码时,设定返回删除数据下一个位置的迭代器,来解决迭代器失效问题。
max::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(2);
v.push_back(3);
v.push_back(9);
v.push_back(6);
auto it = v.begin();
while(it != v.end()) {
if(*it % 2 == 0) {
it = v.erase(it);
} else {
++it;
}
}
for(int n : v) {
cout << n << " ";
}
cout << endl;
完整代码
namespace max {
template<class T>
class vector {
public:
typedef T *iterator;
typedef const T *const_iterator;
vector() {}
vector(size_t n, const T &val = T()) {
reserve(n);
for (size_t i = 0; i < n; ++i) {
push_back(val);
}
}
vector(int n, const T &val = T()) {
reserve(n);
for (int i = 0; i < n; ++i) {
push_back(val);
}
}
template<class InputIterator>
vector(InputIterator first, InputIterator last) {
while(first != last) {
push_back(*first);
++first;
}
}
void swap(vector<T> &v) {
std::swap(_first, v._first);
std::swap(_finish, v._finish);
std::swap(_end_of_storage, v._end_of_storage);
}
vector(const vector<T> &v) {
reserve(v.capacity());
for (auto &e: v) {
push_back(e);
}
}
vector<T> &operator=(vector<T> tmp) {
swap(tmp);
return *this;
}
~vector() {
delete[] _first;
_first = _finish = _end_of_storage = nullptr;
}
iterator begin() {
return _first;
}
iterator end() {
return _finish;
}
const_iterator begin() const {
return _first;
}
const_iterator end() const {
return _finish;
}
void resize(size_t n, const T &val = T()) {
if(n <= size()) {
_finish = _first - n;
} else {
reserve(n);
while(_finish < _first + n) {
*_finish = val;
++_finish;
}
}
}
void reserve(size_t n) {
if (n > capacity()) {
T *tmp = new T[n];
size_t len = size();
if (_first) {
for (size_t i = 0; i < len; ++i) {
tmp[i] = _first[i];
}
delete[] _first;
}
_first = tmp;
_finish = _first + len;
_end_of_storage = _first + n;
}
}
void push_back(const T &val) {
// 判断扩容
if (_finish == _end_of_storage) {
reserve(capacity() == 0 ? 5 : 2 * capacity());
}
*_finish = val;
++_finish;
}
void pop_back() {
assert(size() >= 0);
--_finish;
}
iterator insert(iterator pos, const T &x) {
assert(pos >= _first);
assert(pos <= _finish);
// 判断容量
if (_finish == _end_of_storage) {
size_t len = pos - _first;
reserve(capacity() == 0 ? 5 : 2 * capacity());
pos = _first + len; // 防止异地扩容时,pos位置失效
}
iterator end = _finish - 1;
while (end >= pos) {
*(end + 1) = *end;
--end;
}
*pos = x;
++_finish;
return pos;
}
iterator erase(iterator pos) {
assert(pos >= _first);
assert(pos < _finish);
iterator start = pos;
while (start < _finish - 1) {
*start = *(start + 1);
++start;
}
--_finish;
return pos;
}
T &operator[](size_t pos) {
return _first[pos];
}
const T &operator[](size_t pos) const {
return _first[pos];
}
size_t size() const {
return _finish - _first;
}
size_t capacity() const {
return _end_of_storage - _first;
}
private:
iterator _first = nullptr;
iterator _finish = nullptr;
iterator _end_of_storage = nullptr;
};
}