stack和queue简单模拟实现

news2025/5/18 13:55:19

  • stack
  • reverse_iterator
  • queue
  • priority_queue
    • 仿函数
    • 具体代码

stack

Stacks are a type of container adaptor, specifically designed to operate in a LIFO context (last-in first-out), where elements are inserted and extracted only from one end of the container.

上述描述出自cplusplus.

重点是stack是一个container adaptor也就是容器适配器。
这意味着我们不需要也没有必要从0开始实现stack的方法,而可以通过一个模板,来调用其他容器来实现,以下是stack的部分从成员函数:

template<class T, class Container = deque<int>>
class stack
{
public:
	void push(const T& x)
	{
		_con.push_back(x);
	}

	void pop()
	{
		_con.pop_back();
	}

	size_t size()
	{
		return _con.size();
	}

	bool empty()
	{
		return _con.empty();
	}

	const T& top()
	{
		return _con.back();
	}

private:
	Container _con;
};

可以发现只需要调用传来的模板参数即可。

这里的默认容器是deque,这是一个均衡的容器,整体效率没有vector高,但是可以实现push_front。这是vector做不到的,或者说vector的头插效率是O(n),过低。

值得注意的是,所有容器适配器都不支持迭代器
就以stack举例,如果支持迭代器,那是否意味着破坏了他的FILO特性呢?是的。因此不支持迭代器。

reverse_iterator

上文提到容器适配器,那就不得不提到反向迭代器了。
之前我们实现vector和list的时候都没有实现反向迭代器,因为两者内容过于相似,现在了解了反向迭代器的机制后我们知道,是否可以通过穿入迭代器容器,然后实现反向迭代器。

这意味着,我们可以同时实现所有容器的反向迭代器,也就是实现他们的模板:

template<class Iterator,class Ref,class Ptr>
struct Reverse_iterator
{
	typedef Reverse_iterator<Iterator, Ref, Ptr> Self;
	Iterator _it;
	Reverse_iterator(Iterator it)
		:_it(it)
	{}

	Ref operator*()
	{
		Iterator tmp = _it;
		return *((--tmp));
	}

	Ptr operator->()
	{
		return &(operator*());
	}

	Self& operator++()
	{
		return --_it;
	}

	Self& operator--()
	{
		return ++_it;
	}

	bool operator!=(const Self& it)
	{
		return _it != it;
	}

};

需要注意的一点是,我们的operator*返回的是 *(--tmp),而不是 *(tmp).

原因是,我们的rbegin()和rend()返回的是end()和begin()。这是基于代码对称性考虑的,正常而言我们的rbegin()和rend()理应返回end()-1和begin()-1.

为了解决这个问题,就只能令operator*返回 *(--tmp)

注:以上实现是visual studio的实现方式。

queue

template<class T, class Container = deque<int>>
class queue
{
public:
	void push(const T& x)
	{
		_con.push_back(x);
	}

	void pop()
	{
		_con.pop_front();
	}

	size_t size()
	{
		return _con.size();
	}

	bool empty()
	{
		return _con.empty();
	}

	const T& front()
	{
		return _con.front();
	}

	const T& back()
	{
		return _con.back();
	}

private:
	Container _con;
};

priority_queue

priority_queue实质上就是一个堆,并且是默认大根堆。那么我们想要将其改变为小根堆改如何实现?
如果是C语言的话,我们会增加一个函数指针的参数来实现。
在C++中,我们通过传入一个仿函数来实现。

仿函数

所谓仿函数就是指能够像函数一样使用的对象,如下:

template<class T>
class less
{
public:
	bool operator()(const T& x, const T& y)
	{
		return x < y;
	}
};
void test(int x,int y)
{
	less l;
	if(l(x,y))cout<<"x<y";
	else cout<<"x>=y";
}

本质上,我们重载了 (),因此能够将这个对象像函数一样使用。

具体代码

堆的实现,我们已经讲过,这里就不做赘述,感兴趣的读者可以翻阅我前面的文章。

template<class T,class Container=vector<T>,class Compare = less<T>>
class priority_queue
{
public:

	//默认大堆
	void adjust_up(size_t child)
	{
		size_t parent = (child - 1) / 2;
		Compare com;
		while (child >0)
		{
			if (com(_con[parent], _con[child]))
			{
				std::swap(_con[child], _con[parent]);
				child = parent;
				parent = (child - 1) / 2;
			}
			else
			{
				break;
			}
		}
	}

	void push(const T& x)
	{
		_con.push_back(x);
		adjust_up(_con.size() - 1);
	}

