vector的底层与使用

前言:vector是顺序表(本质也是数组)

文档参考网站:https://legacy.cplusplus.com/reference/vector/vector/vector/

//底层代码
#include<assert.h>
#include<iostream>
#include<vector>
#include<string>
using namespace std;
namespace bit
{
	template<typename T>
	class vector
	{
	public:
		typedef T* iterator;
		typedef const T* const_iterator;

		template <typename InputIterator>
		vector(InputIterator first, InputIterator last)
		{
			reserve(last - first);
			while (first != last)
			{
				push_back(*first);
				first++;
			}
		}
		
			
		vector(int size = 1)
		{
			_begin = _end = new T[size];
			_endofstorage = _begin + size;
		}
		~vector()
		{
			delete[] _begin;
			_begin = _end = _endofstorage = nullptr;
		}
		vector(const vector<T>& s)
		{
			reserve(s.capacity());
			for (auto& e : s)
				push_back(e);
		}
		int size() const
		{
			return _end - _begin;
		}
		int capacity() const
		{
			return _endofstorage - _begin;
		}
		void reserve(int newcapacity)
		{
			if (newcapacity > capacity())
			{
				int old_size = size();
				iterator tmp = new T[newcapacity];
				for(int i = 0 ; i < old_size ; i++)
                {
                     tmp[i] = _begin[i];
                }
                //不能用memcpy,防止数据进行浅拷贝
				_begin = tmp;
				_end = tmp + old_size;
				_endofstorage = tmp + newcapacity;
			}
		}

		void push_back(T val)
		{
			int old_size = size();
			if (_end == _endofstorage)
			{
				reserve(2 * old_size);
			}
			*_end = val;
			_end++;
		}
		iterator begin() //返回临时变量
		{
			return _begin;
		}
		iterator end()
		{
			return _end;
		}
		const_iterator begin() const
		{
			return (const_iterator)_begin;
		}
		const_iterator end() const 
		{
			return (const_iterator)_end;
		}
		void pop_back()
		{
			_end--;
		}
		
		
		iterator insert(iterator position, const T& val)
		{
			assert(position < _end);
			iterator tmp = _end;
			if (_end == _endofstorage) {
				size_t len = position - _begin;
				reserve(2 * size());
				position = _begin + len;
			}
			while (_end != position)
			{
				*_end = *(_end - 1);
				_end--;
			}
			iterator k = _end;
			*_end = val;
			_end = tmp;
			_end++;
			return k;
		}
		T& operator[] (int n)
		{
			assert(n < size());
			return _begin[n];
		}
		const T& operator[] (int n) const
		{
			assert(n < size());
			return _begin[n];
		}
		iterator erase(iterator position)
		{
			assert(position < _end);
			iterator tmp = position;
			while (position != _end)
			{
				*(position) = *(position + 1);
				position++;
			}
			_end--;
			return tmp;
		}
		iterator erase(iterator first, iterator last)
		{
			assert(last < _end && first < _end);
			int a = last - first;
			iterator tmp = last;
			iterator k = first;
			while (tmp != _end)
			{
				*first = *tmp;
				tmp++;
				first++;
			}
			_end -= a;
			return k;
		}
		void clear()
		{
			_end = _begin;
		}
		void resize(int n, const T& val = T())
		{
			int _size = size();
			if (n > _size)
			{
				reserve(n);
				iterator t = _begin + n;
				while (_end != t)
				{
					*_end = val;
					_end++;
				}
			}
			else
			{
				_end = _begin + n;
			}
		}
	private:
		iterator _begin = nullptr;//初始化列表
		iterator _end = nulptr;
		iterator _endofstorage;
	

	};
}

构造函数

第一种方式: vector( int size = 1 )// 全缺省,作为默然构造函数

 开10个整形的数组

第二个方式:vector( int size , const T& val = T() )

