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

news2025/2/12 18:19:31

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;//指向空间位置的结束

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

centos7 安装桌面

先装 xrdp $ sudo yum install -y epel-release $ sudo yum install -y xrdp $ sudo systemctl enable xrdp $ sudo systemctl start xrdp开防火墙端口 $ sudo firewall-cmd --add-port3389/tcp --permanent $ sudo firewall-cmd --reload比较喜欢 GNOME $ sudo yum groupin…

python自动化:系统凭据的获取与添加

在自动化流程开发中&#xff0c;我们经常会遇到输入帐号、密码的情况&#xff0c;帐号明文还可以&#xff0c;但是密码不想展示给他人&#xff0c;但是不想自己去手动输入怎么办&#xff1f; 基于以上情况我们可以使用windows自带的凭据管理器进行密码存储&#xff0c;其实我们…

数据结构与算法之时间空间复杂度

主要简介 1. 时间复杂度:运行一个程序所花费的时间。O() 2. 空间复杂度&#xff1a;运行程序所需要的内存 OOM&#xff0c;开了空间的地方&#xff0c; 比如 数组 链表&#xff0c;缓存对象&#xff0c;递归 时间复杂度表示方式 O(1),O(n),O(nlogn),O(n^2),O(n1),O(logn),O(n!…

造个轮子-任务调度执行小框架-任务清单执行器实现

文章目录 前言执行器流程提交流程线程池实现执行器实现接口状态标志执行周期实现清单代理创建清单项执行总结前言 okey,上一篇文章我们提到了,如何实现它的一个清单的一个代理。这里的话我们来捋一捋我们的这个执行流程是啥: 所以的话,我们的我们这里今天要做的是这个执行…

Jmeter - 函数助手

__StringFromFile StringFromFile函数用于获取文本文件的值&#xff0c;一次读取一行 1、输入文件的全路径&#xff1a;填入文件路径 2、存储结果的变量名&#xff08;可选&#xff09; 3、Start file sequence number (opt)&#xff1a;初始序列&#xff0c;例如从第3行开始读…

ATFX汇评:美7月通胀率数据基本符合预期,美指仍无法站稳103关口

ATFX汇评&#xff1a;据美劳工部&#xff0c;美国7月未季调CPI年率&#xff0c;最新值3.2&#xff0c;高于前值3%&#xff0c;低于预期值3.3%&#xff0c;这标志着连续12个月的下降已经停止&#xff1b;7月未季调核心CPI年率&#xff0c;最新值4.7%&#xff0c;低于前值4.8%&am…

Poco框架(跨平台自动化测试框架)

Poco基于UI控件搜索原理 &#xff0c;适用于Android、iOS原生和各种主流的游戏引擎应用。 中文官方文档&#xff1a;欢迎使用Poco (ポコ) UI自动化框架 — poco 1.0 文档 参考文档&#xff1a; Poco介绍 - Airtest Project Docs 环境准备 安装库&#xff1a;pip install po…

本地安装hadoop及其依赖组件

安装目录以及各个版本 大数据安装版本 软件版本备注hadoophadoop-3.3.4hdfs基础sparkspark-3.2.4-bin-hadoop3.2计算框架zookeeperapache-zookeeper-3.5.7-bin分布式服务器hbasehbase-2.4.11列式存储hiveapache-hive-3.1.3-bin数仓元数据 启动服务 su - hadoop -- 启动hadoo…

Vue3 nodejs 安装和配置---vue3教程一

文章目录 前言1、nodejs安装2、配置缓存路径&#xff1a;3、 阿里镜像cnpm使用4、 yarn安装5、配置nodejs国内镜像6、查看各个版本7、node npm yarn概念8、nodejs 和vue 关系外传 前言 本人主做后端Java&#xff0c;以前搞全栈开发是&#xff0c;还没有vue,rect等前端框架&…

如何解决物流投诉问题,拥有更多的回头客?

在电商物流中&#xff0c;客户投诉比较多的一块通常是配送延迟或派送问题。以下是一些可能导致此类问题的原因以及解决方法&#xff1a; 配送员数量不足或调度不合理&#xff1a;电商企业可能面临配送员不足的情况&#xff0c;导致派送时间延长或出现派送失败等问题。解决方法…