	void adjust_down(size_t parent)
	{
		size_t child = parent * 2 + 1;
		while (child<_con.size())
		{
			if (child + 1 < _con.size() && com(_con[child],_con[child+1]))
			{
				++child;
			}
			if (com(_con[parent],_con[child]))
			{
				std::swap(_con[child], _con[parent]);
				parent = child;
				child = parent * 2 + 1;
			}
			else
			{
				break;
			}
		}
	}

	void pop()
	{
		std::swap(_con[0], _con[_con.size() - 1]);
		_con.pop_back();
		adjust_down(0);
	}

	bool empty()
	{
		return _con.empty();
	}

	size_t size()
	{
		return _con.size();
	}

	const T& top()
	{
		return _con[0];
	}

private:
	Container _con;
};

说起来这里比较奇怪的点是,默认传入less<T>是大根堆,而穿入greater<T>却是小根堆。
但sort穿入,less<T>却是升序排序:

int main()
{
	vector<int>v = { 1,5,4,3,2 };
	sort(v.begin(), v.end(),less<int>());//传入less的匿名对象
	for (auto& e : v)cout << e << ' ';
	cout << endl;
	return 0;
}

Output:1 2 3 4 5

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

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

相关文章

产品经理入门(2)产品体验报告

产品体验报告大纲&#xff1a;重点在产品体验——优点。 1.产品概括 可以从各大平台搜产品介绍。 2.市场分析 按照产品方向分析各个指标——包括有效使用时间,市场规模等。 3. 用户分析——对用户通过各项指标画像。 4.产品体验——对各项功能与设计的体验。 5.报告总结

C43-指针与数组

一 定义一个指针变量指向数组 1.途径一:指向数组首元素的地址 代码示例: #include <stdio.h> int main() {int arr[3]{2,4,5};int *p;p&arr[0];printf("该数组的首元素是:%d",*p);return 0; }成果展示: 报错与总结: 给指针变量赋值时,未在数组首元素前输…

UDP--DDR--SFP,FPGA实现之ddr读写控制模块

DDR读写控制模块实现介绍 由于该模块接口数量较多&#xff0c;为了详细说明模块实现&#xff0c;采用文字流程进行介绍 上级模块传输数据到来捕捉数据有效上升沿传输写指令&#xff0c;写有效&#xff0c;写指令成功被下一级模块缓存&#xff0c;进行写地址一次读写长度&…

云计算与大数据进阶 | 26、解锁云架构核心:深度解析可扩展数据库的5大策略与挑战(上)

在云应用/服务的 5 层架构里&#xff0c;数据库服务层稳坐第 4 把交椅&#xff0c;堪称其中的 “硬核担当”。它的复杂程度常常让人望而生畏&#xff0c;不少人都将它视为整个架构中的 “终极挑战”。 不过&#xff0c;也有人觉得可扩展存储系统才是最难啃的 “硬骨头”&#…

AI Agent | Coze 插件使用指南:从功能解析到实操步骤

一、前言 在人工智能技术飞速发展的今天&#xff0c;低代码开发模式正成为构建智能应用的主流趋势。对于希望快速搭建 AI Bot 的开发者和业务人员而言&#xff0c;coze作为一款强大的低代码 AI 开发平台&#xff0c;凭借其高度模块化的插件体系脱颖而出。这些插件就像搭建智能…

MK米客方德SD NAND:无人机存储的高效解决方案

在无人机技术迅猛发展的当下&#xff0c;飞控系统的数据记录对于飞行性能剖析、故障排查以及飞行安全保障极为关键。以往&#xff0c;SD 卡是飞控 LOG 记录常见的存储介质&#xff0c;但随着技术的革新&#xff0c;新的存储方案不断涌现。本文聚焦于以 ESP32 芯片为主控制器的无…

【vscode】解决vscode无法安装远程服务器插件问题,显示正在安装

文章目录 现状分析采用VSIX离线安装第一步&#xff1a;离线下载插件包第二步&#xff1a;把下载好的插件文件上传到远程服务器上第三步&#xff1a;在windows下打开vscode&#xff0c;并链接远端&#xff0c;进行安装 现状分析 vscode无法远程安装扩展插件&#xff0c;显示正在…

【Spring】Spring的请求处理

欢迎来到啾啾的博客&#x1f431;。 记录学习点滴。分享工作思考和实用技巧&#xff0c;偶尔也分享一些杂谈&#x1f4ac;。 欢迎评论交流&#xff0c;感谢您的阅读&#x1f604;。 目录 引言HTTP/HTTPS协议Spring Web与Spring Web MVCSpring WebFlux 自定义的TPC/IP协议FTP、S…

粒子群算法(PSO算法)

粒子群算法概述 1.粒子群优化算法&#xff08;Particle Swarm Optimization&#xff0c;简称PSO&#xff09;。粒子群优化算法是在1995年由Kennedy博士和Eberhart博士一起提出的&#xff0c;它源于对鸟群捕食行为的研究。 2.基本核心是利用群体中的个体对信息的共享从而使得整…

