[c++]—vector类___提升版(带你了解vector底层的运用)

我写我 不论主谓宾 可以反复错

🌈vector的介绍 

  • 1.vector是表示可变大小数组的序列容器
  • 2.就像数组一样,vector也采用的连续存储空间来存储元素,也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理
  • 3.本质讲,vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言,这是一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大小。
  • 4.vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的
  • 5.因此,vector占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增长
  • 6.与其它动态序列容器相比(deque, list and forward_list), vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起list和forward_list统一的迭代器和引用更好

模拟实现的时候,这里是指针。 

💻vector的构造与析构

那我们现在敲个构造和析构函数吧。


  • 不需要任何初始化的构造,用这种方法初始化,size和capacity都是0,后续需要插入就会扩容。这种初始化方式也是最容易实现的
模拟实现
        vector()
        {}
//因为vector类中的private成员中,已经给了初始值,如果不初始化,会默认给的nullptr初始值。

  • 两个参数,第一个参数是size_t类型,第二个参数是const T& val = T(),T是模板,10个空间都会被初始化为字符a
std::vector<char> v(10,'a');
---
模拟实现
		vector(size_t n, const T& val = T())
		{
			resize(n, val);
		}
  • 给你一个区间,根据这个区间进行初始化,当然,这个区间要是迭代器类型
std::string a = "abcdef";
std::vector<char> v(a.begin(),a.end());
---
模拟实现
		template<typename InputIterator>
		vector(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}
		
		//在这个构造函数中,使用了两个模板参数typename InputIterator。这是因为区间可以用不同类型的迭代器进行表示,例如,可以是普通指针、容器的迭代器、自定义类型的迭代器等。这两个模板参数允许我们灵活地适应不同种类的迭代器,并使用相应的逻辑来处理区间的元素。
  • 当然还有一个构造函数,这个构造函数是为了和第三个构造函数做一个区分,当两个参数都是int类型的时候。
模拟实现
vector(int n, const T& val = T())
{
	resize(n, val);
}
//如果两个参数都是int,C++会自动的寻找与类型最匹配的构造函数,这样找到的不是第三个构造函数,是第四个,因为InputIterator是一个迭代器类型,与int类型不匹配,不额外写一个就会出错。

 后面的函数实现后,我会进行测试。

🕶️析构 

//析构
	~vector()
	{
		if (_start)
		{
			delete[] _start;
			_start = _finish = _endofstorage = nullptr;
		}
	}

💻vector拷贝构造和赋值

🕶️拷贝构造

	//拷贝构造
	vector(const vector<T>& v)
	{
		_start = new T[v.capacity()];//开辟一个空间
		//memcpy(_start, v._start, sizeof(T)*v.size());
		for (int i = 0; i < v.size(); i++)
		{
			_start[i] = v._start[i];
		}
		_finish = _start + v.size();
		_endofstorage = _start + v.capacity();
	}


🕶️赋值

//赋值
	//v1=v2//这里我用现代写法
	void swap(vector<T>& v)
	{
		std::swap(_start, v._start);
		std::swap(_finish, v._finish);
		std::swap(_endofstorage, v._endofstorage);
	}
用于交换的函数,传参传的是一个临时变量,会先执行构造函数,然后将v和this进行交换,再返回,执行完之后,会进行析构函数,这个时候就会把临时变量给释放。
	vector<T>& operator= (const vector& v)
	{
		swap(v);
	}

💻begin和end(迭代器)

  • begin:一个指向第一个元素的迭代器
  • end:一个指向最后一个元素的下一个位置的迭代器
typedef T* iterator;
		typedef const T*const_iterator;

		//begin和end
		iterator begin()
		{
			return _start;
		}
		iterator end()
		{
			return _end;
		}
        //上面可以改

		const_iterator begin()const
		{
			return _start;
		}
		const_iterator end()const
		{
			return _end;
		}
        //加const就不可以修改了

💻size和capacity

//size和capacity
	size_t size()const
	{
		return _finish - _start;
	}
	size_t capacity()const
	{
		return _endofstorage - _start;
	}


💻empty和clear

  • empty是一个判断是否为空的函数
  • clear是用来清空容器数据的函数
//empty和clear
	/*empty是一个判断是否为空的函数
	clear是用来清空容器数据的函数*/
	bool empty()
	{
		return _start == _finish;
	}
	void clear()
	{
		_start = _finish = nullptr;
	}

💻reserve和resize 

这两个都是扩容的函数,具体作用和string里的一样。

  • reserve中的参数如果比capacity大,就进行扩容,如果比capacity小,可不理会.

