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

C++ vector模拟实现

        

目录

        一.默认成员函数

        二.扩容相关函数

        三.[]重载

        四.修改函数

        五.迭代器


        继上次写完string之后,可以写一个vector练练手以及熟悉其底层。vector是一个顺序表,相比普通数组不同点在于顺序表的数据必须是连续存放的。

        一.默认成员函数

        string是只存放字符,而vector需要存放内置类型和自定义类型,所以需要引入类模板。以下是vector的最外层框架。

    template<class T>//类模板参数,T是接收外面转进来的类型,可以使内置也可以是自定义类型class vector{public://成员函数的定义private://内置成员变量是三个迭代器,vector的迭代器实际上还是指针iterator _start = nullptr; // 指向数据块的开始iterator _finish = nullptr; // 指向有效数据的尾iterator _endOfStorage = nullptr; // 指向存储容量的尾};

        以下是vector的默认成员函数,重载&和const &重载一般不需要手动写。

        vector()//默认构造函数{}vector(int n, const T& value = T())//构造一个包含n个元素的vector,每个元素都是value{resize(n, value);//直接用resize即可}template<class InputIterator>vector(InputIterator first, InputIterator last)//通过一个迭代器区间构造vector{while (first != last){push_back(*first);first++;}}vector(const vector<T>& v)//拷贝构造函数{vector tmp(v.begin(), v.end());//复用迭代器区间构造函数完成拷贝,然后再交换swap(tmp);}vector<T>& operator= (vector<T> v)//通过传值来完成拷贝,然后再交换{swap(v);return *this;}~vector()//析构函数{delete[] _start;//直接delete,由于是delete[]所以即使是多层嵌套(自定义类型或者vector或其他类型)也会调用他们的析构函数(这里需了解delete[]原理)_start = nullptr;_finish = nullptr;_endOfStorage = nullptr;}

         二.扩容相关函数

        扩容函数需要注意异地扩容时把原来空间的元素拷贝到新空间时需要使用赋值而不是memcpy或memmove。对于自定义类型并且实现了深拷贝的赋值就不会出现因为浅拷贝导致多次析构的问题。

        size_t size() const{return _finish - _start;//返回当前元素个数}size_t capacity() const{return _endOfStorage - _start;//返回总容量大小}void reserve(size_t n)//扩容{if (n > capacity())//判断目标扩容大小有没有大于总容量{T* tmp = new T[n];//直接创建新空间,大小为nsize_t sz = size();//记录扩容前的元素个数if (_start)//如果_start不为空(如果为空也不用复制元素内容了){for (int i = 0; i < sz; i++){tmp[i] = _start[i];//这里如果用memmove或者memcopy对于自定义类型会发生多次析构的问题(相当于浅拷贝),所以还是用赋值,如果自定义类型有实现深拷贝就没问题}delete[] _start;//这里把原来的删除,如果是浅拷贝,这里的删除了,tmp里面的自定义类型指针就变成野指针了}_start = tmp;//修改_start_finish = tmp + sz;//记录sz的好处_endOfStorage = tmp + n;}}void resize(size_t n, const T& value = T())//扩容或减容至n个元素,扩容的话会用value填满所有空间{if (n < size())//判断目标扩容大小是不是小于当前元素个数{T* tmp = new T[n];//直接创建新空间,大小为nfor (int i = 0; i < n; i++){tmp[i] = _start[i];//一个个拷贝,这里用赋值和reserve原因完全一样}//下面也和reserve一样delete[] _start;_start = tmp;_finish = tmp + n;_endOfStorage = tmp + n;}else if (n > size())//这里是目标扩容大小大于当前元素个数{int i = size();//记录当前元素个数reserve(n);//扩容while (i < n){_start[i++] = value;//从当前元素的结尾开始填充,直到容量达到目标扩容大小}_finish = _start + n;//更新_finish}}

        三.[]重载

        []重载需要断言是否越界,以及还要实现const版本。

        T& operator[](size_t pos)//方括号重载{assert(pos < size());return _start[pos];}const T& operator[](size_t pos) const//const方括号重载{assert(pos < size());return _start[pos];}

        四.修改函数

        修改函数需要注意insert的pos迭代器失效问题以及erase的迭代器失效(对于外部的迭代器)。

        void push_back(const T& x)//尾插{if (_finish == _endOfStorage){reserve(capacity() == 0 ? 4 : capacity() * 2);}_start[size()] = x;//结尾插入元素_finish++;//更新_finish//或者复用insert//insert(end(),x);}void pop_back()//尾删{erase(end());//直接调用erase函数尾删}void swap(vector<T>& v)//交换两个vector的成员变量{std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_endOfStorage, v._endOfStorage);}iterator insert(iterator pos, const T& x)//在pos位置之前插入{assert(pos >= begin());//断言,防止pos越界assert(pos <= end());size_t sz = pos - _start;//计算并记录pos和_start的相对距离,也是待会要插入的位置if (_finish == _endOfStorage)//判断是否要扩容{reserve(capacity() == 0 ? 4 : capacity() * 2);}//重点注意,这里是insert迭代器可能失效的地方pos = _start + sz;//如果是异地扩容,那么pos所指的位置会被删除就变成野指针了,所以要更新pos位置,之前记录的sz就有用了if (size())//如果当前元素个数不为0的话{//从后往前走,然后把左边的数据挪到右边,需要注意下标的越界问题iterator end = _finish;while (end > pos){*end = *(end - 1);//左边的数据挪到右边end--;}}_start[sz] = x;//放入数据_finish++;//更新_finishreturn pos;//返回插入元素的下一个位置,也就是pos}iterator erase(iterator pos)//删除当前位置的元素{assert(pos >= begin());//判断pos是否越界assert(pos <= end());iterator prev = pos + 1;//记录pos位置的前一个位置//从左往右走,然后把右边的数据挪到左边,直接覆盖要删除的元素while (prev < end()){*(prev - 1) = *prev;//把右边的数据挪到左边prev++;}_finish--;//更新_finish//这里是第二个迭代器失效问题,如果外面的迭代器不接受erase返回的迭代器可能后面的删除会出问题return pos;//返回删除元素的下一个位置(其实还是pos)}

        五.迭代器

         vector迭代器就是原生指针,以及实现const迭代器。

        typedef T* iterator;//vector的迭代器是原生指针,和string一样typedef const T* const_iterator;//const迭代器iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}

        以上就是vector的模拟实现,写完后不仅可以提升对代码的操作熟练度,对于顺序表这种数据结构也能有更深的理解。

相关文章:

C++ vector模拟实现

目录 一.默认成员函数 二.扩容相关函数 三.[]重载 四.修改函数 五.迭代器 继上次写完string之后&#xff0c;可以写一个vector练练手以及熟悉其底层。vector是一个顺序表&#xff0c;相比普通数组不同点在于顺序表的数据必须是连续存放的。 一.默认成员函数 string是只存放字符…...

BUUCTF:[GYCTF2020]FlaskApp

Flask的网站&#xff0c;这里的功能是Base64编码解码&#xff0c;并输出 并且是存在SSTI的 /hint 提示PIN码 既然提示PIN&#xff0c;那应该是开启了Debug模式的&#xff0c;解密栏那里随便输入点什么报错看看&#xff0c;直接报错了&#xff0c;并且该Flask开启了Debug模式&am…...

好玩的调度技术

好玩的调度技术 文章目录 好玩的调度技术前言一、乱金柝-空间剥离二、拖拽编辑三、全端兼容 前言 最近感觉自己抑郁了&#xff0c;生态技术实在太庞大太复杂&#xff0c;所以我决定先停一段时间&#xff0c;在停下写生态的这两天写了几个调度的小玩意换换脑子&#xff0c;很有…...

Android 自定义加解密播放音视频(m3u8独立加密)

文章目录 背景加密流程音视频解密音视频播放结语 背景 当涉及App内部视频的时候&#xff0c;我们不希望被别人以抓包的形式来爬取我们的视频大视频文件以文件方式整个加密的话需要完全下载后才能进行解密当前m3u8格式虽然支持加密&#xff0c;但是ts格式的小视频可以独立播放的…...

常见的文件格式

一、C:\fakepath\新建文本文档.txt [object String] 实现方式&#xff1a; <input onchange"test(this.value)" type"file"></input><script>function test(e){console.log(e,Object.prototype.toString.call(e))}</script> 二、…...

浏览器输入url后回车展开过程

当你在浏览器中输入一个URL并敲下回车后&#xff0c;浏览器会执行一系列步骤来访问并展示网页。下面是浏览器访问网页的一般流程&#xff1a; DNS解析&#xff1a;浏览器首先会提取URL中的主机名&#xff0c;然后向DNS服务器发送请求&#xff0c;将主机名解析为对应的IP地址。这…...

Docker 容器创建命令说明

使用命令如下: docker run -itd --name=cluster -v /home/ClusterApp/cluster:/home/ClusterApp/cluster --restart=always --privileged=true -p 12000:12000 python:3.8 命令说明: docker run 创建一个容器并运行 docker run --help 可以查看所有的参数: 命令中参数说明 -…...

西瓜书读书笔记整理(六)—— 第六章 支持向量机

第六章 支持向量机 6.1 间隔与支持向量6.1.1 什么是支持向量机6.1.2 支持向量与间隔6.1.3 支持向量机的求解过程 6.2 对偶问题&#xff08;dual problem&#xff09;6.2.1 什么是对偶问题6.2.2 如何求解支持向量机的对偶问题 6.3 核函数&#xff08;kernel function&#xff09…...

蓝桥杯每日一题2023.9.23

4961. 整数删除 - AcWing题库 题目描述 分析 注&#xff1a;如果要进行大量的删除操作可以使用链表 动态求最小值使用堆&#xff0c;每次从堆中取出最小值的下标然后在链表中删除 注意long long 代码解释&#xff1a; while(k --){auto t q.top();q.pop();res t.first;i…...

C语言数组和指针笔试题(三)(一定要看)

目录 字符数组四例题1例题2例题3例题4例题5例题6例题7 结果字符数组五例题1例题2例题3例题4例题5例题6例题7结果字符数组六例题1例题2例题3例题4例题5例题6例题7 结果 感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接 &#x1f412;&#x1f412;&#x1f412;个…...

leetcode11 盛水最多的容器

题目 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 示例 输入&#xff1a;[1,8,6,2,5,4,8,…...

进入数据结构的世界

数据结构和算法的概述 一、什么是数据结构二、什么是算法三、如何去学习数据结构和算法四、算法的时间复杂度和空间复杂度4.1 算法效率4.2 大O的渐进表示法4.3 时间复杂度4.4 空间复杂度4.5 常见复杂度对比 一、什么是数据结构 数据结构是计算机存储、组织数据的方式。&#x…...

stm32之看门狗

STM32 有两个看门狗&#xff0c;独立看门狗和窗口看门狗&#xff0c;独立看门狗又称宠物狗&#xff0c;窗 口看门狗又称警犬。可用来检测和解决由软件错误引起的故障。两个看门狗的原理都是当计数器达到给定的超时值时&#xff0c;产生系统复位&#xff0c;对于窗口型看门狗同…...

纤维蛋白单体(FM)介绍

纤维蛋白单体&#xff08;FM&#xff09;是血栓形成的早期产物&#xff0c;是纤维蛋白原&#xff08;Fibrinogen&#xff0c;Fbg&#xff09;在凝血酶&#xff08;Thrombin&#xff09;的作用下&#xff0c;脱掉肽A&#xff08;Fibrinopeptide A&#xff0c;Fp A&#xff09;与…...

知识图谱实战导论:从什么是KG到LLM与KG/DB的结合实战

前言 本文侧重讲解&#xff1a; 什么是知识图谱LLM与langchain/数据库/知识图谱的结合应用 比如&#xff0c;虽说基于知识图谱的问答 早在2019年之前就有很多研究了&#xff0c;但谁会想到今年KBQA因为LLM如此突飞猛进呢 第一部分 知识图谱入门导论 //待更.. 第二部分 LLM与…...

第5章 会话与会话技术

第5章 会话与会话技术 一. 单选题&#xff08;共5题&#xff0c;50分&#xff09;二. 判断题&#xff08;共5题&#xff0c;50分&#xff09; 一. 单选题&#xff08;共5题&#xff0c;50分&#xff09; (单选题) 阅读下面代码&#xff1a; Book book BookDB.getBook(id)…...

IDEA2023新UI回退老UI

idea2023年发布了新UI&#xff0c;如下所示 但是用起来真心不好用&#xff0c;各种位置也是错乱&#xff0c;用下面方法可以回退老UI...

ElasticSearch(三)

1.数据聚合 聚合&#xff08;aggregations&#xff09;可以让我们极其方便的实现对数据的统计、分析、运算。例如&#xff1a; 什么品牌的手机最受欢迎&#xff1f; 这些手机的平均价格、最高价格、最低价格&#xff1f; 这些手机每月的销售情况如何&#xff1f; 实现这些…...

【LinkedHashMap】146. LRU 缓存

146. LRU 缓存 解题思路 与普通的 HashMap 不同&#xff0c;LinkedHashMap 会保持元素的有序性。这可以在某些情况下提供更可预测的迭代顺序直接获取元素 因为使用到该元素 将该元素重新放入队尾 表示最近使用该元素写入元素&#xff0c;首先如果该元素原来存在 那么需要将ke…...

Opencv-python去图标与水印方案实践

RGB色彩模式是工业界的一种颜色标准&#xff0c;是通过对红&#xff08;R&#xff09;、绿&#xff08;G&#xff09;、蓝&#xff08;B&#xff09;三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的&#xff0c;RGB即是代表红、绿、蓝三个通道的颜色&#xff…...

基于Agent架构的轻量级自托管部署工具Ship实战指南

1. 项目概述&#xff1a;一个为开发者而生的轻量级部署工具最近在折腾一个前后端分离的小项目&#xff0c;从本地开发到服务器部署&#xff0c;中间那套流程真是让人头大。代码提交、构建、测试、再到服务器上拉取、重启服务&#xff0c;一套组合拳下来&#xff0c;少说也得十几…...

WindowsCleaner终极指南:3步告别C盘爆红,让Windows重获新生

WindowsCleaner终极指南&#xff1a;3步告别C盘爆红&#xff0c;让Windows重获新生 【免费下载链接】WindowsCleaner Windows Cleaner——专治C盘爆红及各种不服&#xff01; 项目地址: https://gitcode.com/gh_mirrors/wi/WindowsCleaner 你是否经常遇到C盘变红的警告&…...

CODE-II:百万级心电图AI评估基准与深度学习模型实践

1. 项目概述&#xff1a;当心电图遇上AI&#xff0c;我们如何量化“看懂”的能力&#xff1f;心电图&#xff0c;这个在临床诊断中司空见惯的波形图&#xff0c;背后是心脏每一次搏动的电生理活动记录。医生们通过识别P波、QRS波群、T波的形态、间期和节律&#xff0c;来判断心…...

Casbin Talent 2026:高校开发者开源进阶与工业级项目实战指南

1. 项目概述&#xff1a;Casbin Talent 2026&#xff0c;一个为高校开发者量身定制的开源进阶通道如果你是一名在校大学生&#xff0c;对开源世界充满好奇&#xff0c;渴望在真实的工业级项目中打磨技术&#xff0c;但又觉得像Google Summer of Code&#xff08;GSoC&#xff0…...

reverse-geocoder未来展望:AI增强地理编码与智能位置预测

reverse-geocoder未来展望&#xff1a;AI增强地理编码与智能位置预测 【免费下载链接】reverse-geocoder A fast, offline reverse geocoder in Python 项目地址: https://gitcode.com/gh_mirrors/re/reverse-geocoder 在当今数据驱动的世界中&#xff0c;地理编码技术已…...

别再默认用E1000了!VMware虚拟机网卡选VMXNET3还是E1000E?实测数据告诉你答案

VMware虚拟机网卡性能实战&#xff1a;从理论到选型决策树 在虚拟化环境中&#xff0c;网络性能往往是决定整体系统效率的关键瓶颈之一。作为一名长期奋战在VMware运维一线的技术专家&#xff0c;我见过太多因为网卡选型不当导致的性能问题——从莫名其妙的网络延迟到令人抓狂的…...

开源机械爪技术全解析:从结构设计到ROS集成开发指南

1. 项目概述与核心价值如果你是一名开发者&#xff0c;尤其是在开源社区里摸爬滚打过一阵子&#xff0c;那你肯定对“awesome-xxx”这类项目不陌生。它们通常是一个精心整理的列表&#xff0c;汇聚了某个特定技术领域或工具生态下的优质资源。今天要聊的这个fundgao/awesome-op…...

从零到一:用MMDetection在Ubuntu 20.04上搭建Faster R-CNN模型(含完整配置与避坑指南)

从零到一&#xff1a;Ubuntu 20.04下MMDetection与Faster R-CNN实战全解析 当目标检测技术遇上PyTorch生态&#xff0c;MMDetection框架正在成为工业界和学术界的新宠。本文将带您完成从裸机到完整训练Faster R-CNN模型的实战旅程&#xff0c;特别针对Ubuntu 20.04系统和NVIDIA…...

告别头像上传模糊!用Cropper.js打造完美头像裁剪上传功能(附完整前后端代码)

从零构建高精度头像裁剪系统&#xff1a;Cropper.js全栈实战指南 每次上传头像时&#xff0c;你是否遇到过这样的尴尬——精心选择的图片上传后变得模糊不清&#xff0c;或者被强制拉伸变形&#xff1f;这种糟糕的用户体验在社交平台、企业系统中尤为常见。本文将带你从零构建…...

集合进阶(Collection)

一、集合概述和分类1.1 集合的分类如下图所示&#xff1a;一类是单列集合元素是一个一个的&#xff0c;另一类是双列集合元素是一对一对的。 主要学习Collection单列集合。Collection是单列集合的根接口&#xff0c;也称之为顶层接口&#xff0c;Collection接口下面又有两个子接…...