LLM智能体新纪元:深入解析MCP与A2A协议,赋能智能自动化协作

LLM智能体&#xff08;LLM agents&#xff09;是能够自主行动以实现特定目标的AI系统。在实际应用中&#xff0c;智能体能够将用户请求拆解为多个步骤&#xff0c;利用知识库或API获取数据&#xff0c;最终整合出答案。这让智能体相比于传统独立聊天机器人拥有更强大的能力——…

SAP学习笔记 - 开发豆知识01 - CDS SDK命令出乱码 (cds init CAP-Test03 --add java)

1&#xff0c;现象 安装完VSCode以及各种需要的插件&#xff08;比如SAP CDS Language Support&#xff09;&#xff0c;就可以做CAP开发。 用这个命令创建Project&#xff1a;cds init CAP-Test03 --add java 然后出来一个乱码错误 adding java The derived package name c…

(C语言)超市管理系统 (正式版)(指针)(数据结构)(清屏操作)(文件读写)(网页版预告)(html)(js)(json)

目录 前言&#xff1a; 源代码&#xff1a; product.h product.c fileio.h fileio.c main.c json_export.h json_export.c tasks.json idex.html script.js 相关步骤&#xff1a; 第一步&#xff1a; 第二步&#xff1a; 第三步&#xff1a; 第四步&#xff1a; 第五步…

进阶-数据结构部分:​​​​​​​2、常用排序算法

飞书文档https://x509p6c8to.feishu.cn/wiki/FfpIwIPtviMMb4kAn3Sc40ABnUh 常用排序算法 这几种算法都是常见的排序算法&#xff0c;它们的优劣和适用场景如下&#xff1a; 冒泡排序&#xff08;Bubble Sort&#xff09;&#xff1a;简单易懂&#xff0c;时间复杂度较高&…

25、DeepSeek-R1论文笔记

DeepSeek-R1论文笔记 1、研究背景与核心目标2、核心模型与技术路线3、蒸馏技术与小模型优化4、训练过程简介5、COT思维链&#xff08;Chain of Thought&#xff09;6、强化学习算法&#xff08;GRPO&#xff09;7、冷启动**1. 冷启动的目的****2. 冷启动的实现步骤****3. 冷启动…

LeetCode --- 156双周赛

题目列表 3541. 找到频率最高的元音和辅音 3542. 将所有元素变为 0 的最少操作次数 3543. K 条边路径的最大边权和 3544. 子树反转和 一、找到频率最高的元音和辅音 分别统计元音和辅音的出现次数最大值&#xff0c;然后相加即可&#xff0c;代码如下 // C class Solution {…

npm 报错 gyp verb `which` failed Error: not found: python2 解决方案

一、背景 npm 安装依赖报如下错&#xff1a; gyp verb check python checking for Python executable "python2" in the PATH gyp verb which failed Error: not found: python2 一眼看过去都觉得是Python环境问题&#xff0c;其实并不是你python环境问题&#xf…

初识Linux · IP协议· 下

目录 前言&#xff1a; 内网IP和公网IP 内网IP 公网IP 路由 前言&#xff1a; 前文我们介绍了IP协议的协议头&#xff0c;通过源码等方式我们理解了IP协议中的字段&#xff0c;比如8位协议&#xff0c;比如通过环回问题引出的8位最大生存时间&#xff0c;比如8位协议&…

JAVA的常见API文档(上)

游戏打包 注意API文档中的方法不需要记忆&#xff01;&#xff01; 了解之后如果需要可以查询API文档 对Math的方法总结&#xff1a; 运用刚学的Math方法加快代码的运行效率 可以减少循环次数 找规律&#xff1a; 发现因子有规律&#xff1a; 必定一个大于平方根&#xff0c;…

Spark,连接MySQL数据库,添加数据,读取数据

连接数据库 可以看到shell中我们读取出的数据 在IDEA中打代码如果能输出跟shell中一样的结果即证明连接成功 【出错反思】 像我前面出错的原因就是在打代码时将密码输入错误 添加数据 读取数据就是在上面代码中一起展示了&#xff0c;这里我就不单独说了

【EDA软件】【联合Modelsim仿真使用方法】

背景 业界EDA工具仿真功能是必备的&#xff0c;例如Vivado自带仿真工具&#xff0c;且无需联合外部仿真工具&#xff0c;例如MoodelSim。 FUXI工具仿真功能需要联合Modelsim&#xff0c;才能实现仿真功能。 方法一&#xff1a;FUXI联合ModelSim 1 添加testbench文件 新建to…