解释 T()        当T为自定义类型时,调用T的默然构造函数

                      但对于内置类型,编译器会自动调用内置类型的默然构造(纯粹为了符合类模版)

                       对于int 为 0  , 对于double 为 0.0 ,对于char 为 '\0' , 对于指针为nullptr等

第三种方式:运用类成员函数模版

template <class InputIterator>
  vector (InputIterator first, InputIterator last) 左闭右开

第四种方式:C++11提出的(用初始化链表初始化)

  

e的类型是初始化链表

初始化链表只有四个接口函数 , 初始化链表只能支持遍历 ,不能支持赋值,初始化链表中的数据储存在常量区中(不能被修改)

析构函数

底层实现简单  ( clear 函数 + 指针置为空指针 )

这里补充一下clear函数

void clear()
{

_end = _begin;

}

~vector()
{

clear();

delete[] _begin;

_begin = _end = _endofstorage = nullptr;
}

拷贝构造函数(深拷贝)

现代写法:

vector( const vector<T> & s )
{

        reserve(s.capacity());//提前开好空间

        for( auto& e : s )//使用引用,防止拷贝构造,提升效率
        {

        push_bakc(e);//注意数据要进行深拷贝
        }
}

迭代器

由于物理空间上连续,与指针的行为相似

typedef T* iterator ;

typedef const T* const_iterator;

要注意*this是const成员还是非const成员

iterator begin()
{
        return _begin;
}

iterator end()
{
return _end;

}

const_iterator begin()const
{
       return (const T*) _begin;
}

const_iterator end() const
{

return (const T*)_end;

}

const T& operator[](int npos) const 
{

assert( npos < size() );//注意未初始化的地方不能使用
return _begin[npos];

}

 T& operator[](int npos) 
{

assert( npos < size() );
return _begin[npos];

}

运算符重载

vector<T>& operator=(  vector<T>  s) (构造 加 交换 )
{
       swap(s,*this);

       return *this;
}

insert函数

主要是在某个位置之前插入一个值或一段区间

样列:

#include<string>
#include<vector>
#include<iostream>
using namespace std;
int main()
{
    
    vector<int> s;
    s.push_back(1);
    s.push_back(2);
    s.push_back(3);
    s.push_back(4);
    s.push_back(5);
    s.insert(s.begin() + 1, 10);
    for (auto& e : s)
    {
        cout << e << " ";
    }
    cout << endl;
}

样列:

#include<string>
#include<vector>
#include<iostream>
using namespace std;
int main()
{
    
    vector<int> s;
    s.push_back(1);
    s.push_back(2);
    s.push_back(3);
    s.push_back(4);
    s.push_back(5);
    string k("asdfasfsaf");
    s.insert(s.begin() + 1, k.begin() + 2 , k.end() - 4);
    for (auto& e : s)
    {
        cout << e << " ";
    }
    cout << endl;
}

erase函数(一般不会缩容)

删除某个位置的值 , 或删除一段区间的值(左闭右开)

#include<iostream>
#include<vector>
using namespace std;
int main()
{
    vector<int> s;
    s.push_back(1);
    s.push_back(1);
    s.push_back(1);
    s.push_back(1);
    s.push_back(1);
    s.push_back(1);
    s.push_back(1);
    s.erase(s.begin(), s.end() - 1);
    for (auto& e : s)
    {
        cout << e << " ";
    }
    cout << endl;
    return 0;
}

注意在使用insert函数和erase函数会造成迭代器失效,所以在使用完迭代器之后,就不能在使用,

如果你就要使用,则要更新迭代器

举个例子:(删除顺序表中的偶数)

#include<iostream>
#include<vector>
using namespace std;
int main()
{
    vector<int> s;
    s.push_back(1);
    s.push_back(2);
    s.push_back(3);
    s.push_back(4);
    s.push_back(4);
    s.push_back(9);
    s.push_back(11);
    s.push_back(11);
    s.push_back(11);
    auto it = s.begin();
    while (it != s.end())
    {
        if (*it % 2 == 0)it = s.erase(it);
        else it++;
    }
    for (auto& e : s)cout << e << " ";
    cout << endl;
    return 0;
}

