C++——vector介绍及其简要模拟实现

vector的介绍

此主题介绍转载自(https://cplusplus.com/reference/vector/vector/)

1.vector是一个表示可变大小数组的序列容器

2.vector同数组一样,采用连续存储空间来存储元素,这样可以用下标来对vector中的元素进行访问,但是vector的大小可以动态改变,,且可以其元素被容器vector自动处理。

3.从本质上讲,vector使用动态分配数组来存储器元素,当有元素插入的时候,这个数组需要重新分配大小,然后再将全部元素移入到这个数组里,但是这个过程及其消耗时间,所以为了解决这个问题,vector并不会每次都重新分配大小。

vector的使用/用法

数组的创建

vector <int> v1;//创建一个整型数组v1
vector <int> v2(10,0);//初始化一个数组,count nums  存放count个nums
vector<int> v5(v4);//将v4中的元素拷贝给v5

vector iterator 迭代器的使用

vector<int> v3(v2.begin(),v2.end());

//string类和vector类的的迭代器是互通的
string str("hello world");
vector<int> v4(str.begin(), str.end());
vector<int> v5(v4);

vector<int>::iterator it = v4.begin();//同时也可以进行迭代器,实现循环遍历
while (it != v4.end())
{
	cout << *it << " ";
	++it;
}
cout << endl;
	for (auto e : v5)
{
	cout << e << " ";
}
cout << endl;

vector空间增长相关函数

vector<int> v;
v.reserve(100);//reserve改变的是capacity
v.resize(100);//reserve改变的是size 若仅开拓空间,那么仍然不能使用

v.size();//读取size
v.capacity();//读取capacity

vector的增删查改

vector<int> v;
//尾插
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);

//尾删
v.pop_back()

//查找
auto it=find(v.begin(),v.end(),3);//first last dest(firts和last都是迭代器,dest是查找的目标,会返回查找目标的下标)

//删除
it =find(v.begin(),v.end(),3);
v.erase(it);//删除找到需要删除的数据的下标,然后进行删除

//清除数据
v.clear();

//释放空间呢?
v.shrink_to_fit();

//同时也能按照数组下标去访问
for(int i=0;i<v.size();i++)
{
    cout<<v[i]<<endl;
}

vector类和string类的函数用法基本相同,所以这里不作过多的解释,用法也很简单,详细可以参考(https://cplusplus.com/reference/vector/vector/)


vector简要模拟

首先我们要知道vector实现的底层逻辑。找其源代码

可以知道其是进行指针的初始化,模板命名重命名为' iterator ' ' T* == iterator '

 大致模板

namespace an
{
	template<class T>
	class vector 
	{
	public:
		typedef T* iterator;
		typedef const T* const_iterator;
		iterator begin()
		iterator end()
		vector()
		{}
        vector(size_t n,const T& val=T());
        vector(const vector<T>& v);
        void swap(vector<T>& v);
        vector<T>& operator=(vector<T> tmp);
		~vector()
        void reserve(size_t n);
		void resize(size_t n,const T& val=T());
		void push_back(const T& x)
		
		T& operator[](size_t pos)
		const T& operator[](size_t pos) const
		size_t capacity();
		size_t size();
	    void insert(iterator& pos, const T& x);
        iterator erase(iterator pos);
	private:
		iterator _start;//原生指针,其实就是T* 
		iterator _finish;
		iterator _endofstorage;
	};
}

初始化

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

获取大小/容量

size_t size() const
{
    return _finish-_start;//指针相减就是个数
}

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

迭代器开头/结尾

iterator begin()
{
    return _start;
}
iterator end()
{
    return _finish;
}

开拓空间/重新定义空间

void reserve(size_t n)
{
    if(n>capacity)
    {
        size_t sz=size();
        T* tmp=new T[n];//扩容,需要先开辟一个符合大小的空间,然后再拷贝进去
        if(_start)//如果拷贝的空间内不为空
        {
            for(size_t i=0;i<sz;i++)
            {
                tmp[i]=_start[i];//由于是指针,所以需要深拷贝,memcpy仅能支持浅拷贝
            }
            delete[] _start;//清除空间
        }    
        _start=tmp;
        _finish=_start+sz;
        _endofstorage=_start+n;
    }
}

void resize(size_t n,const T& val=T())
{
    if(n<=size())    
    {        
        _finish=_start+n;
    }
    else
    {
        reserve(n);
        while(_finish<_start+n)    
        {
            *_finish=val;
            ++_finish;
        }    
    }
}    

尾插

void push_back(const T& x)
{
    if(_finish==_endofstorage)
    //扩容里的代码也可以用reserve(capacity()==0?4:capacity()*2)来代替
    {
        size_t sz=size();
        size_t cp=capacity()==0?4:22*capacity();
        T* tmp=new T[cp];
        if(_start!=nullptr)
        {
            memcpy(tmp,_start,sizeof(T)*size());
            delete[] _start;
        }
        _start=tmp;
        _finish=_start+sz;
        _endofstorage=_start+cp;
    }    
    *_finish=x;//最后一个位置赋值
     ++_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];
}

