当前位置: 首页 > news >正文

抚顺少儿编程哪家好网络优化工程师前景

抚顺少儿编程哪家好,网络优化工程师前景,南京模板建站哪家好,渭南网站建设与维护手撕vector目录: 一、基本实现思路方针 二、vector的构造函数剖析(构造歧义拷贝构造) 2.1构造函数使用的歧义问题 2.2 vector的拷贝构造和赋值重载(赋值重载不是构造哦,为了方便写在一起) 三、vector的…

手撕vector目录:

一、基本实现思路方针

二、vector的构造函数剖析(构造歧义+拷贝构造)

2.1构造函数使用的歧义问题

2.2 vector的拷贝构造和赋值重载(赋值重载不是构造哦,为了方便写在一起)

三、vector的基本接口

3.1empty和clear

3.2 size和capacity

3.3  [ ]和iterator

四、 resize和reserve

五、尾插尾删

六、迭代器失效

6.1 insert

6.2 erase

七、vector.h


一、基本实现思路方针

本篇的目的很简单,只有一个:模拟实现vector

如何去模拟实现?我们可以看看vector的源码,我们可以抽离出主体框架:

namespace lzy//防止命名冲突
{template<class T>class lzy_vector{public:typedef T* iterator;typedef const T* const_iterator;public://成员函数private:T* _start;T* _finish;T* _end_of_storage;}
}

对于size = _finish - _start

对于capacity = _endofstorage-_start

可以看到,vector 的底层和 string 一样,都是一个指针指向一块动态开辟的数组,但是二者不同的是,string 是用 T* str 和 _size 和 _capacity 三个成员变量来维护这块空间,而 vector 是用 _finish 和 _end_of_storage 两个指针来维护这块空间;虽然 vector 使用指针看起来难了一些,但本质上其实是一样的 : _size = _finish - _start, _capacity = _end_of_storage - _start;

 有了这些作为铺垫,我们对于vector的模拟实现大概有了一个基本的框架,话不多说,直接进入主题👇


二、vector的构造函数剖析(构造歧义+拷贝构造)

1. 无参的构造函数,我们利用初始化列表来进行初始化。用nullptr初始化比较好,因为nullptr的free或delete都不会出错 

2. 另一种构造是用n个value值来进行构造,value既有可能是内置类型,也有可能是自定义类型,所以如果用引用作参数的话,需要用const引用,也就是常引用来作参数,否则无法接收内置类型的实参

3. 除无参构造外,常用的构造还有迭代器区间作为参数的构造函数。这里的迭代器需要用函数模板来实现,因为构造vector所用的迭代器不一定只是vector类型的,还有可能是string类型,所以这里的迭代器形参需用模板来实现

 lzy_vector() // 初始化列表给空指针:_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){}//n个val构造lzy_vector(size_t n, const T& val = T()):_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){reserve(n);for (size_t i = 0; i < n; i++)push_back(val);}//迭代器区间构造template<class InputIterator>lzy_vector(InputIterator first, InputIterator last):_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){while (first != last){push_back(*first);++first;}}

吐槽:经过一番折腾,总算是有了个输出结果,要不是reserve没写,要不就是push_back没写,要不就是类模板没搞,要不就是迭代器输出的时候迭代器的begin没写。。。。

2.1构造函数使用的歧义问题

1. 在实现完n个value构造的构造函数之后,如果我们此时用10个int类型的数字1来构造对象v1,实际会报错,报错的原因其实是由于函数的匹配优先级所导致的实参无法正确匹配相应的构造函数而使用10个char类型的字符A却不会报错,这其实也是由于函数的匹配优先级决定的 

2.  对于size_t和常引用作为参数的构造来说,它的匹配优先级对于10个1实际不是最高的,因为常引用需要进行类模板参数T类型的推导,而10又是整型int,int到size_t还需要进行隐式类型转换,代价有点大


而对于迭代器区间作为参数的构造来讲,函数模板参数InputIterator只需要进行一次类型推导即可完成匹配,所以用10个1来构造时,实际匹配的构造函数是迭代器区间作为参数的构造函数,而在匹配的构造函数中,对迭代器区间进行了解引用,那就是对常量10进行了解引用,则发生非法的间接寻址(用了迭代器区间的构造函数,会报错)

3 对于这种问题的解决,可以将size_t换成int类型,或者将10强转为size_t类型,但stl源码的解决方式并非是这样的,而是利用了函数重载来解决了这个问题,多重载了一个类型为int的构造函数

好的,我们继续开干!上面的代码运行结果正确

