vector是C++库里自带的可变大小数组的序列容器,它的使用非常强大,像一把青龙偃月刀,不过在用它玩出花样之前,还是得先练成关羽一般的本事才行。
这篇文章会讲解vector的模拟实现,学习模拟实现是为了更加灵活地使用它,而且也是在准备面试过程中必不可少的一步。
前置注意事项:
(1)需要自己开一块命名空间,与STL库的vector进行区分,同时也是方便调试,如果不知道命名空间的小伙伴可看这篇文章
(2)需要了解模板相关的知识,简单理解就是类似typedef了一个类,可以取代任何数据类型
与之前的顺序表()类似,有size和capacity,不过C++有独特的表示方式,就是迭代器。
vector通过指向开头和结尾的迭代器来间接表示size,同时定义一个容量的结尾来表示capacity,同时提供对应的接口供用户使用,同时部分使用const返回值,避免被修改
namespace myvector
{
template<class T>
class vector
{
public:
typedef T* iterator;
typedef const T* const_iterator;
// 提供接口来访问
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
const_iterator cbegin() const
{
return _start;
}
const_iterator cend() const
{
return _finish;
}
size_t size() const
{
return _finish - _start;
}
size_t capacity() const
{
return _endOfStorage - _start;
}
private:
iterator _start; // 指向数据块的开始
iterator _finish; // 指向有效数据的尾
iterator _endOfStorage; // 指向存储容量的尾
};
}
这两个函数很容易混,前者是开空间,后者是开空间加赋值,还可以删除元素
先写这两个函数是因为后面很多的函数都会复用他们
void reserve(size_t n)
{
if (n > capacity())
{
T* tmp = new T[n];
size_t oldSize = size();
for (int i = 0; i < oldSize; i++)
{
tmp[i] = _start[i];
}
delete[] _start;
_start = tmp;
_finish = tmp + oldSize;
_endOfStorage = tmp + n;
}
}
void resize(size_t n, const T& value = T())
{
if (n > size())
{
reserve(n);
while(_finish < _start + n)
{
*_finish = value;
++_finish;
}
}
else
_finish = _start + n;
}
【以下为错误代码】
void reserse(int n)
{
if (n > (int)capacity())
{
size_t oldSize = size();
T* tmp = new T[n];
if (_start)//防止指针为空
{
//浅拷贝
memcpy(tmp,_start,sizof(T)*n)
delete[]_start;
}
_start = tmp;
_finish =_start + oldSize;
_endOfStorage = _start + n;
}
}
void insert(iterator pos, const T& x)
{
assert(pos >= _start);
assert(pos <= _finish);
if (_finish == _endOfStorage)
{
// reserve可能会改变_start的值,所以先记录一下插入的位置len
size_t len = pos - _start;
reserve(capacity() == 0 ? 4 : capacity() * 2);
pos = _start + len;
}
iterator it = _finish - 1;
// 依次插入
while (it >= pos)
{
*(it + 1) = *it;
it--;
}
*pos = x;
++_finish;
}
iterator erase(iterator pos)
{
assert(pos >= _start);
assert(pos < _finish);
iterator it = pos + 1;
while (it < _finish)
{
*(it - 1) = *it;
++it;
}
--_finish;
return pos;
}
void push_back(const T& x)
{
if (_finish == _endofstorage)
reserve(capacity() == 0 ? 4 : 2 * capacity());
*_finish = x;
_finish++;
}
void pop_back()
{
assert(size());
_finish--;
}
void push_back(const T& x)
{
insert(end(), x);
}
void pop_back()
{
erase(end() - 1);
}
包括无参构造函数、拷贝构造、迭代器构造等等
无参构造函数使用初始化列表初始化
vector()
:_start(nullptr)
, _finish(nullptr)
, _endofstorage(nullptr)
{}
vector(int n, const T& value = T())
{
// 这里的缺省值不能给0,因为传的参数可能为自定义类型或容器
reserve(n);
for (size_t i = 0; i < n; i++)
push_back(value);
}
vector(size_t n, const T& value = T())
{
// 这里的缺省值不能给0,因为传的参数可能为自定义类型或容器
reserve(n);
for (size_t i = 0; i < n; i++)
push_back(value);
}
template<class InputIterator>
vector(InputIterator first, InputIterator last)
{
while (first != last)
{
push_back(*first);
++first;
}
}
vector(const vector<T>& v)
{
reserve(v.capacity());
for (auto& e : v)
push_back(e);
}
// 析构
~vector()
{
delete[] _start;
_start = _finish = _endOfStorage = nullptr;
}
【注意点】
(1)这里的迭代器构造并不是直接使用 vector 的 iterator,而是使用模板迭代器,也就是说这里可以传其他容器的迭代器
(2)构造2函数的缺省值给的是默认无参构造,这个属于匿名对象,val是它的引用,所以相当于延长了它的生命周期;而匿名对象是临时变量,临时变量具有常性,所以需要用const修饰
(3)拷贝构造的范围for最好使用引用,避免当元素是容器和自定义变量时调用拷贝构造
(4)这里定义了 vector(size_t n, const T& value = T()) 和 vector(int n, const T& value = T())两个重载的函数,为了避免传两个整型时调用到迭代器构造去了
这里就相当于把reserve和push_back结合起来了
vector(const vector<T>& v)
:_start(nullptr)
, _finish(nullptr)
, _endofstorage(nullptr)
{
_start = new T[v.capacity()];
for (size_t i = 0; i < v.size(); i++)
{
_start[i] = v[i];
}
_finish = _start + v.size();
_endofstorage = _start + v.capacity();
}
T& operator[](size_t pos)
{
assert(pos < size());
return _start[pos];
}
const T& operator[](size_t pos)const
{
assert(pos < size());
return _start[pos];
}
vector<T>& operator=(const vector<T>& v)
{
if (this != &v) // 避免给自己赋值
{
delete[] _start;
_start = new T[v.capacity()];
for (size_t i = 0; i < v.size(); i++)
{
_start[i] = v[i];
}
_finish = _start + v.size();
_endofstorage = _start + v.capacity();
}
return *this; // 支持连续赋值
}
void swap(vector<T>& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_endOfStorage, v._endOfStorage);
}
vector<T>& operator= (vector<T> v)
{
swap(v);
return *this;
}
注意:这里的std::不能省略,否则就会就近调用这个swap函数
template<class T>
class vector
{
public:
typedef T* iterator;
typedef const T* const_iterator;
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
const_iterator cbegin() const
{
return _start;
}
const_iterator cend() const
{
return _finish;
}
// construct and destroy
vector()
:_start(nullptr)
, _finish(nullptr)
, _endofstorage(nullptr)
{}
vector(int n, const T& value = T())
{
reserve(n);
for (size_t i = 0; i < n; i++)
push_back(value);
}
template<class InputIterator>
vector(InputIterator first, InputIterator last)
{
while (first != last)
{
push_back(*first);
++first;
}
}
vector(const vector<T>& v)
{
reserve(v.capacity());
for (auto& e : v)
push_back(e);
}
vector<T>& operator= (vector<T> v)
{
swap(v);
return *this;
}
~vector()
{
delete[] _start;
_start = _finish = _endOfStorage = nullptr;
}
// capacity
size_t size() const
{
return _finish - _start;
}
size_t capacity() const
{
return _endOfStorage - _start;
}
void reserve(size_t n)
{
if (n > capacity())
{
T* tmp = new T[n];
size_t oldSize = size();
for (int i = 0; i < oldSize; i++)
{
tmp[i] = _start[i];
}
delete[] _start;
_start = tmp;
_finish = tmp + oldSize;
_endOfStorage = tmp + n;
}
}
void resize(size_t n, const T& value = T())
{
if (n > size())
{
reserve(n);
while(_finish < _start + n)
{
*_finish = value;
++_finish;
}
}
else
_finish = _start + n;
}
///access///
T& operator[](size_t pos)
{
assert(pos < size());
return _start[pos];
}
const T& operator[](size_t pos)const
{
assert(pos < size());
return _start[pos];
}
///modify/
void push_back(const T& x)
{
insert(end(), x);
}
void pop_back()
{
erase(end() - 1);
}
void swap(vector<T>& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_endOfStorage, v._endOfStorage);
}
void insert(iterator pos, const T& x)
{
assert(pos >= _start);
assert(pos <= _finish);
if (_finish == _endOfStorage)
{
size_t len = pos - _start;
reserve(capacity() == 0 ? 4 : capacity() * 2);
pos = _start + len;
}
iterator it = _finish - 1;
while (it >= pos)
{
*(it + 1) = *it;
it--;
}
*pos = x;
++_finish;
}
iterator erase(iterator pos)
{
assert(pos >= _start);
assert(pos < _finish);
iterator it = pos + 1;
while (it < _finish)
{
*(it - 1) = *it;
++it;
}
--_finish;
return pos;
}
private:
iterator _start;// 指向数据块的开始
iterator _finish; // 指向有效数据的尾
iterator _endOfStorage; // 指向存储容量的尾
};
如果感到有收获的话,不妨点个赞,感谢大家的支持!
因篇幅问题不能全部显示,请点此查看更多更全内容