#include
#include
using namespace std;
namespace lz
{
//模拟实现vector
template<class T>
class vector
{
public:
typedef T* iterator;
typedef const T* const_iterator;
//默认成员函数
vector(); //构造函数
vector(size_t n, const T& val); //构造函数
template<class InputIterator>
vector(InputIterator first, InputIterator last); //构造函数
vector(const vector<T>& v); //拷贝构造函数
vector<T>& operator=(const vector<T>& v); //赋值运算符重载函数
~vector(); //析构函数
//迭代器相关函数
iterator begin();
iterator end();
const_iterator begin()const;
const_iterator end()const;
//容量和大小相关函数
size_t size()const;
size_t capacity()const;
void reserve(size_t n);
void resize(size_t n, const T& val = T());
bool empty()const;
//修改容器内容相关函数
void push_back(const T& x);
void pop_back();
void insert(iterator pos, const T& x);
iterator erase(iterator pos);
void swap(vector<T>& v);
//访问容器相关函数
T& operator[](size_t i);
const T& operator[](size_t i)const;
private:
iterator _start; //指向容器的头
iterator _finish; //指向有效数据的尾
iterator _endofstorage; //指向容器的尾
};
}
string s("hh aa);
lz::vector<int> v(s.begin(), s.end());
for(auto e:v)
{
cout << e << endl;
}
2.> 分析过程:调用时,使用last和first两个不同迭代器类型,也就是vector的首尾位置。所以我们拿到这两个变量,做加法,first最终会到last。
3.> 注意一定要先在构造列表中做初始化,因为后面reserve()中会使用到这些值。
4.>由此,可以再用迭代器构造函数的方式写拷贝构造函数。先创建一个以迭代器构造函数拷贝一个vector<>tmp,再用自己实现的Swap()使得当前对象成员变量与tmp交换,更加省事。
double d = 2.2;
int& i = d;
有编译错误,因为d会隐式类型转换。
再回到这个函数上,需要先扩容判断,当endofsotrage == _finish,就reverse()。
9. 关于容量的函数:
T* tmp = new T[n];
_start = tmp;
_finish = _start + size();
_end_of_s = _start + n;
经典错误1.:size():return _finish - _start; start已经通过扩容后新空间的首地址tmp更新了,那么size()返回的size已经用坏味道了。那么怎么办呢?可以在更新_start之前先求size();
因为==_finish在末元素下 一个,整体从0开始,所以+n,到末元素后一==,思路正确。而==_endofs = start + n 也是在最大合法位置的下一个位置==。因整体从0开始,所以它下标是N,然而是第N+1个位置。所以每次扩容时_finish == +endOfs时做扩容。
经典错误2:memcpy():memcpy只适合浅拷贝。
1>简洁写法:通过非引用类型的参数做了拷贝构造,再利用Swap()直接交换参数很当前对象。
2> 参数类型:vector类型,返回值是vector类型。返回当前对象本身。return *this;赋值运算符显然要的是个对象。
解释地址:
https://blog.csdn.net/qq_40080842/article/details/127037413?app_version=5.11.1&code=app_1562916241&csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22127037413%22%2C%22source%22%3A%22qq_40080842%22%7D&uLinkId=usr1mkqgl919blen&utm_source=app
此外,++it,没有重载++,it = begin(),也能从返回的位置往后挪到,因为it是int*地址类型,地址++,默认移动一个存储元素大小,所以往后挪一个int。
insert()
1,> 返回值和参数:不需要返回值,参数是:size_t pos , const T& x ,内部存模板参数类型的值。
1.>先判断位置是否合法,pos <=_finish,允许等于,做尾插。>_start。
2.> 判断是否需要扩容,_findish == _endofS,_endOfS位置在N+1,然而最大能放N,原始赋值endOfS = _start + n;
3.> 挪动数据,iteartor end = _finish - 1;
挪动范围: end >= pos,意思是从后往前pos位置的也被挪走。
挪动习惯:*(end+1 )= *(end); 这样使得变量最小为0,不会越界。再–end。
观察如下使用场景:
p通过find()查找,但是insert()内部如果发生了扩容,那么从start~endOfS之间内存地址都变了,你的p已经非法了,所以实现时,reserve()之前,要先记录原始len,再更新pos = start + len。
以上,就是一个迭代器失效问题,迭代器失效还会常见于erase()。
此外,再对p做插入,还会报错,虽然内部对pos更新了,但是没有影响到p。因为内部pos是形参,所以建议:实现使用引用做参数。但是尊重源码实现,源码参数不是引用,此外就算给了引用,也没用,因为迭代器begin()返回也不是引用类型,是临时对象,但是如果给迭代器的begin()变成&,所以建议不重复对一个位置做插入。
pop_back()
1> 参数是const T&,直接给末尾赋值,本质做深拷贝。
因为底层是连续空间,直接–_finish;表示末尾的下一个往回收。****
insert()
1.> 过程:
先判断pos位置是否合法 ,在start~endfS
判断是否需要扩容,需要先保存原始长度len,再去reserve(n),此时内部的_start已经改变,需要手动计算扩容后的pos真实位置。
拷贝原始数据,不要用memcpy(),当内存类型为对象类型,则需要做深拷贝memcpy()只适合默认类型的浅拷贝时使用。
所以这里实现时:_start[i] = v[i];
erase()
注意类外实现都需要加上typename,防止歧义,告诉编译器:这是个类型。
1.>过程:
先查位置是否合法两个assert。
当前位置于pos+1,然后以pos-1 = pos去循环赋值。
最后给_finish–。
还可以加缩容判断,当size()为capacity()一半,就缩容。
2.>注意点:不要重复对一个位置删,因为删完做了挪动,当前迭代器位置可能已经变了,可能会跳过一些元素,最终可能报错。
3.>解决思路:删除完返回迭代器位置,且删除过程中加判断,if(符合删除条件){调用erase()} else{it++;}
此外,STL规定erase()返回删除位置的下一个。建议insert和erase之后别访问,可能有各种迭代器失效情况。
头文件
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
using namespace std;
namespace lz
{
//模拟实现vector
template<class T>
class vector
{
public:
typedef T* iterator;
typedef const T* const_iterator;
//默认成员函数
vector(); //构造函数
vector(size_t n, const T& val); //构造函数
template<class InputIterator>
vector(InputIterator first, InputIterator last) //构造函数
:_start(nullptr)
, _finish(nullptr)
, _endofstorage(nullptr)
{
while (first != last)
{
push_back(*first);
first++;
}
}
vector(const vector<T>& v); //拷贝构造函数
vector<T>& operator=(vector<T> v); //赋值运算符重载函数
~vector(); //析构函数
//迭代器相关函数
iterator begin();
iterator end();
const_iterator begin()const;
const_iterator end()const;
//容量和大小相关函数
size_t size()const;
size_t capacity()const;
void reserve(size_t n);
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;
}
bool empty()const;
//修改容器内容相关函数
void push_back(const T& x);
void pop_back();
void insert(iterator pos, const T& x);
iterator erase(iterator pos);
//访问容器相关函数
T& operator[](size_t i);
const T& operator[](size_t i)const;
// 其它功能
void swap(vector<T>& v)
{
std::swap(v._start, _start);
std::swap(v._finish, _finish);
std::swap(v._endofstorage, _endofstorage);
}
T& front();
T& back();
private:
iterator _start; //指向容器的头
iterator _finish; //指向有效数据的尾
iterator _endofstorage; //指向容器的尾
};
//========构造函数
template<class T>
vector<T>::vector()
:_start(nullptr)
, _finish(nullptr)
, _endofstorage(nullptr)
{};
//vector::vector()
//{
// // 2 12
//};
//template
//vector::vector(const vector& v)
// :_start(nullptr)
// , _finish(nullptr)
// , _endofstorage(nullptr)
//{
// _start = new T[v.capacity()]; //开辟一块和容器v大小相同的空间
// for (size_t i = 0; i < v.size(); i++) //将容器v当中的数据一个个拷贝过来
// {
// _start[i] = v[i];
// }
// _finish = _start + v.size(); //容器有效数据的尾
// _endofstorage = _start + v.capacity(); //整个容器的尾
//
//}
// 拷贝构造现代写法
//template
//vector::vector(const vector& v)
// :_start(nullptr)
// , _finish(nullptr)
// , _endofstorage(nullptr)
//{
// reserve(v.capacity()); //调用reserve函数将容器容量设置为与v相同
// for (auto& e : v) //将容器v当中的数据一个个尾插过来
// {
// push_back(e);
// }
//}
//
// v2(v) 拷贝构造 现代 简洁写法
template<class T>
vector<T>::vector(const vector<T>& v)
:_start(nullptr)
, _finish(nullptr)
, _endofstorage(nullptr)
{
vector<T> tmp(v.begin(), v.end());
swap(tmp);
}
template<class T>
vector<T>::vector(size_t n, const T& val)
:_start(nullptr)
, _finish(nullptr)
, _endofstorage(nullptr)
{
reserve(n); //调用reserve函数将容器容量设置为n
for (size_t i = 0; i < n; i++) //尾插n个值为val的数据到容器当中
{
push_back(val);
}
}
template<class T>
vector<T>:: ~vector()
{
delete[] _start; //释放容器存储数据的空间
_start = nullptr; //_start置空
_finish = nullptr; //_finish置空
_endofstorage = nullptr;
}
//========容量相关
// 扩容
template<class T>
void vector<T>::reserve(size_t n)
{
if (n > capacity()) //判断是否需要进行操作
{
size_t sz = size(); //记录当前容器当中有效数据的个数
T* tmp = new T[n]; //开辟一块可以容纳n个数据的空间
if (_start) //判断是否为空容器
{
for (size_t i = 0; i < sz; i++) //将容器当中的数据一个个拷贝到tmp当中
{
tmp[i] = _start[i];
}
delete[] _start; //将容器本身存储数据的空间释放
}
_start = tmp; //将tmp所维护的数据交给_start进行维护
_finish = _start + sz; //容器有效数据的尾
_endofstorage = _start + n; //整个容器的尾
}
}
/*template
void vector::resize(size_t n, const T& val = T())
{
}*/
template<class T>
size_t vector<T>::capacity()const
{
return _endofstorage - _start;
}
template<class T>
size_t vector<T>::size()const
{
return _finish - _start;
}
template<class T>
bool vector<T>::empty()const
{
return size() == 0;
}
//========CRUD
template<class T>
void vector<T>::push_back(const T& x)
{
if (_finish == _endofstorage) //判断是否需要增容
{
size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity(); //将容量扩大为原来的两倍
reserve(newcapacity); //增容
}
*_finish = x; //尾插数据
_finish++; //_finish指针后移
}
template<class T>
void vector<T>::pop_back()
{
assert(!empty()); //容器为空则断言
_finish--; //_finish指针前移
}
template<class T>
void vector<T>::insert(iterator pos, const T& x)
{
assert(pos >= _start);
assert(pos <= _finish);
if (_finish == _endofstorage) //判断是否需要增容
{
size_t len = pos - _start; //记录pos与_start之间的间隔
size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity(); //将容量扩大为原来的两倍
reserve(newcapacity); //增容
pos = _start + len; //通过len找到pos在增容后的容器当中的位置
}
//将pos位置及其之后的数据统一向后挪动一位,以留出pos位置进行插入
iterator end = _finish-1;
while (end >= pos)
{
*(end+1) = *(end);
end--;
}
*pos = x; //将数据插入到pos位置
_finish++; //数据个数增加一个,_finish后移
}
//template
//typename vector::iterator vector::erase(typename vector::iterator pos)
//{
// assert(pos>= _start);
// assert(pos < _finish);
// iterator it = pos + 1;
// while (it != _finish)
// {
// *(it - 1) = *it;
// it++;
// }
// _finish--; //数据个数减少一个,_finish前移
// return pos;
//}
template<class T>
typename vector<T>::iterator vector<T>::erase(typename vector<T>::iterator pos)
{
assert(pos>= _start);
assert(pos < _finish);
iterator it = pos + 1;
while (it != _finish)
{
*(it - 1) = *it;
it++;
}
_finish--; //数据个数减少一个,_finish前移
return pos;
}
//========重载
template<class T>
T& vector<T>::operator[](size_t i)
{
assert(i < size()); //检测下标的合法性
return _start[i]; //返回对应数据
}
template<class T>
const T& vector<T>::operator[](size_t i)const
{
assert(i < size()); //检测下标的合法性
return _start[i]; //返回对应数据
}
template<class T>
vector<T>& vector<T>::operator=(vector<T> i)
{
swap(i);
return *this;
}
//========迭代器
template<class T>
typename vector<T>::iterator vector<T>::begin()
{
return _start;
}
template<class T>
typename vector<T>::iterator vector<T>::end()
{
return _finish;
}
template<class T>
typename vector<T>::const_iterator vector<T>::begin()const
{
return _start;
}
template<class T>
typename vector<T>::const_iterator vector<T>::end()const
{
return _finish;
}
template<class T>
T& vector<T>::front()
{
assert(size() > 0);
return *_start;
}
template<class T>
T& vector<T>::back()
{
assert(size() > 0);
return *(_finish - 1);
}
class Solution {
public:
vector<vector<int>> generate(int numRows) {
// resize()初始化 开几行
vector<vector<int>> res;
res.resize(numRows);
// 每一行再次初始化开空间,i行开i+1个
// 默认给0 但是初始化第一个和最后一个给1
for (int i = 0; i < numRows; i++)
{
res[i].resize(i + 1, 0);
res[i].front() = res[i].back() = 1;
}
// 行列
for (int i = 0; i < numRows; i++)
{
for (int j = 0; j < res[i].size(); j++)
{
if (res[i][j] == 0)
res[i][j] = res[i - 1][j - 1] + res[i - 1][j];
cout << "i = "<< i <<" , j = " << j <<" , res = " << res[i][j] << endl;
}
}
return res;
}
};
}
测试文件
#include"l2vector_t.h"
void test_v1()
{
lz::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
for (size_t i = 0; i < v.size(); i++)
{
cout << v[i] << " ";
}
cout << endl;
}
void test_iteartor()
{
lz::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
for (size_t i = 0; i < v.size(); i++)
{
cout << v[i] << " ";
}
cout << endl;
lz::vector<int>::iterator it = v.begin();
while (it != v.end())
{
cout << *it << " ";
++it;
}
}
void test_insert()
{
lz::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
for (size_t i = 0; i < v.size(); i++)
{
cout << v[i] << " ";
}
cout << endl;
auto p = find(v.begin(), v.end(), 3);
if (p != v.end())
{
v.insert(p, 30);
}
for (auto e : v)
{
cout << e << " " << endl;
}
}
void test_erase()
{
lz::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
auto p = find(v.begin(), v.end(), 3);
if(p!=v.end())
{
v.erase(p);
}
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
}
void test_copy()
{
lz::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
lz::vector<int> v2(v);
for (auto& e : v)
{
e = 1;
cout << e << " ";
}
cout << endl;
for (auto e : v2)
{
cout << e << " ";
}
}
void test_vector_iterator()
{
string s("hello world");
lz::vector<char> v(s.begin(), s.end());
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
}
// 赋值重载的测试
void test_operator_equals()
{
lz::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
lz::vector<int> v2;
v2 = v;
for (auto e : v)
{
cout << e << " ";
}
}
void test_resize()
{
lz::vector<int> v;
v.resize(10, 1);
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
v.resize(3);
for (auto e : v)
{
cout << e << " ";
}
}
void test_vectorerwei()
{
lz::Solution().generate(5);
}
int main()
{
//test_iteartor();//test_insert();//test_erase();
//test_copy();
//test_vector_iterator();
//test_operator_equals();
//test_resize();
test_vectorerwei();
return 0;
}