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

【C++】——Vector的模拟实现

P. S.:以下代码均在VS2019环境下测试,不代表所有编译器均可通过。
P. S.:测试代码均未展示头文件stdio.h的声明,使用时请自行添加。

  

在这里插入图片描述

                                           博主主页:Yan. yan.
                                              C语言专栏
                                            数据结构专栏
                                         力扣牛客经典题目专栏
                                                     C++专栏

文章目录

  • 一、Vector的成员变量
  • 二、默认成员函数
    • 1、构造函数
    • 2、拷贝构造函数
    • 3、析构函数
  • 三、增删查改工作
    • 1、reserve()
    • 2、 resize()
    • 3、insert()
    • 4、erase()
  • 四、[]重载和迭代器
    • 1、begin迭代器
    • 2、end迭代器
    • 3、[]运算符重载

一、Vector的成员变量

  我们以类模板的方式来实现Vector的实现。

template<class T>

  类型名称也重新进行修改

typedef T* iterator;
typedef const T* const_iterator;

根据库的实现方式,成员函数如下:

private:iterator _start;iterator _finish;iterator _end_of_storage;

二、默认成员函数

1、构造函数

构造函数可分为3种:

  • 无参构造
  • 构造n个val对象
  • 根据迭代区间构造
    对于无参的构造,我们只需要初始化成员函数即可。


    无参构造
//无参构造函数
vector()//:_start(nullptr)//,_finish(nullptr)//,_end_of_storage(nullptr)
{}

构造n个val对象

//构造n个对象
vector(size_t n, const T& val = T()):_start(nullptr), _finish(nullptr), _end_of_storage(nullptr)
{//1.开空间reserve(n);//2.将空间填充为val对象for (size_t i = 0; i < capacity(); i++){_start[i] = val;}//也可以复用resize//resize(n, val);
}

注意:这里在构造时必须初始化,如果不初始化,在调用reserve函数开空间时会出现访问野指针的问题。也可以调用resize函数进行拷贝构造n个对象。

使用迭代区间进行构造
同理,如果不初始化,会出现扩容后访问野指针的情况。

template<class Inputiterator>
vector(Inputiterator first, Inputiterator last)
{while (first != last){push_back(*first);++first;}
}

2、拷贝构造函数

vector(const vector<T>& v)
//这里必须初始化,否则扩容时会访问不属于自己的空间
:_start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
//如果私有成员给了缺省值,就不用再再次初始化了
{
reserve(v.capacity());
//memcpy(_start, v._start, sizeof(T) * v.size());
//这里使用memcpy的错误跟扩容的错误一样,不再赘述
for (size_t i = 0; i < v.size(); i++) // 如果是string类,会调用string的赋值重载,赋值重载调用string的拷贝构造,完成深拷贝
{_start[i] = v._start[i];
}_finish = _start + v.size();
}

拷贝构造需要注意的几个问题:

  • 拷贝构造同构造函数一样,如果不初始化,在开空间时会出现访问野指针的情况。
  • 拷贝构造必须进行深拷贝,否则如果vector的对象是自定义类型,比如string,会出现两次释放同一块空间的问题。

3、析构函数

释放_start指向的空间,然后全部置为空即可。

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

三、增删查改工作

说明size()和capapcity()
在这里插入图片描述
size的大小为_finish - _start
capacity的大小为_end_of_storage - _start

1、reserve()

该函数的作用是:扩容。

void reserve (size_type n);
  • 思路:
  • 如果要扩容的大小n小于capacity,则不会缩容。
  • 否则执行扩容。
  • 先申请一块n大小的空间
  • 拷贝原空间的数据到新空间,并释放原空间
  • 将新空间的数据交给_start管理。
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;}_start = tmp;_finish = _start + sz;_end_of_storage = _start + n;}
}

2、 resize()

该函数的功能是:重新改变vector容器的大小,让其到达n。新的空间默认初始化为val。

  • 思路:
  • 如果n小于size,则让_finish指向_start + n位置。
  • 如果n大于等于size,先调用reserve函数进行扩容,再将新的空间填充为val。