随机位置插入/删除

void insert(iterator pos,const T& x)
{
    assert(pos>=_start);
    assert(pos<=_finish);
    if(_finish==_endofstorage)
    {
        size_t len=pos-_start;
        reserve(capacity() == 0 ? 4 : capacity() * 2);
        pos=_start+len;//注意,这里更新后的start指向的空间和原来的pos不一样,需要进行更新
    }
    iterator end=_finish-1;
    while(end>=pos)
    {
        *(end+1)=*end;
        --end;
    }
    *pos=x;
    ++_finish;
}

iterator erase(iterator pos)
{
    assert(pos>=_start);
    assert(pos<=_finish);
    iterator it=pos+1;
    while(it<_finish)
    {
        *(it-1)=*it;
        ++it;
    }
    --_finish;
    return pos;//返回删除数据的下一个数据的位置
}

赋值重载/拷贝构造

vector(const vector<T>& v)
{
    reserve(v.capacity());
    for(auto e: v)
    {
        push_back(e);
    }
}


void swap(vector<T>& v)
{
	std::swap(_start, v._start);
	std::swap(_finish, v._finish);
	std::swap(_endofstorage, v._endofstorage);
}
vector<T>& operator=(vector<T> tmp)
{
	swap(tmp);//有this指针,直接作用于要作用的对象
	return *this;
}

迭代器初始化

template<class InputIterator>
vector(InputIterator first, InputIterator last)//迭代器初始化
{
	while (first != last)
	{
		push_back(*first);
		++first;
	}
}

vector初始值初始化

vector(size_t n,const T& val=T())//n个数据去初始化
{
	reserve(capacity());
	for (size_t i = 0; i < n; i++)
    {
		push_back(val);
	}
}
//为了与迭代器的模板类型进行区分,所以这里形参T加上了' & ' 符号

统一初始化

因为上述有多个构造函数,为了简化代码不出现多个初始化列表,所以在声明的时候就进行定义

private:
	//原生指针,其实就是T* 
	iterator _start=nullptr;//指向数据的开始 
	iterator _finish=nullptr;//指向数据的结束
	iterator _endofstorage=nullptr;//指向空间位置的结束

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/71371.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AAAI论文阅读

文章目录 Open-Vocabulary Multi-Label Classifcation via Multi-Modal Knowledge Transfer——知识蒸馏的范畴Med-EASi: Finely Annotated Dataset and Models for Controllable Simplifcation of Medical Texts——医学领域数据集构建“Nothing Abnormal”: Disambiguating M…

ELK 将数据流转换回常规索引

ELK 将数据流转换回常规索引 现象&#xff1a;创建索引模板是打开了数据流&#xff0c;导致不能创建常规索引&#xff0c;并且手动修改、删除索引模板失败 "reason" : "composable template [logs_template] with index patterns [new-pattern*], priority [2…

【果树农药喷洒机器人】Part7:静态PWM变量喷药实验

&#x1f4e2;&#xff1a;如果你也对机器人、人工智能感兴趣&#xff0c;看来我们志同道合✨ &#x1f4e2;&#xff1a;不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 &#x1f4e2;&#xff1a;文章若有幸对你有帮助&#xff0c;可点赞 &#x1f44d;…

YOLOv5可视化界面

Pyside6可视化界面 安装Pyside6 激活之前的虚拟环境yolov5 在该环境的终端输入以下命令 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyside6输入where python找到当前使用的Python的路径 找到该路径下的designer.exe文件&#xff08;/Lib/site-packages/PySi…

Electron 应用实现截图并编辑功能

Electron 应用实现截图并编辑功能 Electron 应用如何实现截屏功能&#xff0c;有两种思路&#xff0c;作为一个框架是否可以通过框架实现截屏&#xff0c;另一种就是 javaScript 结合 html 中画布功能实现截屏。 在初步思考之后&#xff0c;本文优先探索使用 Electron 实现截屏…

docker小白第二天

centos上安装docker docker官网&#xff0c;docker官网&#xff0c;找到下图中的doc文档。 进入如下页面 选中manuals&#xff0c;安装docker引擎。 最终centos下的docker安装文档链接&#xff1a;安装文档链接. 具体安装步骤&#xff1a; 1、打开Centos&#xff0c;输入命…

如何实现Vue路由的二级菜单

目录 Vue路由&#xff08;一、二级路由&#xff09; 一级路由配置 二级路由配置 Vue中展示二级路由的默认模块/二级路由默认显示 Vue路由&#xff0c;二级路由及跳转 如何用vue实现二级菜单栏 ◼️ 相关参考资料 当朋友们看到这个文章时想必是想要了解vue路由二级菜单相…

react学习笔记——4. 虚拟dom中处理动态数据

如下需求 方式1&#xff1a; 直接在ul中使用{data}&#xff0c;是可以遍历数据的&#xff0c;然后如果将data改成下面形式&#xff0c;也是可以实现的。但是如果data是一个对象&#xff0c;则不能便利。 const data [<li>Angular</li>, <li>React</li&g…