 解决方法:

2.2 vector的拷贝构造和赋值重载(赋值重载不是构造哦,为了方便写在一起)

1. 对于拷贝构造的实现,和string一样,还是有传统写法和利用打工人的现代写法,利用打工人的本质实际就是代码重构。传统写就是提前用reserve预留好空间,然后push_back将数据尾插到提前预留的空间当中(这个逻辑还是非常清楚的)

这里让我想起来一个知识点:那会vector介绍接口的时候,我们存在越界访问的问题,我们在reserve之后, 利用[ ] 进行赋值,这样是不对的,因为我们只有capacity,没有size。但是利用push_back插入数据的时候,会进行检查:如果size为0,那么就会赋值,所以reserve之后push_back是合理的

注意:拷贝构造这么写是不对的(我本以为是我的接口写的不完善,但是在std中运行发现也是报错)

原因: 

而使用拷贝构造的时候必须这样:

void testvector()
{lzy::lzy_vector<int> v1(10,1);lzy::lzy_vector<int> v2(v1);for(auto e : v2){cout << e << " ";}
}
int main()
{testvector();return 0;
}

2. 无论是从代码可读性还是实用性的角度来讲,现代写法都更胜一筹,这里利用形参对象v的迭代器来构造临时对象tmp,然后将对象tmp和* this进行交换为了防止对象tmp离开函数栈帧销毁时造成野指针的访问问题,所以在调用构造函数时采用了初始化列表的方式将* this的三个成员都初始化为nullptr(原先埋下的伏笔,居然在这里展现出来了

注:别忘了重新写swap函数

lzy_vector(const lzy_vector<T>& v):_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){vector<T> tmp(v.begin(), v.end());  //利用了迭代器模板swap(tmp);}

3. 在实现拷贝构造后,实现赋值重载就比较简单了,利用传值拷贝构造的临时对象即可,然后调用swap类成员函数即可完成自定义类型的赋值工作。为了符合连续赋值含义,我们利用引用来作为返回值。

lzy_vector<T>& operator=(lzy_vector<T> v)  //复用拷贝构造,存在自我赋值的问题,但不影响程序正确性{swap(v);return *this;}

注意:参数不可以加引用,正常来说,v1=v2; 如果加上引用的话,v2就会变成v1的值

总结:由于拷贝构造必须有引用,所以函数体内另外找了一个打工人,但我们的赋值不需要,所以引用和tmp必须同时存在,这样才可以满足我们的逻辑


三、vector的基本接口

3.1empty和clear

empty

bool empty() const
{return _finish == _start;
}

clear

void clear()
{_finish = _start;//这里可不是置为nullptr哦
}

3.2 size和capacity

size

size_t size() const
{return _finish - _start;
}

capacity

size_t capacity() const 
{return _endofstorage - _start;
}

3.3  [ ]和iterator

[ ]

提供const版本和非const版本:

T& operator[](size_t pos)
{assert(pos < size());return _start[pos];
}const T& operator[](size_t pos)const
{assert(pos < size());return _start[pos];
}

 iterator

同理普通迭代器和const迭代器版本,同理,范围for循环此时也是可以实现的:

typedef T* iterator;
typedef const T* const_iterator;iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}

四、 resize和reserve

这两个接口需要单独拎出来,这是因为后面的插入等相关操作需要用到,所以我们先来看看这两个接口,同时这里有一些问题值得我们去注意:

resize

n个数据去初始化,这个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;}
}

 reserve