【写一个函数,判断一个字符串是否为另外一个字符串旋转之后的字符串】

写一个函数&#xff0c;判断一个字符串是否为另外一个字符串旋转之后的字符串 1.题目 写一个函数&#xff0c;判断一个字符串是否为另外一个字符串旋转之后的字符串。 例如&#xff1a;给定s1 AABCD和s2 BCDAA&#xff0c;返回1 给定s1abcd和s2ACBD&#xff0c;返回0. AABCD左…

40 proc 文件系统

前言 在 linux 中常见的文件系统 有很多, 如下 基于磁盘的文件系统, ext2, ext3, ext4, xfs, btrfs, jfs, ntfs 内存文件系统, procfs, sysfs, tmpfs, squashfs, debugfs 闪存文件系统, ubifs, jffs2, yaffs 文件系统这一套体系在 linux 有一层 vfs 抽象, 用户程序不用…

为何不禁用危险的memcpy或更新memcpy源码,而使用更安全的memcpy_s

关于使用更安全的memcpy_s而不禁用危险的memcpy或更新memcpy源码的问题&#xff0c;以下是一些考虑因素&#xff1a;首先&#xff0c;memcpy_s并不是绝对安全的实现。尽管它要求您提供一个长度参数来确保不会发生溢出或越界问题&#xff0c;但这个长度仍然需要您自己提供&#…

液压系统比例阀放大器US-DAT2-F、US-DAPQ-N、US-DAS2

比例放大器US-DAS1、US-DAS2、US-DAPQ-N、US-DAPQ-H、US-P1、US-P2、US-DAT2-F、US-DAT2-A适配控制各种不带位置反馈比例阀&#xff1b; 控制如博世力士乐&#xff08;Bosch Rexroth&#xff09;、伊顿威格士&#xff08;EATON Vickers&#xff09;、油研&#xff08;YUKEN&am…

从小白到大神之路之学习运维第78天-------Kubernetes集群应用部署测试

第四阶段 时 间&#xff1a;2023年8月11日 参加人&#xff1a;全班人员 内 容&#xff1a; Kubernetes集群应用部署测试 目录 应用部署测试 应用部署测试 下面我们部署一个简单的Nginx WEB服务&#xff0c;该容器运行时会监听80端口。 &#xff08;一&#xff09;环境…

vue报错‘vue-cli-service‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。

运行我的后台管理项目的时候报错&#xff1a;‘vue-cli-service’ 不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件。 查看自己package.json中是否有vue 或者vue-cli-service 查看自己项目目录下有没有node_module文件夹&#xff0c;如果有删除&#xff0c;然后…

uprobe trace多线程mutex等待耗时

问题背景环境 ubuntu2204 服务器支持debugfs uprobe&#xff0c;为了提升应用程序的性能&#xff0c;需要量化不同参数下多线程主程序等待在mutex上的耗时区别 linux document中对uprobe events的说明如下 uprobetracer.rst - Documentation/trace/uprobetracer.rst - Linux…

什么是分布式系统,如何学习分布式系统

正文 虽然本人在前面也写过好几篇分布式系统相关的文章&#xff0c;主要包CAP理论&#xff0c;分布式储存与分布式事务&#xff0c;但对于分布式系统&#xff0c;并没有一个跟清晰的概念。分布式系统涉及到很多的技术、理论与协议&#xff0c;很多人也说&#xff0c;分布式系统…

股票自动交易接口开发原理及源码分享

股票自动交易接口的开发原理涉及多个方面&#xff0c;主要包括以下几个步骤&#xff1a; 1. 数据接口获取&#xff1a;通过连接到证券交易所或第三方数据提供商的API&#xff0c;获取实时市场数据&#xff0c;包括股票报价、交易成交量、买卖盘口等信息。 2. 策略定义&#x…

分类预测 | MATLAB实现SMA-CNN-BiLSTM-Attention多输入分类预测

分类预测 | MATLAB实现SMA-CNN-BiLSTM-Attention多输入分类预测 目录 分类预测 | MATLAB实现SMA-CNN-BiLSTM-Attention多输入分类预测分类效果基本介绍模型描述程序设计参考资料 分类效果 基本介绍 1.MATLAB实现SMA-CNN-BiLSTM-Attention多输入分类预测&#xff0c;CNN-BiLSTM结…