//reserve
	void reserve(size_type n)
	{
		if (n > capacity())
		{
			int sz = size();
			T* tmp = new T[n];
			if (_start)
			{
				for (size_t i = 0; i < sz; i++)
				{
					tmp[i] = _start[i];
				}
				delete[] _start;
			}
			_start = tmp;
			_finish = _start + sz;
			_endofstorage = _start + n;
		}
	}
  • resize中的参数如果比capacity大,则进行扩容,并将扩容的部分赋值为val,反之,进行缩容,也就是原地减小

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

💻insert和erase 

🕶️insert

如果_finish=_endofstorage,那么就得扩容,扩容之后是在新的空间进行的,,所以我们要保留pos的值,防止迭代器失效的问题出现,然后前一个值给后一个值。 

iterator insert(iterator pos, const T& x)
		{
			assert(pos >= _start && pos <= _finish);

			if (_finish == _endofstorage)
			{
				size_t len = pos - _start;

				size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
				reserve(newcapacity);

				// 解决pos迭代器失效问题
				pos = _start + len;
			}

			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				--end;
			}

			*pos = x;
			++_finish;

			return pos;
		}

 🕶️erase

//erase
	iterator erase(iterator pos)
	{
		assert(pos >= _start && pos < _finish);

		iterator it = pos + 1;
		while (it != _finish)
		{
			*(it - 1) = *it;
			++it;
		}

		--_finish;

		return pos;
	}

💻运算符重载[]

vector是一个顺序容器,支持快速的访问,也就是支持下标访问。

T& operator[](size_t pos)
		{
			assert(pos < size());

			return _start[pos];
		}

	const T& operator[](size_t pos) const
		{
			assert(pos < size());

			return _start[pos];
		}

💻尾插尾删

🕶️push_back和pop_back

	//尾插
    void push_back(const T& x)
		{
			/*if (_finish == _endofstorage)
			{
				size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
				reserve(newcapacity);
			}

			*_finish = x;
			++_finish;*/
			insert(end(), x);
		}

    //尾删
    void pop_back()
    {
		erase(--end());
	}

🍭vector底层实现代码

#pragma once
#include<iostream>
using namespace std;
#include<string>
#include<vector>
#include<algorithm>
#include<assert.h>

namespace cl
{
	template <class T> // generic template
	class vector
	{
	public:
		typedef T* iterator;
		typedef const T*const_iterator;

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

		const_iterator begin()const
		{
			return _start;
		}
		const_iterator end()const
		{
			return _finish;
		}


	//构造函数
	vector()
	{}
	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++;
		}
	}
	vector(int n, const T& val = T())
	{
		resize(n, val);
	}

	//拷贝构造
	vector(const vector<T>& v)
	{
		_start = new T[v.capacity()];//开辟一个空间
		//memcpy(_start, v._start, sizeof(T)*v.size());
		for (int i = 0; i < v.size(); i++)
		{
			_start[i] = v._start[i];
		}
		_finish = _start + v.size();
		_endofstorage = _start + v.capacity();
	}
	//析构
	~vector()
	{
		if (_start)
		{
			delete[] _start;
			_start = _finish = _endofstorage = nullptr;
		}
	}
	//赋值
	//v1=v2//这里我用现代写法
	void swap(vector<T>& v)
	{
		std::swap(_start, v._start);
		std::swap(_finish, v._finish);
		std::swap(_endofstorage, v._endofstorage);
	}
	vector<T>& operator= (const vector& v)
	{
		swap(v);
	}

	//size和capacity
	size_t size()const
	{
		return _finish - _start;
	}
	size_t capacity()const
	{
		return _endofstorage - _start;
	}

	//empty和clear
	/*empty是一个判断是否为空的函数
	clear是用来清空容器数据的函数*/
	bool empty()
	{
		return _start == _finish;
	}
	void clear()
	{
		_start = _finish = nullptr;
	}

	//reserve
	void reserve(size_t n)
	{
		if (n > capacity())
		{
			int sz = size();
			T* tmp = new T[n];
			if (_start)
			{
				for (size_t i = 0; i < sz; i++)
				{
					tmp[i] = _start[i];
				}
				delete[] _start;
			}
			_start = tmp;
			_finish = _start + sz;
			_endofstorage = _start + n;
		}
	}
	//resize
	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++;
			}
		}
	}

	//insert和erase
	iterator insert(iterator pos, const T& x)
	{
		assert(pos >= _start && pos <= _finish);

		if (_finish == _endofstorage)
		{
			size_t len = pos - _start;

			size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
			reserve(newcapacity);

			// 解决pos迭代器失效问题
			pos = _start + len;
		}

		iterator end = _finish - 1;
		while (end >= pos)
		{
			*(end + 1) = *end;
			--end;
		}

		*pos = x;
		++_finish;

		return pos;
	}
	//erase
	iterator erase(iterator pos)
	{
		assert(pos >= _start && pos < _finish);

		iterator it = pos + 1;
		while (it != _finish)
		{
			*(it - 1) = *it;
			++it;
		}

		--_finish;

		return pos;
	}

	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 push_back(const T& x)
	{
		/*if (_finish == _endofstorage)
		{
			size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
			reserve(newcapacity);
		}

		*_finish = x;
		++_finish;*/
		insert(end(), x);
	}

	//尾删
	void pop_back()
	{
		erase(--end());
	}
	private:
		iterator _start=nullptr;
		iterator _finish=nullptr;
		iterator _endofstorage=nullptr;

	};

}

