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

【C++】vector介绍以及模拟实现(超级详细<=>源码并存)

欢迎来到我的Blog,点击关注哦💕

【C++】vector介绍以及模拟实现

  • 前言
    • vector介绍
  • vector常见操作
    • 构造函数
    • iterator
    • capacity
    • modify
  • `vector`模拟实现
    • 存储结构
    • 默认构造函数
    • 构造函数
      • 拷贝构造函数
      • 赋值运算符重载
      • 析构函数
    • 容量(capacity)
      • `size`和`capzcity`
      • reserve
      • resize
    • 修改(modify)
      • push_back
            • 直接将`_finsih`位置解引用赋值,`++_finsih`
      • pop_back
      • insert
      • erase
    • 元素访问(Element access)
      • operator [ ]
    • 迭代器(iterator)
  • 源码

前言

string的特性和用法以及底层的探索已经,虽然string不算container的成员之一,但是也见到了其的影子,接下来让我们看看vector

vector介绍

vector 是 C++ 标准模板库(STL)中的一个动态数组容器,它提供了动态大小调整和高效的随机访问功能。vector 的元素在内存中是连续存储的,这意味着可以通过指针或索引高效地访问元素。vector 自动管理其内部使用的内存,不需要手动分配和释放,支持常见容器操作,如插入、删除、遍历等.

vector常见操作

构造函数

(constructor)构造函数声明接口说明
vector(size_type n, const value_type& val = value_type())构造并初始化n个val
vector (const vector& x); (重点)拷贝构造
vector (InputIterator first, InputIterator last);使用迭代器进行初始化构造

iterator

函数声明接口说明
begin + end返回第一个元素的迭代器+返回最后一个元素下一个位置的迭代器
rbegin + rend返回第一个元素的reverse_iterator,即end位置,返回最后一个元素下一个位置的 reverse_iterator,即begin位置

capacity

函数声明接口说明
capacity获取容量大小
sizesize 获取数据个数
empty判断是否为空
resize改变vector的size
reserve改变vector的capacity

modify

vector增删查改接口说明
push_back(重点)尾插
pop_back (重点)尾删
find查找。(注意这个是算法模块实现,不是vector的成员接口)
insert在position之前插入val
erase删除position位置的数据
swap交换两个vector的数据空间
operator[]像数组一样访问

vector模拟实现

存储结构

结构上使用命名空间myvector进行封装,防止与库冲突,使用class封装成为对象vector

这样typedef的一点是和STL保持一致

  • vector写成类模板,可以支持存贮多种类型数据
  • _start表示数据存储的开始地址
  • _finish表示数据存贮的的下一个地址
  • _end_of_storage表示数据当前开辟的最大空间的地址
namespace myvector
{template<class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;private:iterator _start;iterator _finish;iterator _end_of_storage;};
}

默认构造函数

构造函数

  • 初始化是使用的都是空指针
vector():_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){}
  • 使用nval初始化对象
vector(size_t n, const T& val = T())
{
resize(n, val);
}
  • 根据可以模板的嵌套的性质,再次进行模板的定义
  • 这是使用两个迭代器的进行初始化
template<class InputIterator>vector(InputIterator first, InputIterator last)
{while (first != last){push_back(*first);++first;}
}

拷贝构造函数

  • 利用一个对象初始化另外一个对象传引用
  • new出和传递的对象一样大小的空间,在string类中我们利用了mencpy进行拷贝,在vector中不采用mencpy
    1. mencpy拷贝只能进行内置类型的浅拷贝,不能进行自定义类型的深拷贝
    2. 在这里面进行依次赋值,或者push_back
  • 最后进行_finish_end_of_storage的初始化
vector(const vector<T>& v)
{_start = new T[v.capacity()];for (size_t i = 0; i < v.size(); i++){_start[i] = v._start[i];}_finish = _start + v.size();_end_of_storage = _start + v.capacity();}

