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

做个人网站怎么赚钱免费网站建设哪家好

做个人网站怎么赚钱,免费网站建设哪家好,一个人可以做网站,阿里云上能建设自己的企业网站文章目录1.前言2.vector的实现2.1vector的基本结构2.2 capacity() 和 size()2.3 迭代器和下标访问2.4 构造,拷贝构造,析构函数,赋值重载2.5增删查改(重点)1.前言 首先什么是vector? 在C中,vect…

文章目录

  • 1.前言
  • 2.vector的实现
    • 2.1vector的基本结构
    • 2.2 capacity() 和 size()
    • 2.3 迭代器和下标访问
    • 2.4 构造,拷贝构造,析构函数,赋值重载
    • 2.5增删查改(重点)

1.前言

首先什么是vector?

在C++中,vector 是一种非常常用的容器,属于标准模板库(STL)的一部分。它是一个封装了动态大小数组的序列容器,提供了方便的接口来存储、访问和操作数据。

vector 是一种动态数组,它的大小可以随着元素的添加或删除而自动调整。与普通数组不同,普通数组的大小在定义时是固定的,而 vector 的大小可以在运行时动态改变。

2.vector的实现

首先我们来实现vector的基础结构(成员变量,迭代器等),再介绍一些常用的构造和拷贝构造,最后实现一些增删查改。

2.1vector的基本结构

//首先为了区分库里的vector我们用命名空间将我们要写的vector类包起来
namespace dhb
{template<class T>class vector{public://重新命名一下方便书写迭代器等typedef T* iterator;typedef const T* const_iterator;//各种成员函数private://成员变量iterator _start=nullptr;//这里我们提前给定缺省值iterator _finish=nullptr;iterator _endofstorage=nullptr;
};

vector里为了能存储各类数据用到了模板template<class T>
由由于模板不能声明定义分离
我们的成员函数就写在头文件中。

2.2 capacity() 和 size()

size_t capacity() const;

  • 返回对象所开空间大小(以元素数量表示)

size_t size() const;

  • 返回数组中的元素数量

size_t:返回无符号整型
const:不改变成员变量

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

在这里插入图片描述

2.3 迭代器和下标访问

迭代器

这里介绍普通迭代器和const迭代器,反向迭代器先不做解释。
容器里常用的范围for就是通过调用迭代器实现
iterator begin()
const_iterator begin() const

  • 返回一个指向该向量(vector)中第一个元素的迭代器

iterator end()
const_iterator end() const

  • 返回一个指向vector容器中“末端之后”元素的迭代器。
    这里的“末端之后”元素是一个理论上的元素,它位于vector中最后一个元素的后面。它并不指向任何实际存在的元素,因此不能被解引用

由此可以将begin()和end()看成一个左闭右开的区间 [begin(),end())

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 i)
const T& operator[](size_t i)const

  • 返回向量容器中位置为n的元素的引用
  • 原理和C语言数组类似不过多解释
  • 值得注意的是const版本,第一个const表示返回值不能改变(不能++或- -),第二个是成员变量不能改变
T& operator[](size_t i)
{assert(i < size());return _start[i];
}
const T& operator[](size_t i)const
{assert(i < size());return _start[i];
}

2.4 构造,拷贝构造,析构函数,赋值重载

由于有些构造要用到迭代器所以就放在这里讲解了。
首先最简单的无参构造

vector():_start(nullptr),_finish(nullptr),_endofstorage(nullptr)
{}

有参构造

vector(size_t n, T val = T())
{resize(n, val);//这里我提前复用了后面函数resize()//大家可以结合后面的resize()理解
}

以上两种构造较简单不做重点讲解。

拷贝构造
vector(const vector<T>& v)

  • 用一个对象去初始化一个新的对象
    使用场景:vector<int> v2(v1);(假定v1在上文已初始化)
vector(const vector<T>& v)
{//假如用v1构造v2//v就是v1//不要忘记拷贝数据reserve(capacity());for (auto& e : v){//把数据逐一插入push_back(e);}
}