我写我 不论主谓宾 可以反复错

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

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

相关文章

工业性能CCD图像处理+

目录 硬件部分 ​编辑 软件部分 CCD新相机的调试处理&#xff08;更换相机处理&#xff0c;都要点执行检测来查看图像变化&#xff09; 问题:新相机拍摄出现黑屏&#xff0c;图像拍摄不清晰&#xff0c;&#xff08;可以点击图像&#xff0c;向下转动鼠标的滚轮&#xff08…

nlp与cv的发展

Transformer的出现,促进了更高容量模型的建立,为大模型的出现奠定基础. &#x1f9d0;大模型通常具有十亿个以上参数(仅供参考) &#x1f62e;左边的蓝色是CV领域、右下绿色是NLP、右上蓝色是多模态&#x1f603;基础模型(Foundational Models)首次由Bommasani等人在《Stanford…

算法--数据结构基础

文章目录 数据结构单链表栈表达式求值前缀表达式中缀表达式后缀表达式 队列单调栈单调队列KMPTrie并查集堆哈希表字符串哈希 数据结构 单链表 用数组模拟&#xff08;静态链表&#xff09;效率比定义Node类&#xff08;动态链表&#xff09;效率高些 使用数组模拟单链表&am…

2023年总结,讲讲我的故事吧,十年

文章目录 2023前十年后十年 周末&#xff0c;本该是提升自己的最好时机&#xff0c;也该是出去玩的大好时光&#xff0c;但是毫无意外的&#xff0c;在家躺了一天&#xff0c;单纯的有点累。 2023年&#xff0c;发生了好多事情&#xff0c;又好像没发生几件事&#xff0c;可能毕…

插入排序:直接插入排序 希尔排序

插入排序&#xff1a; 假设红竖线前的元素全部排好序&#xff0c;红线后面的数即为要插入的数据&#xff0c;红线依次往后移&#xff0c;假设end为排好序的最后一个数字&#xff0c;end1即为要插入的数字&#xff0c;一次插入时&#xff0c;end与要插入的数字依次比较&#xf…

springMVC-Restful风格

基本介绍 REST&#xff1a;即Representational State Transfer。&#xff08;资源&#xff09;表现层状态转化。是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便&#xff0c;所以正得到越来越多网站的采用. 1.HTTP协议里面&#xff0c;四个表示操…

Java技术栈 —— 微服务框架Spring Cloud —— Ruoyi-Cloud 学习(二)

RuoYi项目开发过程 一、登录功能(鉴权模块)1.1 后端部分1.1.1 什么是JWT?1.1.2 什么是Base64?为什么需要它&#xff1f;1.1.3 SpringBoot注解解析1.1.4 依赖注入和控制反转1.1.5 什么是Restful?1.1.6 Log4j 2、Logpack、SLF4j日志框架1.1.7 如何将项目打包成指定bytecode字节…

ValueError: setting an array element with a sequence...

报错&#xff1a;ValueError: setting an array element with a sequence… 案例1&#xff1a;numpy库使用numpy.array转换list a是一个list&#xff0c;其包含两个元组&#xff0c;使用np.array进行转换&#xff0c;会报错&#xff1a; import numpy as np a ([([1, 2, 3]…

nodejs微信小程序+python+PHP的微博网络舆情分析系统-计算机毕业设计推荐