赋值运算符重载

  • operator=的参数中是值传递,是实参的拷贝,这里面利用这个特性进数据的交换
  • 返回this指针就是赋值的内容了
void swap(vector<T> v)
{std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_end_of_storage, v._end_of_storage);
}vector<T> operator=(vector<T> v)
{swap(v);return *this;
}

析构函数

  • 判断_start是否为空为空,避免再次析构
~vector()
{if (_start){delete[] _start;_start = _finish = _end_of_storage = nullptr;}}

容量(capacity)

sizecapzcity

  • vectorsizecapacity不同于string类中的不一样,vector定义的是指针
  • 充分利用只针的特性,(指针—指针)是数值,可以计算出capacitysize
size_t size()const 
{
return _finish - _start;
}
size_t capacity()const 
{
return _end_of_storage - _start;
}

reserve

  • 开始判断需要扩容的大小是否大于capacity,以避免重复扩容效率低下
  • 在开始时候记录原始空间的大小,是为了避免迭代器失效
    1. 进行空间的扩容,会将原来的空间析构,原始的计算空间大小已经已释放,指向的_start _finish _end_of_storage已经失效
  • 这里还是采用在这里面进行依次赋值,或者push_back
  • 更新_start _finish _end_of_storage
void reserve(size_t n)
{if (n > capacity()){T* tmp = new T[n];size_t sz = size();if (_start){//memcpy(tmp, _start, sizeof(T)*capacity());//string 类深拷贝for (int i = 0; i < sz; i++){tmp [i] = _start[i];}delete[] _start;}_start = tmp;_finish = sz + _start;_end_of_storage = _start + n;}
}

resize

  • 两种情况

    1. N<capacity

      直接进行移动_finish

    2. N>capacity

      进行容量的检查和扩容,依次赋值val

  • const T& val = T()这句话是针对内置类型和自定义类型,C++这里将内置类型进行了升级

    int = 1; <=> int(1);//这里int有点像构造函数
    
void resize(size_t n, const T& val = T())
{if (n < capacity()){_finish = n + _start;}else{reserve(n);while (_finish != _start + n){*_finish = val;++_finish;}}
}

修改(modify)

push_back

  • 首先进行容量的检查

  • 直接将_finsih位置解引用赋值,++_finsih
void push_back(const T& x)
{if (_finish == _end_of_storage){size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity);}*_finish = x;++_finish;
}

pop_back

  • 复用erase
void pop_back()
{
erase(end()-1);
}

insert

  • 进行断言,防止pos越界访问
  • 判断空间的大小_finish == _end_of_storage
  • size_t step = pos - _startstep记录,距离 _start距离,扩容的时候将原空间释放,pos将无法访问,扩容完成后进行pos的恢复
  • pos位置的数据依次进行移动、
  • 插入pos位置的值,修改_finish
  • 为了避免迭代器失效,返回现在的位置pos
iterator insert(iterator pos, const T& x)
{assert(pos <= _finish && pos >= _start);if (_finish == _end_of_storage){//防止迭代器失效size_t step = pos - _start;size_t newcapacity = capacity() == 0 ? 0 : capacity() * 2;reserve(newcapacity);//防止迭代器失效pos = _start + step;}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;++end;}*pos = x;++_finish;return pos
}

erase

  • 进行断言,防止pos越界访问
  • pos后面的元素向前面移动,进行覆盖
  • 为了避免迭代器失效,返回现在的位置pos
iterator erase(iterator pos)
{assert(pos <= _finish && pos >= _start);while (pos != _finish){*pos = *(pos + 1);pos++;}--_finish;return pos
}

元素访问(Element access)

operator [ ]

  • 实现const非const两种,只读和可读可改
  • 充分利用字符串特性可以进行下标的访问
T& operator[](size_t pos)
{assert(pos >= 0 && pos < size());return _start[pos];
}const T& operator[](size_t pos)const
{assert(pos >= 0 && pos < size());return _start[pos];
}

迭代器(iterator)

  • 本质还是指针,直接进行指针的返回就好
//iterator
const_iterator cbegin()
{return _finish;
}const_iterator cend() const
{return _start;
}
iterator begin()
{return _start;
}
iterator end()
{return _finish;
}
const_iterator begin()const
{return _start;
}
const_iterator end()const
{return _finish;

源码

#include <string.h>
#include <assert.h>
#include <iostream>namespace MyVector
{template <class T>class vector{public://iteratorconst_iterator cbegin(){return _finish;}const_iterator cend() const{return _start;}iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin()const{return _start;}const_iterator end()const{return _finish;}//默认构造vector():_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){}vector(size_t n, const T& val = T()){resize(n, val);}~vector(){if (_start){delete[] _start;_start = _finish = _end_of_storage = nullptr;}}vector(const vector<T>& v){_start = new T[v.capacity()];for (size_t i = 0; i < v.size(); i++){_start[i] = v._start[i];}_finish = _start + v.size();_end_of_storage = _start + v.capacity();}void swap(vector<T> v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_end_of_storage, v._end_of_storage);}template<class InputIterator>vector(InputIterator first, InputIterator last){while (first != last){push_back(*first);++first;}}vector<T> operator=(vector<T> v){swap(v);return *this;}//capacityvoid reserve(size_t n){if (n > capacity()){std::cout << "reserve(size_t n)" << std::endl;T* tmp = new T[n];size_t sz = size();if (_start){//memcpy(tmp, _start, sizeof(T)*capacity());//string 类深拷贝for (int i = 0; i < sz; i++){tmp [i] = _start[i];}delete[] _start;}_start = tmp;_finish = sz + _start;_end_of_storage = _start + n;}}size_t size(){return _finish - _start;}size_t capacity(){return _end_of_storage - _start;}size_t size()const {return _finish - _start;}size_t capacity()const {return _end_of_storage - _start;}//modifyvoid push_back(const T& x){if (_finish == _end_of_storage){size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity);}*_finish = x;++_finish;}void pop_back(){erase(end()-1);}void insert(iterator pos, const T& x){assert(pos <= _finish && pos >= _start);if (_finish == _end_of_storage){//防止迭代器失效size_t step = pos - _start;size_t newcapacity = capacity() == 0 ? 0 : capacity() * 2;reserve(newcapacity);//防止迭代器失效pos = _start + step;}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;++end;}*pos = x;++_finish;return pos;}void erase(iterator pos){assert(pos <= _finish && pos >= _start);while (pos != _finish){*pos = *(pos + 1);pos++;}--_finish;return pos;}void resize(size_t n, const T& val = T()){if (n < capacity()){_finish = n + _start;}else{reserve(n);while (_finish != _start + n){*_finish = val;++_finish;}}}T& operator[](size_t pos){assert(pos >= 0 && pos < size());return _start[pos];}const T& operator[](size_t pos)const{assert(pos >= 0 && pos < size());return _start[pos];}private:iterator _start;iterator _finish;iterator _end_of_storage;};}

相关文章:

【C++】vector介绍以及模拟实现(超级详细<=>源码并存)

欢迎来到我的Blog&#xff0c;点击关注哦&#x1f495; 【C】vector介绍以及模拟实现 前言vector介绍 vector常见操作构造函数iteratorcapacitymodify vector模拟实现存储结构默认构造函数构造函数拷贝构造函数赋值运算符重载析构函数 容量&#xff08;capacity&#xff09;si…...

【Redis 进阶】主从复制(重点理解流程和原理)

在分布式系统中为了解决单点问题&#xff08;某个服务器程序只有一个节点&#xff08;只搞一个物理服务器来部署这个服务器程序&#xff09;。可用性不高&#xff1a;如果这个机器挂了意味着服务就中断了&#xff1b;性能 / 支持的并发量比较有限&#xff09;。通常会把数据复制…...

Git常用命

转自&#xff1a;https://blog.csdn.net/ahjxhy2010/article/details/80047553 1.查看某个文件或目录的修改历史 git log filename #查看fileName相关的commit记录 git log -p filenam # 显示每次提交的diff#只看某次提交中的某个文件变化&#xff0c;commit-id  文件名…...

强化学习时序差分算法之Q-learning算法——以悬崖漫步环境为例

0.简介 基于时序差分算法的强化学习算法除了Sarsa算法以外还有一种著名算法为Q-learning算法&#xff0c;为离线策略算法&#xff0c;与在线策略算法Sarsa算法相比&#xff0c;其时序差分更新方式变为 Q(St,At)←Q(St,At)α[Rt1γmaxaQ(St1,a)−Q(St,At)] 对于 Sarsa 来说&am…...

111推流111

推流推流...

刷题——数组中只出现一次的两个数字

数组中只出现一次的两个数字_牛客题霸_牛客网 描述 一个整型数组里除了两个数字只出现一次&#xff0c;其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。 数据范围&#xff1a;数组长度 2≤n≤10002≤n≤1000&#xff0c;数组中每个数的大小 0<val≤100000…...

《剖析程序员面试“八股文”:助力、阻力还是噱头?》

#“八股文”在实际工作中是助力、阻力还是空谈&#xff1f; 作为现在各类大中小企业面试程序员时的必问内容&#xff0c;“八股文”似乎是很重要的存在。但“八股文”是否能在实际工作中发挥它“敲门砖”应有的作用呢&#xff1f;有IT人士不禁发出疑问&#xff1a;程序员面试考…...

Redis过期key的删除策略

在 Redis 中&#xff0c;设置了过期时间的键在过期时间到达后&#xff0c;并不会立即从内存中删除。如果不是&#xff0c;那过期后到底什么时候被删除呢&#xff1f; 下面对这三种删除策略进行具体分析。 立即删除&#xff1a; 立即删除能够保证内存数据的及时性和空间的有效…...

软件管理

设备挂载在目录下才可以读 挂载类似于将u盘插在电脑上 mount /dev/sr0 /opt/openeuler/ vim /etc/rc.d/rc.local #开机自运行脚本&#xff0c;将挂载命令写入脚本&#xff0c;并给这个脚本执行权限 chmod x /etc/rc.d/rc.local [rootlocalhost ~]# cd /etc/yum.repos.d/ […...

【2024】Datawhale AI夏令营 Task3笔记——Baseline2部分代码解读及初步上分思路

【2024】Datawhale AI夏令营 Task3笔记——Baseline2部分代码解读及初步上分思路 本文对可完成赛事“逻辑推理赛道&#xff1a;复杂推理能力评估”初赛的Baseline2部分关键代码进行详细解读&#xff0c;介绍Baseline2涉及的关键技术和初步上分思路。 Baseline2代码由Datawhal…...

软件测试——测试分类(超超超齐全版)

为什么要对软件测试进行分类 软件测试是软件⽣命周期中的⼀个重要环节&#xff0c;具有较⾼的复杂性&#xff0c;对于软件测试&#xff0c;可以从不同的⻆度加以分类&#xff0c;使开发者在软件开发过程中的不同层次、不同阶段对测试⼯作进⾏更好的执⾏和管理测试的分类⽅法。…...

深入解析 Go 语言 GMP 模型:并发编程的核心机制

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家&#xff1a;点击跳转到网站&#xff0c;对人工智能感兴趣的小伙伴可以点进去看看。 前言 本章是Go并发编程的起始篇章&#xff0c;在未来几篇文章中我们会…...

PHP中如何处理字符串

在PHP中&#xff0c;处理字符串是一项非常常见的任务&#xff0c;PHP提供了大量的内置函数来方便地处理字符串。以下是一些常用的字符串处理函数&#xff1a; strlen() - 返回字符串的长度。 php复制代码 $text "Hello, World!"; echo strlen($text); // 输出&…...

windows内存泄漏检查汇总

VLD(Visual Leak Detector) 下载 官方下载地址2.5 另一分支2.7 安装 点击运行安装...

yolo格式数据集之空中及地面拍摄道路病害检测7种数据集已划分好|可以直接使用|yolov5|v6|v7|v8|v9|v10通用

yolo格式数据集之空中及地面拍摄道路病害检测7种数据集已划分好|可以直接使用|yolov5|v6|v7|v8|v9|v10通用 本数据为空中及地面拍摄道路病害检测检测数据集&#xff0c;数据集数量如下&#xff1a; 总共有:33585张 训练集&#xff1a;6798张 验证集&#xff1a;3284张 测试集&a…...

[Meachines] [Easy] Mirai Raspberry树莓派默认用户登录+USB挂载文件读取

信息收集 IP AddressOpening Ports10.10.10.48TCP:22,53,80,1276,32400,32469 $ nmap -p- 10.10.10.48 --min-rate 1000 -sC -sV PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 6.7p1 Debian 5deb8u3 (protocol 2.0) | ssh-hostkey: | 1024 aa:ef:5c:…...

从零开始安装Jupyter Notebook和Jupyter Lab图文教程

前言 随着人工智能热浪&#xff08;机器学习、深度学习、卷积神经网络、强化学习、AGC以及大语言模型LLM, 真的是一浪又一浪&#xff09;的兴起&#xff0c;小伙伴们Python学习的热情达到了空前的高度。当我20年前接触Python的时候&#xff0c;做梦也没有想到Python会发展得怎么…...

数据库魔法:SQL Server中自定义分区函数的奥秘

数据库魔法&#xff1a;SQL Server中自定义分区函数的奥秘 在SQL Server中&#xff0c;分区表是管理大型表和提高查询性能的强大工具。分区函数和分区方案允许你根据特定的规则将数据分散到不同的文件组中。本文将深入探讨如何在SQL Server中实现数据库的自定义分区函数&#…...

网页禁止移除水印

一般的话水印分为明水印和暗水印两种 明水印的话就是在视频canvas上面蒙上一个div&#xff08;如我上篇文章&#xff09; &#xff0c;暗水印的话就是把文字通过技术嵌入到图像里。 具体实现的话可以使用MutationObserver API 来监视 DOM 的变化&#xff0c;特别是针对目标节…...

Node Red 与axios简易测试环境的搭建

为了学习在vue3中如何使用axios&#xff0c;我借Sider Fusion的帮助搭建了基于node的简易测试环境。 Axios 是一个基于 Promise 的 HTTP 客户端&#xff0c;通常用于浏览器环境&#xff0c;但它也可以在 Node.js 环境中使用。因此&#xff0c;可以在 Ubuntu 的 Bash 环境下通过…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望

文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例&#xff1a;使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例&#xff1a;使用OpenAI GPT-3进…...

遍历 Map 类型集合的方法汇总

1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂

蛋白质结合剂&#xff08;如抗体、抑制肽&#xff09;在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上&#xff0c;高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术&#xff0c;但这类方法普遍面临资源消耗巨大、研发周期冗长…...

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法&#xff1a;netstat [选项] 功能&#xff1a;查看网络状态 常用选项&#xff1a; n 拒绝显示别名&#…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业

6月9日&#xff0c;国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解&#xff0c;“超级…...

微信小程序 - 手机震动

一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注&#xff1a;文档 https://developers.weixin.qq…...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

佰力博科技与您探讨热释电测量的几种方法

热释电的测量主要涉及热释电系数的测定&#xff0c;这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中&#xff0c;积分电荷法最为常用&#xff0c;其原理是通过测量在电容器上积累的热释电电荷&#xff0c;从而确定热释电系数…...