C++常见容器实现原理

引言

  • 如果有一天!你骄傲离去!(抱歉搞错了)
  • 如果有一天,你在简历上写下了这段话:
    在这里插入图片描述
  • 那么你不得不在面试前实现一下STL常见的容器了。
  • C++的常用容器有:vector、string、deque、stack、queue、list、set、map。接下来就让我们对每种常用容器进行介绍和实现吧。

一、vector

  • vector详细介绍
  • 实现代码:
#include<assert.h>
#include<algorithm> // 包含函数std::swap

// 模拟实现Vector
template<class T>	// T为容器中元素的类型
class vector
{
public:
	typedef T* iterator;			  // 统一化指向vector中元素的指针为:iterator
	typedef const T* const_iterator;  // const_iterator指针无法修改指向的对象,但可以自增自减

	// 获取迭代器(const和非const)
	iterator begin()
	{
		return _start;	  // _start指向容器内存储的第一个元素
	}

	iterator end()
	{
		return _finish;	  // _finish指向容器内最后一个元素之后
	}

	const_iterator cbegin()const	// 实现同上即可,返回的类型是const_iterator
	{
		return _start;
	}

	const_iterator cend()const
	{
		return _finish;
	}

	// 运算符[]的重载
	T& operator[](size_t pos)
	{
		assert(pos < size());	// size()返回容器内容纳的元素个数
		return _start[pos];		// 根据指针运算,直接索引到Pos索引值即可
	}

	const T& operator[](size_t pos)	// 同上
	{
		assert(pos < size());
		return start[pos];
	}

	// 构造函数
	vector() :_start(nullptr), _finish(nullptr), _endOfStorage(nullptr) {}	// 初始化三个成员指针为空指针

	// 迭代器区间构造函数
	template<class InputIterator>
	vector(InputIterator first, InputIterator last) : _start(nullptr), _finish(nullptr), _endOfStorage(nullptr)
	{
		while (first != last)	// 将区间中的每个元素按照顺序压入容器内即可
		{
			push_back(*first);
			first++;
		}
	}

	// 拷贝构造函数
	vector(const vector<T>& v) :_start(nullptr), _finish(nullptr), _endOfStorage(nullptr)
	{
		vector<T> tmp(v.cbegin(), v.cend());	// 先使用区间构造一个同样的容器,然后把其和此容器进行交换即可
		swap(tmp);
	}

	// 使用n个val值的构造函数
	vector(size_t n, const T& val = T())
	{
		reserve(n);						// 将容器扩容到至少n个元素
		for (size_t i = 0; i < n; ++i)	// 将值压入即可
		{
			push_back(val);
		}
	}

	// 重载运算符=
	vector<T>& operator=(vector<T> v)
	{
		swap(v);		// 由于v不是引用,是新构造来的,直接交换控制权即可
		return *this;	// 返回自身
	}

	// 析构函数
	~vector()			
	{
		delete[] _start;	// 释放申请的空间
		_start = _finish = _endOfStorage = nullptr;		// 将所有成员指针重置为空
	}

	// 容量调整函数(只扩容)
	void reserve(size_t n)
	{
		if (n > capacity())	// 当且仅当需求的容量大于现在容器的最大容量时进行调整
		{
			size_t oldSize = size();	// 获取原本的容量
			T* tmp = new T[n];			// 申请需求的更大容量
			if (_start != nullptr)		// 如果容器本身中包含元素
			{
				for (int i = 0; i < size(); ++i)	// 将本身包含的元素拷贝到新申请的容量中
				{
					tmp[i] = _start[i];
				}
				delete[] _start;		// 释放原本的内存空间
			}
			_start = tmp;				// 将此容器的首地址记录为新申请的空间
			_finish = tmp + oldSize;	// 计算容器中最后一个元素之后的地址
			_endOfStorage = _start + n; // 计算容器中最大容量元素之后的地址
		}
	}

	// 元素个数调整函数(只扩容)
	void reserve(size_t n, T val = T())
	{
		if (n > capacity())	// 如果需要扩容则进行扩容
		{
			reserve(n);
		}
		if (n > size())		// 如果容器包含元素数目少于n,则将包含元素数目-n中的元素设为val
		{
			while (_finish < _start + n)
			{
				*_finish = val;
				_finish++;
			}
		}
		else
		{					// 否则容器包含元素数目多于n,则将容器包含元素数目设为n
			_finish = _start + n;
		}
	}

	// 获取元素个数size
	size_t size()const
	{
		return _finish - _start;	// 指针运算
	}

	// 获取容量大小
	size_t capacity()const
	{
		return _endOfStorage - _start;	// 指针运算
	}

	// 判断是否为空
	bool empty()const
	{
		return _finish == _start;	// 当首元素地址 等于 最后一个元素之后的地址 时,即不存在元素即为空
	}

	void clear()
	{
		_finish = _start;	// 清空,即最后一个元素之后的地址等于空间首地址
	}