void reserve(size_t n)
{if (n > capacity()){T* tmp = new T[n];//size()需要先保存起来,后面_start会发生改变size_t sz = size();//为空不需要拷贝了if (_start){for (size_t i = 0; i < sz; i++){tmp[i] = _start[i];}delete[] _start;//memcpy(tmp, _start, sizeof(T) * size());//浅拷贝//delete[] _start;}_start = tmp;_finish = _start+sz;_endofstorage = _start + n;}
}


五、尾插尾删

void push_back(const T& x)
{if (_finish == _endofstorage){size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newCapacity);}*_finish = x;++_finish;
}void pop_back()
{assert(_finish > _start);--_finish;
}


六、迭代器失效

6.1 insert

//迭代器失效:扩容引起野指针问题
void insert(iterator pos, const T& val)
{assert(pos >= _start);assert(pos <= _finish);if (_finish == _endofstorage){size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newCapacity);}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = val;++_finish;
}

 测试代码:

void Test3()
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;vector<int>::iterator it = find(v.begin(), v.end(), 3);if (it != v.end()){v.insert(it, 30);}for (auto e : v){cout << e << " ";}cout << endl;
}

 

这是因为扩容导致pos失效了:

 

insert过程中发生扩容,导致it指向的空间实际上已经被释放,it指向已被释放的空间是野指针,造成了迭代器失效

所以,我们应该去更新pos,算出pos刚开始的相对位置,然后再去进行更新即可解决问题。但是此时外面调用insert的it仍然是失效的,因为是传值调用,形参改变不影响实参,可以通过返回值接收解决问题。(如果是传引用的话,只能传变量,而临时对象具有常性,不能调用,存在很多问题),所以直接用返回值解决。

改正代码:

