先看一下官方文档中对构造函数是怎么描述的。
default | explicit vector (const allocator_type& alloc = allocator_type()); |
无参构造 |
---|---|---|
fill | explicit vector (size_type n, const value_type& val = value_type(), const allocator_type& alloc = allocator_type()); |
构造并且初始化n个val |
range | template |
利用迭代器构造 |
copy | vector (const vector& x); |
拷贝构造 |
这里的allocator
什么的表示内存池,能够更快的申请空间,这次的实现就不实现内存池了,直接new
。
首先要先声明自己的命名空间
namespace mudan
{
class vector
{
};
}
为什么这里我叫mudan
呢?因为我媳妇叫牡丹,哈哈哈~
然后可以看到参数当中有很多都是没有听过的,一般都是typedef
的,可以去查一下Member types
可以看到iterator
其实就是模板T
。
namespace mudan
{
template<class T>
class vector
{
public:
typedef T* iterator;
private:
iterator _start;//起始位置
iterator _finish;//最后一个元素的后一个位置
iterator _end_of_capacity;//整个容器的最后一个位置的下一个位置
};
}
成员定义好了就该实现构造函数了。
vector()
:_start(nullptr)
,_finish(nullptr)
,_end_of_capacity(nullptr)
{}
//区间构造函数
template<class InputIterator>
vector(InputIterator first, InputIterator last)
:_start(nullptr)
,_finish(nullptr)
,_end_of_capacity(nullptr)
{
while (first != last)
{
push_back(*first);
first++;
}
}
~vector()
{
delete[] _start;
_finish = nullptr;
_end_of_capacity = nullptr;
}
直接初始化为nullptr
即可,因为随机的空间是不能被操作的。
可以看到初始化成功了。
然后就可以开始尝试实现push_back
函数了。
而这里要实现push_back
分为几种情况
1.原来的空间为
nullptr
就需要分配内存空间,一般先分配四个大小的空间2.空间不够需要扩容,一般扩大到原空间的两倍较为合适
3.直接添加元素
这里需要扩容就需要实现一下reserve
函数了。
而在reserve
函数当中需要得知当前的容量大小,因此,可以实现一下size()
和capacity()
。
size_t size()
{
return (_finish-_start);
}
size_t capacity()
{
return (_end_of_capacity-_start);
}
void reserve(size_t n)
{
if (n > capacity())
{
T* tmp = new T[n];//开辟一个n个大小的空间
if (_start)
{
memcpy(tmp, _start, sizeof(T) * capacity());//将原来空间的内容拷贝过来
}
delete[] _start;
}
_start = tmp;
_finish = _start + sz;
_end_of_capacity = _start + n;
}
void push_back(const T &val)
{
if (_finish == _end_of_capacity)
{
reserve(capacity() == 0 ? 4 : 2 * capacity());
}
*_finish = val;
++_finish;
}
好了,现在可以简单的测试一下程序对不对了。
开搞!!!
咦,程序怎么崩溃了?还是报的空指针问题?
通过调试可以发现问题发生在扩容这里了。
程序走到这里都是很正常的,空间也都开辟了
但走到下一步的时候,size()
传回的值确实一个超级大的数字,这是为啥?
因为_start
确实有空间了,但是_finish
还没有啊,而size()
的实现方式是通过_finish-_start
所得到的,当然会出现问题,所以这里问题就出现在size()
上了。
解决方法就是提前算好size()
的大小。
void reserve(size_t n)
{
size_t sz = size();
if (n > capacity())
{
T* tmp = new T[n];//开辟一个n个大小的空间
if (_start)
{
memcpy(tmp, _start, sizeof(T) * sz);//将原来空间的内容拷贝过来
}
delete[] _start;
_start = tmp;
_finish = _start + sz;
_end_of_capacity = _start + n;
}
}
为了进一步验证正确性,实现一下operator[]
reference
就是T&
T& operator[](size_t pos)
{
assert(pos < size());
assert(pos >= 0);
return _start[pos];
}
const T& operator[](size_t pos)const
{
assert(pos < size());
assert(pos >= 0);
return _start[pos];
}
为什么库里要实现两个operator[]
?
因为有时候传过来的是const
类型,因为返回是引用类型,所以会有权限的放大的问题,因此const
对应const
的operator
就可以了。
可以看到程序是正常运行的。
void pop_back()
{
_finish--;
}
为了支持范围for
,实现一个begin()
和end()
,因为范围for
是很简单的替换,只认begin()
和end()
。
const_iterator begin()const
{
return _start;
}
const_iterator end()const
{
return _finish;
}
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
然后就是利用迭代器进行遍历
如果这里的iterator
不是在public
当中typedef
的就会报错,因为会受到访问限定符的约束。
在position
位置之前插入一个val
。
根据以前实现的顺序表可以知道,如果要在1 2 3 4 5 6
当中的3
之前插入一个520
,需要将3 4 5 6
全都往后挪动一个位置,空出一个位置给520
–>1 2 520 3 4 5 6
。
void insert(iterator pos, const T& val)
{
assert(pos >= _start);
assert(pos <= _finish);
if (_finish == _end_of_capacity)
{
reserve(capacity() == 0 ? 4 : 2 * capacity());
}
iterator end = _finish - 1;
while (end >= pos)
{
*(end + 1) = *end;
end--;
}
*pos = val;
++_finish;
}
为了测试代码的正确性,可以测试一下这个程序------>在所有的偶数之前插入一个当前偶数的二倍。
但走着走着怎么程序就挂掉了呢?并且出现了随机数。
其实跟着之前的代码走一遍就知道哪里出错了。
首先,第一个问题就是it
没有++
会导致一直都是在第二个位置进行插入,再一个问题就是当容量不够的时候是需要扩容的,这里的扩容不是原地扩容,所以会导致野指针的问题,即pos
的指向已经不是原来的内容了。
我们回到库当中的insert
的定义:
可以看到还给了一个迭代器版本的insert
,这里就可以利用这个迭代器版本的insert
的返回值来更新it
,让it
动起来并且会更新it
的地址,当遇到不是偶数的时候直接++
即可,返回值就是更新后的pos
位置,为了防止迭代器失效可以在每次扩容之后更新一下pos
的位置,不过要先计算好pos
位置离_start
的距离是多少。
iterator insert(iterator pos, const T& val)
{
assert(pos >= _start);
assert(pos <= _finish);
if (_finish == _end_of_capacity)
{
size_t len = pos - _start;
reserve(capacity() == 0 ? 4 : 2 * capacity());
pos = _start + len;//更新迭代器位置,防止迭代器失效
}
iterator end = _finish - 1;
while (end >= pos)
{
*(end + 1) = *end;
end--;
}
*pos = val;
++_finish;
return pos+1;
}
======================================================================================
while (it != arr.end())
{
if ((*it) % 2 == 0)
{
it=arr.insert(it, (*it) * 2);
}
it++;
}
for (auto e : arr)
{
cout << e << " ";
}
目前来看都是正常的。
然后就是实现一下erase
了。
erase()
也是和之前写过的顺序表一样,直接向前覆盖就行了。
假如要实现一个删除所有奇数的程序,利用erase()
实现:
iterator erase(iterator pos)
{
assert(pos >= _start);
assert(pos <_finish);
iterator begin = pos + 1;
while (begin < _finish)
{
*(begin - 1) = *begin;
begin++;
}
--_finish;
return pos;
}
vector<T>& operator=(const vector<T> v)
{
swap(v);
return *this;
}
void swap(vector<T>& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_end_of_capacity, v._end_of_capacity);
}
T& front()
{
assert(size() > 0);
return *_start;
}
T& back()
{
assert(size() > 0);
return *(_finish - 1);
}
void resize(size_t n,const T&val=T())
{
if (n > capacity())
{
reserve(n);//大于直接扩容
}
if (n > size())
{
//初始化并且填上值
while (_finish < _start + n)
{
*_finish = val;
++_finish;
}
}
else
{
_finish = _start + n;
}
}
现在,vector
的常用接口基本都实现好了,做一道杨辉三角的题目试试。
class Solution {
public:
vector<vector<int>> generate(int numRows) {
vector<vector<int>> ret(numRows);
for (int i = 0; i < numRows; ++i) {
ret[i].resize(i + 1);
ret[i][0] = ret[i][i] = 1;
for (int j = 1; j < i; ++j) {
ret[i][j] = ret[i - 1][j] + ret[i - 1][j - 1];
}
}
return ret;
}
};
这是使用官方的库实现的。
但使用我们自己的突然程序就崩溃了。
可以看到,是在析构函数崩溃的,可以先猜想,是不是因为同一块内存空间析构了两次导致的呢?
这里的第二个_start
是浅拷贝。
等_start
析构完了,tmp
也变成也指针了,但最后tmp
还要析构一次,所以会导致一块内存析构两次的结果。
void reserve(size_t n)
{
if (n > capacity())
{
size_t oldSize = size();
T* tmp = new T[n];
if (_start)
{
//memcpy(tmp, _start, sizeof(T)*oldSize);
for (size_t i = 0; i < oldSize; ++i)
{
tmp[i] = _start[i];
}
delete[] _start;
}
_start = tmp;
_finish = tmp + oldSize;
_end_of_capacity = _start + n;
}
}
最后发现还是跑不了,靠,原来是忘记写拷贝构造了,默认的浅拷贝还是会导致同一块内存析构两次。
vector(const vector<T>& v)
:_start(nullptr)
, _finish(nullptr)
, _end_of_capacity(nullptr)
{
vector<T> tmp(v.begin(), v.end());
swap(tmp);
}
template<class InputIterator>
vector(InputIterator first, InputIterator last)
: _start(nullptr)
, _finish(nullptr)
, _end_of_capacity(nullptr)
{
while (first != last)
{
push_back(*first);
first++;
}
}
vector(size_t n, const T& val = T())
:_start(nullptr)
,_finish(nullptr)
,_end_of_capacity(nullptr)
{
reserve(n);
for (size_t i = 0; i < n; ++i)
{
push_back(val);
}
}
vector(int n, const T& val = T())
:_start(nullptr)
, _finish(nullptr)
, _end_of_capacity(nullptr)
{
reserve(n);
for (int i = 0; i < n; ++i)
{
push_back(val);
}
}
现在程序就没啥问题咯。
#pragma once
#include
#include
#include
using namespace std;
namespace mudan
{
template<class T>
class vector
{
public:
typedef T* iterator;
typedef const T* const_iterator;
//默认构造函数
vector()
:_start(nullptr)
, _finish(nullptr)
, _end_of_capacity(nullptr)
{}
template<class InputIterator>
vector(InputIterator first, InputIterator last)
: _start(nullptr)
, _finish(nullptr)
, _end_of_capacity(nullptr)
{
while (first != last)
{
push_back(*first);
first++;
}
}
vector(size_t n, const T& val = T())
:_start(nullptr)
,_finish(nullptr)
,_end_of_capacity(nullptr)
{
reserve(n);
for (size_t i = 0; i < n; ++i)
{
push_back(val);
}
}
vector(int n, const T& val = T())
:_start(nullptr)
, _finish(nullptr)
, _end_of_capacity(nullptr)
{
reserve(n);
for (int i = 0; i < n; ++i)
{
push_back(val);
}
}
vector(const vector<T>& v)
:_start(nullptr)
, _finish(nullptr)
, _end_of_capacity(nullptr)
{
vector<T> tmp(v.begin(), v.end());
swap(tmp);
}
//析构函数
~vector()
{
delete[] _start;
_finish = nullptr;
_end_of_capacity = nullptr;
}
size_t size()
{
return (_finish - _start);
}
size_t capacity()
{
return (_end_of_capacity - _start);
}
const_iterator begin()const
{
return _start;
}
const_iterator end()const
{
return _finish;
}
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
void reserve(size_t n)
{
if (n > capacity())
{
size_t oldSize = size();
T* tmp = new T[n];
if (_start)
{
//memcpy(tmp, _start, sizeof(T)*oldSize);
for (size_t i = 0; i < oldSize; ++i)
{
tmp[i] = _start[i];
}
delete[] _start;
}
_start = tmp;
_finish = tmp + oldSize;
_end_of_capacity = _start + n;
}
}
void push_back(const T &val)
{
if (_finish == _end_of_capacity)
{
reserve(capacity() == 0 ? 4 : 2 * capacity());
}
*_finish = val;
++_finish;
}
void pop_back()
{
_finish--;
}
iterator insert(iterator pos, const T& val)
{
assert(pos >= _start);
assert(pos < _finish);
if (_finish == _end_of_capacity)
{
size_t len = pos - _start;
reserve(capacity() == 0 ? 4 : 2 * capacity());
pos = _start + len;
}
iterator end = _finish - 1;
while (end >= pos)
{
*(end + 1) = *end;
end--;
}
*pos = val;
++_finish;
return pos+1;
}
iterator erase(iterator pos)
{
assert(pos >= _start);
assert(pos < _finish);
iterator begin = pos + 1;
while (begin < _finish)
{
*(begin - 1) = *begin;
begin++;
}
--_finish;
return pos;
}
T& operator[](size_t pos)
{
assert(pos < size());
return _start[pos];
}
const T& operator[](size_t pos) const
{
assert(pos < size());
return _start[pos];
}
T& front()
{
assert(size() > 0);
return *_start;
}
T& back()
{
assert(size() > 0);
return *(_finish - 1);
}
void swap(vector<T>& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_end_of_capacity, v._end_of_capacity);
}
vector<T>& operator=(vector<T> v)
{
swap(v);
return *this;
}
void resize(size_t n, T val = T())
{
if (n > capacity())
{
reserve(n);
}
if (n > size())
{
while (_finish < _start + n)
{
*_finish = val;
++_finish;
}
}
else
{
_finish = _start + n;
}
}
private:
iterator _start;//起始位置
iterator _finish;//最后一个元素的后一个位置
iterator _end_of_capacity;//整个容器的最后一个位置的下一个位置
};
class Solution {
public:
vector<vector<int>> generate(int numRows) {
vector<vector<int>> vv;
vv.resize(numRows, vector<int>());
for (size_t i = 0; i < vv.size(); ++i)
{
vv[i].resize(i + 1, 0);
vv[i][0] = vv[i][vv[i].size() - 1] = 1;
}
for (size_t i = 0; i < vv.size(); ++i)
{
for (size_t j = 0; j < vv[i].size(); ++j)
{
if (vv[i][j] == 0)
{
vv[i][j] = vv[i - 1][j] + vv[i - 1][j - 1];
}
}
}
for (int i = 0; i < vv.size(); i++)
{
for (int j = 0; j < vv[i].size(); j++)
{
cout << vv[i][j] << " ";
}
cout << endl;
}
return vv;
}
};
void test()
{
vector<int>arr;
arr.push_back(1);
arr.push_back(2);
arr.push_back(3);
arr.push_back(4);
arr.push_back(5);
arr.push_back(6);
arr.push_back(7);
arr.push_back(8);
arr.push_back(9);
arr.push_back(10);
for (int i = 0; i < arr.size(); i++)
{
cout << arr[i] << " ";
}
cout << endl;
for (auto e : arr)
{
cout << e << " ";
}
cout << endl;
cout << "============================================" << endl;
//vector::iterator it = arr.begin();
//while (it != arr.end())
//{
// if ((*it) % 2 == 0)
// {
// it=arr.insert(it, (*it) * 2);
// }
// it++;
//}
//for (auto e : arr)
//{
// cout << e << " ";
//}
cout << endl;
vector<int>::iterator ite = arr.begin();
while (ite != arr.end())
{
if ((*ite) % 2 != 0)
{
ite = arr.erase(ite);
}
else
{
ite++;
}
}
for (auto e : arr)
{
cout << e << " ";
}
cout << endl;
vector<vector<int>>vv;
}
}