	// 尾部插入函数
	void push_back(const T& x)
	{
		if (_finish == _endOfStorage)	// 如果空间满了
		{
			size_t newCapacity = (capacity() == 0 ? 4 : capacity() * 2);	// 扩容两倍
			reserve(newCapacity);	// 扩容
		}
		*_finish = x;	// 将最后一个之后的元素设为x,即压入x
		_finish++;		// 尾指针向后移动
	}

	// 尾部删除函数
	void pop_back()
	{
		assert(!empty());	// 不为空时删除
		_finish--;			// 直接将尾指针向前移动即可
	}

	// 插入指定位置
	void insert(iterator pos, const T& val)
	{
		assert(pos < _finish);	// 插入位置需要位于:[_start,finish)
		assert(pos >= _start);

		if (_finish == _endOfStorage) // 如果空间满了
		{
			size_t len = pos - _start;		//计算此位置之前有多少元素
			size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;	// 计算扩容后的容量数目
			reserve(newCapacity);			// 扩容

			pos = _start + len;	 // 计算新的对应pos位置 
		}

		iterator end = _finish - 1; // 计算尾元素位置
		while (end >= pos)		// 从尾元素到插入位置之后的位置
		{
			*(end + 1) = *end;	// 每个元素向后移动
			end--;
		}
		*pos = val;  // 在pos位置插入val
		_finish++;	 // 将finish+1 
	}

	// 删除指定位置
	iterator erase(iterator pos)
	{
		assert(pos >= _start);
		assert(pos < _finish);

		iterator begin = pos;	
		while (begin < _finish - 1)	 // 从删除位置到最后一个元素
		{
			*(begin) = *(begin + 1); // 每个元素向前移动一位
			begin++;
		}
		_finish--;	// 尾指针-1
		return pos;
	}

	// 交换
	void swap(vector<T>& v)	// 交换对应指针即可
	{
		std::swap(_start, v._start);
		std::swap(_finish, v._finish);
		std::swap(_endOfStorage, v._endOfStorage);
	}

private:
	iterator _start;			// 容器中第一个元素地址,也是容器申请内存空间首地址
	iterator _finish;			// 容器中最后一个元素之后的地址
	iterator _endOfStorage;		// 容器申请的内存空间的尾地址,也即是容器能容纳的最多元素之后的地址
};

二、list

  • 实现代码:

三、map

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

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

相关文章

Docker:安装MySQL

Docker&#xff1a;安装MySQL 1. 部署MySQL2.部署多个MySQL服务 1. 部署MySQL 首先需要安装Docker&#xff0c;安装Docker地址&#xff1a;http://t.csdnimg.cn/utPGF 安装命令&#xff1a; docker run -d \--name mysql \-p 3306:3306 \-e TZAsia/Shanghai \-e MYSQL_ROOT…

[论文笔记]GTE

引言 今天带来今年的一篇文本嵌入论文GTE, 中文题目是 多阶段对比学习的通用文本嵌入。 作者提出了GTE,一个使用对阶段对比学习的通用文本嵌入。使用对比学习在多个来源的混合数据集上训练了一个统一的文本嵌入模型,通过在无监督预训练阶段和有监督微调阶段显著增加训练数…

IOC课程整理-6 Spring IoC 依赖注入

1 依赖注入的模式和类型 模式 类型 2 自动绑定&#xff08;Autowiring&#xff09; 官方定义 “自动装配是Spring框架中一种机制&#xff0c;用于自动解析和满足bean之间的依赖关系。通过自动装配&#xff0c;Spring容器可以根据类型、名称或其他属性来自动连接协作的bean&…

通道洗牌的思想神了

大家好啊&#xff0c;我是董董灿。 昨天写了一篇关于分组卷积的文章&#xff1a;分组卷积的思想神了&#xff0c;然后有同学希望多了解下通道洗牌。 我个人感觉&#xff0c;通道洗牌这个算法&#xff0c;或者说这个思想&#xff0c;可以称之为小而精&#xff0c;并且是实际解…

Photoshop使用笔记总目录

Photoshop基础学习之工具学习 一、【Photoshop界面认识】 二、【 Photoshop常用快捷键】 三、【色彩模式与颜色填充】 四、【选区】 五、【视图】 六、【常用工具组】 七、【套索工具组】 八、【快速选择工具组】 九、【裁剪工具组】 十、【图框工具组】 十一、【吸取…

1.量化相关了解

前言 深度学习模型部署过程中&#xff0c;我们希望可以快速地对模型进行压缩和推理加速&#xff0c;离线量化是一种常用的压缩加速方法。 一、量化概述 量化是指将连续的信号取值&#xff0c;离散化为有限个取值的过程。 深度学习模型量化是使用低比特定点数表征模型浮点参数…

C#学习相关系列之多线程(七)---Task的相关属性用法

一、Task和Thread的区别 任务是架构在线程之上的,任务最终的执行还是要给到线程去执行的。任务和线程之间不是一对一的关系&#xff0c;任务更像线程池&#xff0c;任务相比线程池有很小的开销和精确的控制。&#xff08;总的来说Task的用法更为先进&#xff0c;在多线程的时候…

Go学习第十三章——Gin入门与路由