push_back 和 pop_back

尾增 和 尾删

reserve和resize函数

reserve函数时扩容,reserve使用完,不能用[]赋值

resize函数是扩容(当newcapacity > newcapacity) + 初始化

要注意reserve函数在完成扩容时,是对数据进行深拷贝(不能使用memcpy)

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

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

相关文章

实现Spring底层机制(阶段1—编写自己的Spring容器,扫描包,得到bean的Class对象)

环境搭建抛出问题 1.环境搭建 1.创建maven项目 2.导入依赖 <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 http://maven.ap…

隐藏表头和最高层级的复选框

隐藏表头和最高层级的复选框 <!-- 表格 --><el-tableref"tableRef"v-loading"tableLoading"default-expand-allclass"flex-1 !h-auto"row-key"regionId":header-cell-class-name"selectionClass":row-class-name&q…

20240422,C++文件操作

停电一天之后&#xff0c;今天还有什么理由不学习呜呜……还是没怎么学习 一&#xff0c;文件操作 文件操作可以将数据持久化&#xff0c;对文件操作时须包含头文件<fstream> 两种文件类型&#xff1a;文本文件&#xff1a;文件以文本的ASCII码形式存储&#xff1b;二进…

算法导论 总结索引 | 第三部分 第十一章:散列表

1、动态集合结构&#xff0c;它至少要支持 INSERT、SEARCH 和 DELETE字典操作 散列表 是实现字典操作的 一种有效的数据结构。尽管 最坏情况下&#xff0c;散列表中 查找一个元素的时间 与链表中 查找的时间相同&#xff0c;达到了 Θ(n)。在实际应用中&#xff0c;散列表的性…

GLID: Pre-training a Generalist Encoder-Decoder Vision Model

1 研究目的 现在存在的问题是&#xff1a; 目前&#xff0c;尽管自监督预训练方法&#xff08;如Masked Autoencoder&#xff09;在迁移学习中取得了成功&#xff0c;但对于不同的下游任务&#xff0c;仍需要附加任务特定的子架构&#xff0c;这些特定于任务的子架构很复杂&am…

Linux使用Docker部署DashDot访问本地服务器面板

文章目录 1. 本地环境检查1.1 安装docker1.2 下载Dashdot镜像 2. 部署DashDot应用 本篇文章我们将使用Docker在本地部署DashDot服务器仪表盘&#xff0c;并且结合cpolar内网穿透工具可以实现公网实时监测服务器系统、处理器、内存、存储、网络、显卡等&#xff0c;并且拥有API接…

前端开发攻略---拖动归类,将元素拖拽到相应位置

1、演示 2、代码 <!DOCTYPE html><html lang"en"><head><meta charset"UTF-8" /><meta http-equiv"X-UA-Compatible" content"IEedge" /><meta name"viewport" content"widthdevice-…

我在本地部署通义千问Qwen1.5大模型,并实现简单的对话和RAG

节前&#xff0c;我们星球组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、参加社招和校招面试的同学&#xff0c;针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。 汇总…

什么是防抖和节流?有什么区别? 如何实现?

防抖&#xff08;Debounce&#xff09;和节流&#xff08;Throttle&#xff09;是两种常用的技术手段&#xff0c;主要用于控制某个函数在一定时间内触发的次数&#xff0c;以减少触发频率&#xff0c;提高性能并避免资源浪费。 防抖&#xff08;Debounce&#xff09;的工作原…

掉落回弹问题(C语言)

一、N-S流程图&#xff1b; 二、运行结果&#xff1b; 三、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;float b 100;float sum 0;int i 0;//运算&#xff1b;for (i 1; i < 10; i){//运算&…

【oceanbase】安装ocp,ocp部署oceanbase