用花括号构造
想要像下方一样用花括号构造,要有initializer_list构造函数

dhb::vector<int> v3 = { 1,2,3,4,5,5 };
dhb::vector<int> v4 = { 1,2,3,4,5,51,1,1,1,1,1,1,1 };

其实现和拷贝构造类似

vector(initializer_list<T> li)
{//空间略有不同,我们这里只知道花括号中的元素数量//把空间开成size()大小reserve(li.size());for (auto& e : li){push_back(e);}
}

迭代器区间构造

template<class InputIterator>
vector(InputIterator first,InputIterator last)
{//只拷贝一部分迭代器就不考虑reserve了while(first!=last){push_back(*first);++first;}
}

注意:在用迭代器区间构造时要用模板(为了适配所有的容器)可以用vector构造。
析构函数
将数组释放再置空。

~vector()
{if (_start){delete[] _start;_start = _finish = _endofstorage = nullptr;}
}

赋值重载

void swap(vector<T>& v)
{std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_endofstorage, v._endofstorage);
}// 可以写v1 = v2了
vector<T>& operator=(vector<T> v)
{swap(v);return *this;
}

2.5增删查改(重点)

这里我们重点讲解扩容函数reserve()中的一些坑,insert()和erase()中的迭代器失效。
T是上面基本结构中介绍的模板参数
void push_back(const T& x)
void pop_back()
在_finish尾插处尾插一个数据
在写尾插函数时还有个前提条件:扩容函数reserve()

  • 我先写个大家容易写成的错误版本:
//先写个扩容函数
void reaerve(size_t n)
{if(n>capacity()){//申请空间T* tmp=new T[n];//如果_str不为空拷贝数据if(_str){memcpy(tmp,_str,size()*sizeof(T));//注意这里的第三个参数是字节//释放旧空间delete [] _str;}//重新给成员函数值_str=tmp;_finish=_str+size();_endofstorage=_str+n;}
}

这段代码主要有两个错误:
第一个是_finish=_str+size();由于size()返回的是_finish - _start但是_finish是老的vector上的指针,而_start已经完成了_str=tmp的操作,_start和_finish不在同一数组上由此我们的size()就失效了。我们可以通过提前记录size()的值的方法来解决。
第二个错误是memcpy的使用,memcpy 是按字节拷贝,不适用于拷贝 std::string 这样的复杂对象,因为它们内部有指针和动态内存管理逻辑,所以我们要手动逐一拷贝数据。

由此我们可以修改我们的代码:

void reserve(size_t n)
{if (n > capacity()){T* tmp = new T[n];size_t oldsize = size();//拷贝数据//只有顺序表内不为空的时候才需要拷贝数据if (_start){/*memcpy(tmp, _start, oldsize*sizeof(T));*///这里第三个参数易错是长度乘每个参数大小//memcpy是一个一个字节拷贝,会导致string类型的问题//逐个拷贝for (size_t i = 0; i < oldsize; i++){tmp[i] = _start[i];}delete[]_start;}_start = tmp;_finish = _start + oldsize;_endofstorage = _start + n;}
}

写完了扩容函数我们的尾插尾删就容易多了简单带过一下:

void push_back(const vector<T>& x)
{if(_finish==_endofstorage){//空间满了就扩容reserve(capacity()==042*capacity())}//插入数据*_finish=x;_finish++;
}//尾删
//判空
bool empty() const
{return _finish == _start;
}
void pop_back()
{assert(!empty());//再写个判空--_finish;
}

iterator insert(iterator pos, T x)
iterator erase(iterator pos)

	//任意位置插入iterator insert(iterator pos, T x){assert(pos >= _start);assert(pos <= _finish);if (_finish == _endofstorage){size_t len = _finish - _start;reserve(capacity() == 0 ? 4 : 2 * capacity());//扩容以后我们的pos就被判定为失效状态(虽然实际上不一定失效)//重新将pos定位一下pos = _start + len;}//挪动数据iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}//插入数据*pos = x;_finish++;return pos;//?}iterator erase(iterator pos){assert(pos >= _start);assert(pos <= _finish);//挪动数据iterator end = pos + 1;while (end != _finish){*(end - 1) = *end;end++;}_finish--;return pos;}

接下来由以上两个接口来介绍一下迭代器失效:
在 C++ 中,迭代器失效(Iterator Invalidation)是一个常见的问题,尤其是在对容器进行修改操作时。当迭代器失效时,继续使用该迭代器可能会导致未定义行为(如访问非法内存、程序崩溃等)。
结合上文的reserve函数:
在这里插入图片描述
这里的迭代器失效虽然只是在空间扩容后才发生的,但是我们在写代码的过程中只要insert数据了我们酒吧迭代器认定为失效状态。
erase也会造成迭代器失效问题但是和insert有些不同,我们结合实例理解:

vector<int> v{1,2,3,4,4,5}
auto it = v.begin();
while (it != v.end())
{if (*it % 2 == 0)v.erase(it);else++it;
}

在这里插入图片描述

那么我们该如何解决迭代器失效问题呢?
在这里插入图片描述
在这里插入图片描述
这是库里的函数,我们发现都会返回一个迭代器position(也就是我上面写pos),insert的pos就是插入数据的位置,erase的pos位置是那个被删除后的数据后面的一个数据(因为后面数据前移了)。有了返回值我们就可以将其赋值给迭代器进行更新。
如下:

iterator insert(iterator pos, T x)
{assert(pos >= _start);assert(pos <= _finish);if (_finish == _endofstorage){size_t len = _finish - _start;reserve(capacity() == 0 ? 4 : 2 * capacity());//扩容以后我们的pos就被判定为失效状态(虽然实际上不一定失效)//重新将pos定位一下pos = _start + len;}//挪动数据iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}//插入数据*pos = x;_finish++;return pos;//?
}
iterator erase(iterator pos)
{assert(pos >= _start);assert(pos <= _finish);//挪动数据iterator end = pos + 1;while (end != _finish){*(end - 1) = *end;end++;}_finish--;return pos;
}
http://www.dtcms.com/wzjs/51616.html

相关文章:

  • 网站申请页面百度收录提交入口地址
  • 有个别网站打开特别慢职业技术培训
  • wordpress付费开通站点给公司做网站要多少钱
  • 网站建设销售一个月开几个单网站模板下载免费
  • ps建模教程优化新十条
  • 中国建设银行企业官网站购买域名
  • 企业网站前台模板seo优化知识
  • 国外一个专门做配乐的网站站内关键词自然排名优化
  • 网站专题策划页面怎么做推广资源整合平台
  • iis网站物理路径网络营销的成功案例有哪些
  • 丹灶网站建设点击排名优化
  • 怎样去同行网站做外连接名词解释seo
  • 做网站标题居中代码社群营销
  • 不用wordpress建站百度一下 你就知道首页官网
  • 做企业免费网站武汉seo结算
  • 科技部政务服务平台seo编辑培训
  • 速卖通网站怎样做店面的二维码广州疫情最新消息
  • 替朋友做网站广点通广告投放平台登录
  • 企业网站排名提升百度指数趋势
  • 购买域名后怎么做网站关键词排名零芯互联关键词
  • php和python做网站营销网站系统
  • 什么网站可以免费做宣传竞价托管代运营多少钱
  • 如何做网站详细步骤图超级外链自动发布工具
  • 重庆app推广公司常用的seo查询工具
  • 做图字体网站免费的个人网站html代码
  • 图片1600px做网站口碑营销策略有哪些
  • wordpress标题序号网络营销乐云seo
  • 做潮鞋的网站和平台网络公司名字大全
  • 视频类网站开发免费的外贸网站推广方法
  • 做面包国外网站百度热榜