Go web框架——Gin入门与路由 1 Gin框架介绍1.1 基础介绍1.2 安装Gin1.3 快速使用 2 路由2.1 基本路由GET请求POST请求 2.2 路由参数2.3 路由分组基本分组带中间件的分组 2.4 重定向 1 Gin框架介绍 github链接&#xff1a;https://github.com/gin-gonic/gin 中文文档&#xf…

logback-classic包中ThrowableProxy递归缺陷StackOverflowError解析

logback-classic&#xff08;<1.2.12版本&#xff09;ThrowableProxy类中存在递归缺陷&#xff0c;会导致java.lang.StackOverflowError。改缺陷在1.2.12以上版本(包含该版本)中已修复。 如何复现&#xff1a; 两个异常彼此设置casue&#xff1a; 运行后报以下错误 以上写…

中文编程开发语言工具系统化教程零基础入门篇和初级1专辑课程已经上线,可以进入轻松学编程

中文编程开发语言工具系统化教程零基础入门篇和初级1专辑课程已经上线&#xff0c;可以进入轻松学编程 学习编程捷径&#xff1a;&#xff08;不论是正在学习编程的大学生&#xff0c;还是IT人士或者是编程爱好者&#xff0c;在学习编程的过程中用正确的学习方法 可以达到事半…

python随手小练10(南农作业题)

题目1&#xff1a; 编写程序&#xff0c;输出1~1000之间所有能被4整除&#xff0c;但是不能被5整除的数 具体操作&#xff1a; for i in range(1,1000): #循环遍历1~999&#xff0c;因为range是左闭右开if (i % 4 0) and (i % 5 ! 0) :print(i) 结果展示&#xff1a; 题目2&…

Vue学习之样式汇总

Vue学习之样式汇总 一 二者左右排版 案例 说明&#xff1a;头部一左一右排版&#xff0c;内容一左一右两个排版&#xff0c;公告栏文字超过点点点显示 代码实现 说明&#xff1a; &#xff08;1&#xff09;头部实现一左一右排版需要使用一下两个样式 display: flex;justify-…

nginx 动静分离 防盗链

一、动静分离环境准备静态资源配置(10.36.192.169)安装nginx修改配置文件重启nginx 动态资源配置(192.168.20.135)yum安装php修改nginx配置文件重启nginx nginx代理机配置&#xff08;192.168.20.134&#xff09;修改nginx子自配置文件重启nginx 客户端访问 二、防盗链nginx防止…

红队专题-从零开始VC++C/S远程控制软件RAT-MFC-远控介绍及界面编写

红队专题 招募六边形战士队员[1]远控介绍及界面编写1.远程控制软件演示及教程简要说明主程序可执行程序 服务端生成器主机上线服务端程序 和 服务文件管理CMD进程服务自启动主程序主对话框操作菜单列表框配置信息 多线程操作非模式对话框 2.环境&#xff1a;3.界面编程新建项目…

毅速丨增减材协同制造已逐渐成为趋势

近年来&#xff0c;增材制造3D打印技术的发展非常迅速&#xff0c;被广泛应用于航空航天、汽车、电子、医疗等许多行业。增材制造技术通过逐层增加材料的方式制造出各种复杂形状的零件&#xff0c;具有很高的制造效率和灵活性。 然而&#xff0c;在精密加工领域&#xff0c;增材…

STM32 TIM(四)编码器接口

STM32 TIM&#xff08;四&#xff09;编码器接口 编码器接口简介 Encoder Interface 编码器接口 编码器接口可接收增量&#xff08;正交&#xff09;编码器的信号&#xff0c;根据编码器旋转产生的正交信号脉冲&#xff0c;自动控制CNT自增或自减&#xff0c;从而指示编码器的…

bbr 流相互作用图示

类似 AIMD 收敛图&#xff0c;给出 bbr 的对应图示&#xff1a; bbr 多流相互作用非常复杂&#xff0c;和右下角的 AIMD 相比&#xff0c;毫无美感&#xff0c;但是看一眼左下角的 bbr 单流情况&#xff0c;又过于简陋&#xff0c;而 bbr 的核心就基于这简陋的假设。 浙江温…

力扣每日一题73:矩阵置零

题目描述&#xff1a; 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&#xff1a;[[1,0,1],[0,0,0],[1,0,1]]示例 2…

Unable to find GatewayFilterFactory with name TokenRelay

目录 问题分析解决方案参考文档开源项目微服务商城项目前后端分离项目 问题分析 Spring Cloud Gateway 网关作为代理资源服务器&#xff0c;需要将 JWT 传递给下游资源服务器&#xff0c;下面是网关的配置 spring:cloud:gateway:discovery:locator:enabled: true # 启用服务发…

Rabbitmq----分布式场景下的应用

服务异步通信-分布式场景下的应用 如果单机模式忘记也可以看看这个快速回顾rabbitmq,在做学习 消息队列在使用过程中&#xff0c;面临着很多实际问题需要思考&#xff1a; 1.消息可靠性 消息从发送&#xff0c;到消费者接收&#xff0c;会经理多个过程&#xff1a; 其中的每一…