https://www.oceanbase.com/docs/common-ocp-1000000000584989 资源 iphostnamecpumem组件192.168.0.71obnode-000-071816oceanbase-ce192.168.0.72obnode-000-072816oceanbase-ce192.168.0.73obnode-000-073816oceanbase-ce192.168.0.74obproxy-000-07424obproxy-ce192.168.0…

【北京迅为】《iTOP-3588开发板系统编程手册》-第16章 串口应用编程

RK3588是一款低功耗、高性能的处理器&#xff0c;适用于基于arm的PC和Edge计算设备、个人移动互联网设备等数字多媒体应用&#xff0c;RK3588支持8K视频编解码&#xff0c;内置GPU可以完全兼容OpenGLES 1.1、2.0和3.2。RK3588引入了新一代完全基于硬件的最大4800万像素ISP&…

291个地级市资源错配指数、劳动和资本相对扭曲指数(2006-2021年)

01、数据介绍 资源错配指数&#xff08;Misallocation Index&#xff09;是一个用于衡量资源配置效率的指标&#xff0c;它衡量的是生产要素的配置是否合理&#xff0c;是否达到了最优的状态。资源错配指数越高&#xff0c;资源的利用效率越低。资源错配指数主要用于衡量各种生…

学习STM32第十七天

备份域详解 一、简介 在参考手册的电源控制章节&#xff0c;提到了备份域&#xff0c;BKPR是在RTC外设中用到&#xff0c;包含20个备份数据寄存器&#xff08;80字节&#xff09;&#xff0c;备份域包括4KB的备份SRAM&#xff0c;以32位、16位或8位模式寻址&#xff0c;在VBAT…

SpringCloud系列(9)--将服务消费者Consumer注册进Eureka Server

前言&#xff1a;上一章节我们介绍了如何将服务提供者注册进Eureka服务里&#xff0c;本章节则介绍如何将服务消费者Consumer注册进Eureka服务里 Eureka架构原理图 1、修改consumer-order80子模块的pom.xml文件&#xff0c;引入Eureka Clinet的依赖&#xff0c;然后reolad一下&…

SVD奇异值分解原理及应用

-------------------------------------------------------------------------------------------------------------------------------- 首先说明&#xff1a;本文的内容来自百家号“人工智能遇见磐创”大佬的整理&#xff0c;感谢原作者&#xff08;本文在原作者的基础上按…

找不到msvcp140dll,无法继续执行代码的详细解决方法

在我们日常使用计算机进行各类工作任务的过程中&#xff0c;时常会遭遇一些突发的技术问题。比如&#xff0c;有时在运行某个重要程序或应用软件时&#xff0c;系统会突然弹出一个令人困扰的错误提示&#xff1a;“电脑提示找不到msvcp140.dll文件&#xff0c;因此无法继续执行…

Mysql基础(二)数据类型和约束

一 数据类型 讲解主要的数据类型,不面面俱到,后续遇到具体问题再查询补充扩展&#xff1a; 知识点的深度和广度以工作为导向 ① int float M : 表示显示宽度&#xff0c;M的取值范围是(0, 255)例如: int(5),当数据宽度小于5位的时候在数字前面需要用字符填满宽度说明&…

双击复制elementui表格某个单元格的数据

提示:记录工作中遇到的需求及解决办法 文章目录 前言一、代码前言 在使用elementui的表格将数据展示出来时,我们想复制该表格区域对应的内容,但因为想复制的列不想太宽而数据太长导致数据省略,无法使用鼠标选择来全部复制到,所以想能不能实现一个双击该内容达到复制效果;…

VSCode 配置 C/C++ 环境

1 安装 VSCode 直接去官网(https://code.visualstudio.com/)下载并安装即可。 2 配置C/C编译环境 方案一 如果是在Windows&#xff0c;需要安装 MingW&#xff0c;可以去官网(https://sourceforge.net/projects/mingw-w64/)下载安装包。 注意安装路径不要出现中文。 打开 w…