【分布式】Viewstamped Replication Revisited

篇前感悟&#xff1a; 阅读分布式系统文章的意义其实并不在于你个人真正地去开发这样一个基于这种协议的系统&#xff0c;因为真正去开发一个高可用的分布式系统实在是太难了&#xff08;对我来说…&#xff09;更多的还是汲取其中的思想&#xff0c;包括设计思路&#xff0c;优…

2023河南萌新联赛第(五)场:郑州轻工业大学-F 布鲁特佛斯

2023河南萌新联赛第&#xff08;五&#xff09;场&#xff1a;郑州轻工业大学-F 布鲁特佛斯 https://ac.nowcoder.com/acm/contest/62977/F 文章目录 2023河南萌新联赛第&#xff08;五&#xff09;场&#xff1a;郑州轻工业大学-F 布鲁特佛斯题意解题思路代码 题意 给定一个…

「C/C++」C/C++可变参数函数

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「C/C」C/C程序设计&#x1f4da;全部专栏「UG/NX」NX二次开发「UG/NX」BlockUI集合「VS」Visual Studio「QT」QT5程序设计「C/C」C/C程序设计「Win」Windows程序设计「DSA」数据结构与算法「File」数据文件格式 目录 当你需要…

exec族函数

本节学习exec族函数&#xff0c;并大量参考了以下链接&#xff1a; linux进程---exec族函数(execl, execlp, execle, execv, execvp, execvpe)_云英的博客-CSDN博客 exec族函数函数的作用 我们用fork函数创建新进程后&#xff0c;经常会在新进程中调用exec函数去执行另外一个程…

【数据中台商业化】数据中台微前端实践

一&#xff0c;需求背景 1 业务背景 在以往的业务场景中&#xff0c;用户进入五花八门的菜单体系中&#xff0c;往往会产生迷茫情绪&#xff0c;难以理解平台名称及具体作用&#xff0c;导致数据开发与管理学习成本较高&#xff0c;降低工作效率。为此我们整合从数据接入&…

Node.js |(四)HTTP协议 | 尚硅谷2023版Node.js零基础视频教程

学习视频&#xff1a;尚硅谷2023版Node.js零基础视频教程&#xff0c;nodejs新手到高手 文章目录 &#x1f4da;HTTP概念&#x1f4da;窥探HTTP报文&#x1f4da;请求报文的组成&#x1f407;HTTP请求行&#x1f407;HTTP请求头&#x1f407;HTTP的请求体 &#x1f4da;响应报文…

《连锁零售超市经营数据分析实战》学习笔记

这篇文章整理自 接地气的陈老师 x 和鲸社区 | 连锁零售超市经营数据分析实战 活动业务讲解会【接地气的陈老师】的讲解 更多数据分析动手实践活动欢迎访问>>和鲸社区活动 活动背景 现在你是某零售企业的商业数据分析师&#xff0c;你为管理层提供日常经营数据。到一年年…

亚信科技AntDB数据库与库瀚存储方案完成兼容性互认证,联合方案带来约20%性能提升

近日&#xff0c;亚信科技AntDB数据库与苏州库瀚信息科技有限公司自主研发的RISC-V数据库存储解决方案进行了产品兼容测试。经过双方团队的严格测试&#xff0c;亚信科技AntDB数据库与库瀚数据库存储解决方案完全兼容、运行稳定。除高可用性测试外&#xff0c;双方进一步开展TP…

Linux学习之sed多行模式

N将下一行加入到模式空间 D删除模式空间中的第一个字符到第一个换行符 P打印模式空间中的第一个字符到第一个换行符 doubleSpace.txt里边的内容如下&#xff1a; goo d man使用下边的命令可以实现把上边对应的内容放到doubleSpace.txt。 echo goo >> doubleSpace.txt e…

【TypeScript】this指向,this内置组件

this类型 TypeScript可推导的this类型函数中this默认类型对象中的函数中的this明确this指向 怎么指定this类型 this相关的内置工具类型转换ThisParameterType<>ThisParameterType<>ThisType TypeScript可推导的this类型 函数中this默认类型 对象中的函数中的this…

【elasticSearch系】3.完整搭建详尽版elk

话不多说,我们先看下经典的elk 是由哪些组件搭建组合起来的 elasticSearch和kibana搭建 可以查看之前我搭建elasticsearch和kibana 的这篇文章 logstash搭建 为了和之前我搭建elasticsearch和kibana版本保持一致,这里我们还是选择7.17.3 下载地址 点击下载,这里为了方…

数据库中的连表更新和连表删除

1.连表更新 准备两张表,id一样,但是姓名不一样, 需求根据id让姓名保持一致 执行的sql UPDATE teacher_copy1 AS b INNER JOIN teacher c ON b.TId c.TId set b.tnamec.tname 执行结果 2.连接删除 DELETE a FROMteacher_copy1 AS aINNER JOIN teacher b ON a.TId b.TId