&#xff08;4&#xff09;微博信息交流&#xff1a;在首页导航栏上我们会看到“微博信息交流”这一菜单&#xff0c;我们点击进入进去以后&#xff0c;会看到所有管理员在后台发布的交流信息&#xff1b; &#xff08;5&#xff09;新闻资讯&#xff1a;用户可以查看新闻资讯信…

关于“Python”的核心知识点整理大全24

10.1.6 包含一百万位的大型文件 前面我们分析的都是一个只有三行的文本文件&#xff0c;但这些代码示例也可处理大得多的文件。 如果我们有一个文本文件&#xff0c;其中包含精确到小数点后1 000 000位而不是30位的圆周率值&#xff0c;也可 创建一个包含所有这些数字的字符串。…

HiveSql语法优化三 :join优化

前面提到过&#xff1a;Hive拥有多种join算法&#xff0c;包括Common Join&#xff0c;Map Join&#xff0c;Bucket Map Join&#xff0c;Sort Merge Buckt Map Join等&#xff1b;每种join算法都有对应的优化方案。 Map Join 在优化阶段&#xff0c;如果能将Common Join优化为…

Java 基础学习(十二)文本I/O、日期与时间API

1 文本 I/O 1.1 字符流 1.1.1 什么是字符流 在Java中&#xff0c;字符流是指提供了基于字符的I/O能力的API。 Java 1.0中提供的基于字节的I/O流API只能支持8位字节流&#xff0c;无法妥善地处理16位Unicode字符。由于需要支持Unicode处理国际化字符&#xff0c;因此Java 1.…

TCP/IP详解——HTTPS 协议

文章目录 1. HTTPS 协议1.1 HTTPS 原理1.2 HTTPS 过程1.3 从数据包角度看 HTTPS 交互过程1.4 常见的 HTTPS 数据包解码1.4.1 ClientHello 数据包1.4.2 ServerHello 数据包 1.5 思考 1. HTTPS 协议 1.1 HTTPS 原理 HTTPS概念 HTTPS 是以安全为目标的HTTP通道&#xff0c;并不…

小 cookie,大作用:探索网站中的隐私追踪器(上)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

持续集成交付CICD:Jenkins使用GitLab共享库实现基于Ansible的CD流水线部署前端应用的蓝绿发布

目录 一、实验 1.蓝绿发布准备 2.Jenkins使用GitLab共享库实现基于Ansible的CD流水线部署前端应用的蓝绿发布 二、问题 1.手动构建Jenkins前端项目CI流水线报错 2.如何优化手动构建流水线选项参数 一、实验 1.蓝绿发布准备 &#xff08;1&#xff09;环境 表1 蓝绿发布…

flume:Ncat: Connection refused.

一&#xff1a;nc -lk 44444 和 nc localhost 44444区别 nc -lk 44444 和 nc localhost 44444 是使用 nc 命令进行网络通信时的两种不同方式。 1. nc -lk 44444&#xff1a; - 这个命令表示在本地监听指定端口&#xff08;44444&#xff09;并接受传入的连接。 - -l 选项…

前端视角看 Docker : 基础命令全面指南

引言 Docker是一种开源的容器化平台&#xff0c;它允许开发者将应用程序和其依赖打包在一个轻量级的、可移植的容器中。这使得应用程序在不同的环境中部署变得简单且高效。本文将介绍Docker的一些基础命令和概念&#xff0c;帮助初学者快速上手。 1. Docker简介 Docker使用…

054:vue工具 --- BASE64加密解密互相转换

第054个 查看专栏目录: VUE ------ element UI 专栏目标 在vue和element UI联合技术栈的操控下&#xff0c;本专栏提供行之有效的源代码示例和信息点介绍&#xff0c;做到灵活运用。 &#xff08;1&#xff09;提供vue2的一些基本操作&#xff1a;安装、引用&#xff0c;模板使…

云原生之深入解析使用Telepresence轻松在本地调试和开发Kubernetes应用程序

一、 准备 telepresence 下载&#xff1a;https://www.telepresence.io/docs/latest/install/kubectl 下载&#xff1a;https://kubernetes.io/docs/tasks/tools/ 二、版本检测 $telepresence version Client: v2.5.3 (api v3) Root Daemon: not running User Daemon: not r…

css文本样式的使用

在CSS中&#xff0c;可以通过以下属性来设置文本的样式&#xff1a; color&#xff1a;设置文本的颜色。 p {color: red; }效果图&#xff1a; font-size&#xff1a;设置文本的字体大小。 p {font-size: 16px; }效果图&#xff1a; font-family&#xff1a;设置文本的字…