iterator insert(iterator pos, const T& val)
{assert(pos >= _start);assert(pos <= _finish);if (_finish == _endofstorage){//扩容会导致pos迭代器失效,需要更新size_t len = pos - _start;size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newCapacity);pos = _start + len;}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = val;++_finish;return pos;
}

6.2 erase

 挪动数据进行覆盖即可:

void erase(iterator pos)
{assert(pos >= _start);assert(pos < _finish);iterator begin = pos + 1;while (begin < _finish){*(begin - 1) = *begin;++begin;}--_finish;
}

 erase的pos也可能会导致pos失效,测试代码:

void Test6(){//删除所有偶数vector<int> v;v.push_back(1);v.push_back(2);v.push_back(2);v.push_back(3);v.push_back(4);vector<int>::iterator it = v.begin();while (it != v.end()){if (*it % 2 == 0){v.erase(it);}++it;}for (auto e : v){cout << e << " ";}cout << endl;}

 

测试发现:

1,2,3,4的时候发生崩溃

1,2,2,3,5结果只删了一个2

1,2,3,4,5结果是正常的

image-20221127140628122

 

上述代码在VS下,当erase(it)之后,it指向的位置发生改变,然后在++it的话,会出现问题,出现一些错误,造成迭代器失效。

我们最好统一认为失效了。

正确的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;
}		

 测试代码:
 

void Test6(){//删除所有偶数vector<int> v;v.push_back(1);v.push_back(2);v.push_back(2);v.push_back(3);v.push_back(4);vector<int>::iterator it = v.begin();while (it != v.end()){if (*it % 2 == 0){it = v.erase(it);}else{++it;}}for (auto e : v){cout << e << " ";}cout << endl;}

七、vector.h

#include<iostream>
using namespace std;
namespace lzy
{template<class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}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():_start(nullptr), _finish(nullptr), _endofstorage(nullptr){}/*vector(const vector<T>& v):_start(nullptr),_finish(nullptr),_endofstorage(nullptr){reserve(v.capacity());for (const auto& e : v){push_back(e);}}*///vector<int> v1(10, 5);//vector<char> v2(10, 'A');vector(size_t n, const T& val = T()):_start(nullptr), _finish(nullptr), _endofstorage(nullptr){reserve(n);for (size_t i = 0; i < n; i++){push_back(val);}}//改成int或强转vector(int n, const T& val = T()):_start(nullptr), _finish(nullptr), _endofstorage(nullptr){reserve(n);for (int i = 0; i < n; i++){push_back(val);}}template <class InputIterator>vector(InputIterator first, InputIterator last):_start(nullptr), _finish(nullptr), _endofstorage(nullptr){while (first != last){push_back(*first);//int不能解引用++first;}}vector(const vector<T>& v):_start(nullptr), _finish(nullptr), _endofstorage(nullptr){vector<T> tmp(v.begin(), v.end());swap(tmp);}//缺陷:自己拷贝自己vector<T>& operator=(vector<T> v){swap(v);return *this;}~vector(){delete[] _start;_start = _finish = _endofstorage = nullptr;}void reserve(size_t n){if (n > capacity()){T* tmp = new T[n];size_t sz = size();//为空不需要拷贝了if (_start){for (size_t i = 0; i < sz; i++){tmp[i] = _start[i];}delete[] _start;//memcpy(tmp, _start, sizeof(T) * size());//浅拷贝//delete[] _start;}_start = tmp;_finish = _start + sz;_endofstorage = _start + 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{return _finish == _start;}size_t size() const{return _finish - _start;}size_t capacity() const{return _endofstorage - _start;}void push_back(const T& x){if (_finish == _endofstorage){size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newCapacity);}*_finish = x;++_finish;}void pop_back(){assert(_finish > _start);--_finish;}//迭代器失效:野指针问题/*void insert(iterator pos, const T& val){assert(pos >= _start);assert(pos < _finish);if (_finish == _endofstorge){reserve(capacity() == 0 ? 4 : capacity() * 2);}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = val;++_finish;}*/iterator insert(iterator pos, const T& val){assert(pos >= _start);assert(pos <= _finish);if (_finish == _endofstorage){//扩容会导致pos迭代器失效,需要更新size_t len = pos - _start;size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newCapacity);pos = _start + len;}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = val;++_finish;return pos;}iterator erase(iterator pos){assert(pos >= _start);assert(pos < _finish);iterator begin = pos + 1;while (begin < _finish){*(begin - 1) = *begin;++begin;}--_finish;return pos;}void swap(vector<T>& v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_endofstorage, v._endofstorage);}void clear(){_finish = _start;}public:iterator _start;iterator _finish;iterator _endofstorage;};void Test1(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);cout << v.size() << endl;cout << v.capacity() << endl;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 (auto e : v){cout << e << " ";}cout << endl;}void Test2(){vector<int> v;v.resize(10, -1);for (auto e : v){cout << e << " ";}cout << endl;v.resize(5);for (auto e : v){cout << e << " ";}cout << endl;v.pop_back();v.pop_back();v.pop_back();v.pop_back();v.pop_back();v.pop_back();}void Test3(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;v.insert(v.end(), 0);for (auto e : v){cout << e << " ";}cout << endl;vector<int>::iterator it = find(v.begin(), v.end(), 3);if (it != v.end()){v.insert(it, 30);}for (auto e : v){cout << e << " ";}cout << endl;}void Test4(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);vector<int>::iterator it = find(v.begin(), v.end(), 3);if (it != v.end()){//传值v.insert(it, 30);}//insert以后it不能使用,可能迭代器失效(野指针)//(*it)++;for (auto e : v){cout << e << " ";}cout << endl;}void Test5(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);vector<int>::iterator it = find(v.begin(), v.end(), 3);if (it != v.end()){v.erase(it);}cout << *it << endl;//	(*it)++;for (auto e : v){cout << e << " ";}cout << endl;}void Test6(){//删除所有偶数vector<int> v;v.push_back(1);v.push_back(2);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);vector<int>::iterator it = v.begin();while (it != v.end()){if (*it % 2 == 0){it = v.erase(it);}else{++it;}}for (auto e : v){cout << e << " ";}cout << endl;}void Test7(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);vector<int> v1(v);for (auto e : v1){cout << e << " ";}cout << endl;vector<int> v2;v2.push_back(10);v2.push_back(20);v2.push_back(30);v1 = v2;for (auto e : v1){cout << e << " ";}cout << endl;v1 = v1;for (auto e : v1){cout << e << " ";}cout << endl;}void Test8(){string str("hello world");vector<int> v(str.begin(), str.end());for (auto e : v){cout << e << " ";}cout << endl;/*vector<int> v1(v.begin(), v.end());*/vector<int> v1(10, 5);//vector<char> v2(10, 'A');for (auto e : v1){cout << e << " ";}cout << endl;}class Solution {public:vector<vector<int>> generate(int numRows) {vector<vector<int>> vv;vv.resize(numRows);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];}}}return vv;}};void Test9(){vector<vector<int>> vvRet = Solution().generate(5);for (size_t i = 0; i < vvRet.size(); i++){for (size_t j = 0; j < vvRet[i].size(); j++){cout << vvRet[i][j] << " ";}cout << endl;}/*vector<vector<int>> vv;vector<int> v(10, 1);vv.push_back(v);vv.push_back(v);vv.push_back(v);vv.push_back(v);vv.push_back(v);for (size_t i = 0; i < vv.size(); i++){for (size_t j = 0; j < vv[i].size(); j++){cout << vv[i][j] << " ";}cout << endl;}*/cout << endl;}void Test10(){vector<string> v;v.push_back("11111111111111111111");v.push_back("22222222222222222222");v.push_back("33333333333333333333");v.push_back("44444444444444444444");v.push_back("55555555555555555555");for (auto e : v){cout << e << " ";}cout << endl;}
}

希望对大家有所帮助! 

 

http://www.dt0577.cn/news/15190.html

相关文章:

  • 网站建设的重要性 学校百度seo优化怎么做
  • 自己的电脑做服务器 并建网站谷歌浏览器下载安装2023最新版
  • 如何设置网站域名网站推广的基本方法
  • 怎么自己做网站app腾讯企业邮箱登录入口
  • 做网站销售说辞搜外友链平台
  • 知果果网站谁做的360优化大师最新版的功能
  • 上海松江做网站多少钱广告宣传网站
  • iis 发布asp网站可以免费发广告的网站有哪些
  • 怎么做p2p网站百度网站首页入口
  • 网站怎么做下载功能百度知道小程序
  • 开发日记网站seo基础优化
  • 那个网站可以做网页百度平台客服电话是多少
  • 专业做网站登录百度网盘下载慢
  • 美食app界面设计模板重庆网页优化seo公司
  • 行业门户网站如何做做竞价推广大概多少钱
  • 辛集做网站公司网站seo搜索引擎优化怎么做
  • 男女生做羞羞网站在线代理浏览网站
  • 做网站的总要求上门南京百度网站快速优化
  • 中山公司网站制作鹤壁seo公司
  • 网站站开发 流量学电脑办公软件培训班
  • 乐陵森洁新能源有限公司电话seo技术优化整站
  • 凡科网商城充值seo新手快速入门
  • 做会计网站的流程图郑州seo优化外包顾问
  • 智慧旅游网站建设方案怎样注册网站建立网页
  • 深圳大型论坛网站建设百度关键词排名推广话术
  • 模板网站视频上海seo网站优化软件
  • wordpress baidu提交seo算法
  • 兰州网站制作公司100市场监督管理局是干什么的
  • 医疗网站建设行情重庆seo杨洋
  • 建网站如何添加会员模式东莞做网站公司电话