void resize(size_t n, const T& val = T()){if (n < size()){_finish = _start + n;}else{//扩容到n,如果n<capacity(),则啥事不做,否则,扩容到nreserve(n);//将多的空间全部设置成缺省值while (_finish != _start + n){*_finish = val;++_finish;}}}

3、insert()

该函数的作用是:在pos位置插入模板对象val。

  • 思路:
  • 插入元素前先检查容量
  • 如果容量满了,则调用reserve函数执行扩容操作
  • 然后从pos位置开始将其之后的元素全部都往后挪。
  • 再在pos位置插入val。
void insert(iterator pos, const T& val)
{
assert(pos <= _finish);
//插入前先检查扩容
if (_finish == _end_of_storage)
{size_t oldpos = pos - _start;//记录相对位置size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();reserve(newcapacity);pos = _start + oldpos;
}//记录旧的size,防止出现迭代器失效问题。//将pos之后的位置往后挪,再插入
iterator end = _finish - 1; // reserve之后,_finish也跟着更新了。
while (end >= pos)
{*(end + 1) = *end;--end;
}*pos = val;
_finish += 1;
}

4、erase()

该函数的功能是:删除pos位置的值。

iterator erase(iterator pos)
{assert(pos < _finish);iterator end = pos;while (end != _finish){*end = *(end + 1);++end;}--_finish;return pos;
}

有一个需要注意的点:当我们删除元素后,pos迭代器就会失效,因为空间已经释放,这时候不能使用pos迭代器。
解决方法:返回删除位置的下一个元素的位置,即pos位置。
然而,在只剩下一个待删除元素或者删除最后一个位置的元素时,不能再使用pos迭代器。

四、[]重载和迭代器

1、begin迭代器

返回_start地址即可。

iterator begin()
{return _start;
}const_iterator begin() const
{return _start;
}

2、end迭代器

返回_finish地址即可。

iterator end()
{return _finish;
}const_iterator end() const
{return _finish;
}

3、[]运算符重载

只需给定pos下标即可。
在此之前需要判断pos位置不能超过整个顺序表的size大小。

T& operator[]( size_t pos)
{assert(pos < size());return *(_start + pos);
}//不可修改的
const T& operator[]( size_t pos) const
{assert(pos < size());return *(_start + pos);
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Golang | Leetcode Golang题解之第324题摆动排序II
  • mysql如何储存大量数据,分库存分表的建议和看法
  • gbd的概念与常用指令
  • 【Linux基础】Linux基本指令(一)
  • 小米教你:2GB内存搞定20亿数据的高效算法
  • 【C++】vector 的模拟实现
  • 从0开始的算法(数据结构和算法)基础(七)
  • Unity Addressables bundle依赖查看和资源重复查看工具
  • linux 多进程搭建webserver
  • MinGW-w64编译安装Acise
  • 维吉尼亚密码加解密实现(python)
  • Android 12系统源码_多屏幕(一)多屏幕设备显示Activity
  • 超声波眼镜清洗机哪个性价比高?2024推荐四款清洁力高的超声波清洗机
  • 第十一章:图论part06 108.冗余连接 109.冗余连接II (补)
  • 3、pnpm yarn npm
  • [译] React v16.8: 含有Hooks的版本
  • Docker 笔记(1):介绍、镜像、容器及其基本操作
  • echarts的各种常用效果展示
  • HTTP中GET与POST的区别 99%的错误认识
  • js递归,无限分级树形折叠菜单
  • laravel with 查询列表限制条数
  • overflow: hidden IE7无效
  • React+TypeScript入门
  • Vue 重置组件到初始状态
  • Webpack4 学习笔记 - 01:webpack的安装和简单配置
  • 阿里云购买磁盘后挂载
  • 解析带emoji和链接的聊天系统消息
  • 微服务框架lagom
  • 最近的计划
  • 智能情侣枕Pillow Talk,倾听彼此的心跳
  • #考研#计算机文化知识1(局域网及网络互联)
  • (52)只出现一次的数字III
  • (9)YOLO-Pose:使用对象关键点相似性损失增强多人姿态估计的增强版YOLO
  • (C++哈希表01)
  • (libusb) usb口自动刷新
  • (pojstep1.1.2)2654(直叙式模拟)
  • (Repost) Getting Genode with TrustZone on the i.MX
  • (阿里云万网)-域名注册购买实名流程
  • (定时器/计数器)中断系统(详解与使用)
  • (二)springcloud实战之config配置中心
  • (附源码)springboot宠物管理系统 毕业设计 121654
  • (附源码)计算机毕业设计SSM疫情下的学生出入管理系统
  • (六)什么是Vite——热更新时vite、webpack做了什么
  • (十八)devops持续集成开发——使用docker安装部署jenkins流水线服务
  • (四)stm32之通信协议
  • (算法)硬币问题
  • (一)appium-desktop定位元素原理
  • (转)C语言家族扩展收藏 (转)C语言家族扩展
  • ***php进行支付宝开发中return_url和notify_url的区别分析
  • ***通过什么方式***网吧
  • .NET C# 使用 SetWindowsHookEx 监听鼠标或键盘消息以及此方法的坑
  • .net core 调用c dll_用C++生成一个简单的DLL文件VS2008
  • .NET 中 GetProcess 相关方法的性能
  • .NET/C# 编译期间能确定的相同字符串,在运行期间是相同的实例
  • .NET8.0 AOT 经验分享 FreeSql/FreeRedis/FreeScheduler 均已通过测试