数据结构:队列和栈的相互实现

发布时间:2026/9/14 22:50:32

数据结构:队列和栈的相互实现 文章目录前言一、队列实现栈1.2 代码的实现1.2.1结构体的构建1.2.2 初始化1.2.3 模型入栈1.2.4 模拟出栈并返回栈顶元素1.2.5 获取栈顶元素1.2.6 判空1.2.7 释放二 栈实现队列2.1 思路分析2.2 代码实现2.2.1 结构体的构建2.2.2 初始化2.2.3 将元素 x 推到队列的末尾(模拟入队)2.2.4 返回队列开头的元素2.2.5 从队列的开头移除并返回元素(模拟出队)2.2.6 判空2.2.7 销毁前言虽然在实践中没有什么意义但是可以帮助我们熟悉和了解栈和队列一、队列实现栈思路如下图所示队列的规则是先进先出而栈的规则是后进先出如图中q1我们入队1、2、3、4按照栈我们出栈的是4因此我们将q1中的红色框中的数据导给q2然后剩下44直接出队就达到了效果。当我们出完4后当我们想入数据是给q1还是q2呢q2假设我们入给q1如下图所示然后我们需要6出队该怎么出呢是不是想将5导入到q2再出6那如果我再出5你是不是要让q2的1、2、3、4导给q1然后出5。如果再进行push呢又给q2吗这样会一直导来导去逻辑会混乱。那栈顶的数据我们就不知道是在q1还是在q2。因此我们需要向非空的队列中去push数据。1.2 代码的实现首先需要了解队列的实现#includestdio.h#includestdlib.h#includeassert.h#includestdbool.htypedefintQDataTpye;typedefstructQueueNode{QDataTpye val;structQueueNode*next;}QueueNode;typedefstructQueue{QueueNode*ptail;QueueNode*phead;intsize;}Queue;//初始化voidQueueInit(Queue*pq);//队尾插入voidQueuePush(Queue*pq,QDataTpye x);//队头删除voidQueuePop(Queue*pq);//取队头队尾的数据QDataTpyeQueueFront(Queue*pq);QDataTpyeQueueBack(Queue*pq);//个数intQueueSize(Queue*pq);//判空boolQueueEmpty(Queue*pq);//销毁voidQueueDestory(Queue*pq);voidQueueInit(Queue*pq){assert(pq);pq-pheadpq-ptailNULL;pq-size0;}voidQueuePush(Queue*pq,QDataTpye x){assert(pq);QueueNode*newnode(QueueNode*)malloc(sizeof(QueueNode));if(newnodeNULL){perror(QueuePush::malloc);return;}newnode-nextNULL;newnode-valx;//空的if(pq-pheadNULL){pq-pheadpq-ptailnewnode;}else//尾插{pq-ptail-nextnewnode;pq-ptailnewnode;}pq-size;}intQueueSize(Queue*pq){assert(pq);returnpq-size;}voidQueuePop(Queue*pq){assert(pq);assert(pq-size!0);//一个节点if(pq-phead-nextNULL){free(pq-phead);pq-pheadpq-ptailNULL;}else{QueueNode*nextpq-phead-next;free(pq-phead);pq-pheadnext;}pq-size--;}QDataTpyeQueueFront(Queue*pq){assert(pq);assert(pq-phead);returnpq-phead-val;}QDataTpyeQueueBack(Queue*pq){assert(pq);assert(pq-ptail);returnpq-ptail-val;}boolQueueEmpty(Queue*pq){assert(pq);returnpq-size0;}voidQueueDestory(Queue*pq){assert(pq);QueueNode*curNULL;curpq-phead;while(cur){QueueNode*temcur-next;free(cur);curtem;}pq-pheadpq-ptailNULL;pq-size0;在实现队列的基础上再来用两个队列实现栈1.2.1结构体的构建首先我们需要封装一个结构体来管理这两个队列typedefstructMyStack{Queue q1;Queue q2;}MyStack;1.2.2 初始化对结构体进行初始化MyStack*MyStackCreat(){MyStack*pst(MyStack*)malloc(sizeof(MyStack));if(pstNULL){perror(MyStackCreat::malloc);exit(1);}QueueInit((pst-q1));QueueInit((pst-q2));returnpst;}1.2.3 模型入栈谁不为空就入给谁都为空随便入voidmyStackPush(MyStack*obj,QDataTpye x){if(!QueueEmpty((obj-q1))){QueuePush((obj-q1),x);}else{QueuePush((obj-q2),x);}}1.2.4 模拟出栈并返回栈顶元素intmyStackPop(MyStack*obj){//假设法MyStack*Empty(obj-q1);MyStack*nonEmpty(obj-q2);if((obj-q2)NULL){nonEmpty(obj-q1);Empty(obj-q2);}//不为空前size-1导走删除最后一个就是栈顶数据while(QueueSize(nonEmpty)1){QueuePush(Empty,QueueFront(nonEmpty));QueuePop(nonEmpty);}inttopQueueFront(nonEmpty);QueuePop(nonEmpty);returntop;}1.2.5 获取栈顶元素找到不为空的队列返回队尾元素就是栈顶元素intmyStackTop(MyStack*obj){if(!QueueEmpty((obj-q1))){returnQueueBack(((obj-q1)));}else{returnQueueBack(((obj-q2)));}}1.2.6 判空也就是判断两个队列是否为空boolmyStckEmpty(MyStack*obj){returnQueueEmpty((obj-q2))QueueEmpty((obj-q1));}1.2.7 释放直接释放obj没有当我们直接释放掉obj时除了释放掉了obj后面的都没有释放掉会造成内存泄漏voidmyStackFree(MyStack*obj){QueueDestory((obj-q1));QueueDestory((obj-q2));free(obj);}这里obj置不置空都行它是一级指针只起到传值的作用改变不了实参。二 栈实现队列2.1 思路分析首先我们需要明白栈是后进先出而队列是先进先出。和上面队列实现栈一样我们将一个不为空的栈导到另外一个栈去然后出栈是不是就达到效果了。此时第一个栈就变成空如果我们再想入栈数据该怎么办呢是向非空的栈入数据的话我们就需要保持之前的顺序需要将第二个栈的数据导到第一个栈然后入栈数据然后再将这个数据导入到第二个栈中出栈这也是可以的但是很麻烦。因此我们只需要将一个栈作为入栈另一个栈出栈就好了比如之前导好后的数据我们需要再入栈就向最开始导的栈中入然后等另外一个栈所有的数据完成出栈后再将数据导入进去。2.2 代码实现首先我们需要在实现栈的基础上完成。typedefintSTDataType;typedefstruct{STDataType*arr;//指向栈数组空间的指针inttop;//栈顶位置intcapacity;//容量}Stack;//栈的初始化voidStackInit(Stack*s);//栈的销毁voidStackDestory(Stack*s);//核心逻辑//x元素入栈voidStackPush(Stack*s,STDataType x);//将栈顶元素出栈并返回栈顶元素STDataTypeStackPop(Stack*s);//获取栈顶元素并返回STDataTypeStackTop(Stack*s);//获取栈中有效元素个数intStackSize(Stack*s);//检测栈是否为空如果是空返回真否则返回假boolStackEmpty(Stack*s);voidStackInit(Stack*s){assert(s);s-arr(STDataType*)malloc(4*sizeof(STDataType));//开辟四个元素的空间if(s-arrNULL){perror(StackInit::malloc);return;}// 初始化时top 0表⽰top指向的是栈顶元素的下⼀个位置// 初始化时top -1表⽰top指向的是栈顶元素s-top0;s-capacity0;}voidStackPush(Stack*s,STDataType x){assert(s);//空间扩容if(s-capacitys-top){intnewcapacitys-capacity0?4:2*s-capacity;STDataType*tem(STDataType*)realloc(s-arr,sizeof(STDataType)*newcapacity);if(temNULL){perror(tem::realloc);exit(1);}s-arrtem;s-capacitynewcapacity;}//入栈s-arr[s-top]x;}STDataTypeStackPop(Stack*s){assert(s);//判断是否为空如为空就没有出栈的必要if(!StackEmpty(s))returns-arr[--s-top];}STDataTypeStackTop(Stack*s){assert(s);if(!StackEmpty(s))returns-arr[s-top-1];//top0,指向的是栈顶下一个位置}intStackSize(Stack*s){assert(s);returns-top;}boolStackEmpty(Stack*s){assert(s);returns-top0;}voidStackDestory(Stack*s){assert(s);if(s-arr){free(s-arr);s-arrNULL;s-top0;s-capacity0;}}2.2.1 结构体的构建在栈的结构上构建两个栈一个栈作为入栈一个栈作为出栈typedefstructSTQ{Stack s1;//栈1入栈Stack s2;//栈2出栈}MyQueue;2.2.2 初始化MyQueue*myQueueCreate(){MyQueue*obj(MyQueue*)malloc(sizeof(MyQueue));if(objNULL){perror(myQueueCreate::malloc);exit(1);}StackInit((obj-s1));StackInit((obj-s2));returnobj;}2.2.3 将元素 x 推到队列的末尾(模拟入队)voidmyQueuePush(MyQueue*obj,intx){assert(obj);StackPush((obj-s1),x);}2.2.4 返回队列开头的元素我们先确定s2是否为空为空我们需要将s1的数据导入s2中然后去s2的栈顶元素即可intmyQueuePeek(MyQueue*obj){assert(obj);if(StackEmpty((obj-s2))){//导数据while(!StackEmpty((obj-s1))){inttopStackTop((obj-s1));StackPush((obj-s2),top);StackPop((obj-s1));}}returnStackTop((obj-s2));}2.2.5 从队列的开头移除并返回元素(模拟出队)这个和上面的2.2.4差不多都需要导入数据但是导入数据后只需要pop就可以了。intmyQueuePop(MyQueue*obj){assert(obj);inttopmyQueuePeek((obj-s2));StackPop((obj-s2));returntop;}2.2.6 判空boolmyQueueEmpty(MyQueue*obj){assert(obj);returnStackEmpty((obj-s1))StackEmpty((obj-s1));}2.2.7 销毁voidmyQueueFree(MyQueue*obj){StackDestory(obj-s1);StackDestory(obj-s2);free(obj);}
延伸阅读

更多相关文章

2026/9/11 2:40:51

DPWM技术解析:高效电力电子转换的核心

1. DPWM技术背景与核心价值在电力电子领域,PWM(脉宽调制)技术堪称现代功率变换器的"心脏"。而DPWM(Discontinuous Pulse Width Modulation,不连续脉宽调制)作为PWM家族中的重要分支,其…

2026/9/10 16:22:00

Java线程与CPU调度原理及性能优化实践

1. Java线程与CPU调度的核心关系 现代计算机系统中,CPU作为计算核心资源,其调度机制直接影响着Java多线程程序的执行效率。理解这两者的交互原理,是编写高性能并发程序的基础。我们先从最底层的硬件特性说起: CPU物理核心与逻辑线…

2026/9/13 9:53:58

射频功放(PA)核心参数解析与效率优化实践

1. 射频功放(PA)基础概念与核心价值射频功率放大器(Power Amplifier,简称PA)是无线通信系统中不可或缺的关键部件,它位于发射链路的末端,负责将调制后的射频信号放大到足够的功率电平&#xff0…

2026/9/14 22:46:03

AI辅助系统诊断:8GB老笔记本内存占用从94%降至64%

如果你的笔记本只有8GB内存,打开任务管理器看到内存占用94%,你的第一反应是什么?去年的我就是这个状态,风扇狂转、切窗口要等三秒、开个浏览器直接卡死。今年我换了个思路:不凭感觉瞎清理,而是把AI当成一个…

2026/9/14 22:46:03

全景红外热成像测温预警:重构工业安全防线的技术解析

1. 为什么工业现场需要“全景红外”这双眼睛1.1 一个真实的痛点场景做工业安全监控这行十多年,我见过太多类似的项目:一家占地几百亩的化工厂,厂区里有反应釜、储罐区、管廊桥架,还有装卸站台,传统的方案是布上十几路甚…

2026/9/14 22:46:03

LangChain模型调用指南:LLM与Chat Models对比与实践

1. LangChain 模型调用基础解析在构建基于大语言模型的应用程序时,LangChain 提供了两种核心模型接口:LLM(大型语言模型)和 Chat Models(聊天模型)。这两者的本质区别在于输入输出结构和适用场景。1.1 LLM …

2026/9/14 22:46:03

基于Hadoop、Hive与LSTM的美食推荐系统毕设实战全解析

又到了一年一度毕业设计选题的时候,后台私信里问我“XX系统怎么做”的同学越来越多。其中被问到最多次的,就是“美团大众点评的美食推荐系统”这个课题。坦白讲,这个题目能火不是没道理的:一是美团点评的数据真实、有说服力&#…

2026/9/14 22:41:03

OpenCLI:将网站转化为命令行工具的开源方案

1. 项目概述:OpenCLI如何将网站变成命令行工具OpenCLI是一款革命性的AI原生工具,它能够将任意网站、本地工具或Electron应用转化为可被AI调用的命令行接口。这个开源项目在GitHub上获得了广泛关注,其核心价值在于打破了传统网页交互的局限&am…

2026/9/14 2:17:50

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/14 0:03:22

KCF目标跟踪算法与OTB工程实现:毕业设计实战解析

简介:这是一份基于KCF核相关滤波算法、融合尺度池与抗遮挡处理的目标检测跟踪MATLAB完整源码,主要面向计算机相关专业准备毕业设计、课程设计或期末大作业的学生,也适合需要项目实战练习的初学者。源码在OTB数据集上完成验证,能够…

2026/9/14 0:03:22

语音情感识别实战:Keras实现LSTM、CNN、SVM与MLP多模型对比

简介:面向语音情感识别入门与进阶开发者,这份基于Keras的项目源码完整实现了LSTM、CNN、SVM、MLP四种模型,兼容Python3.8与Keras/TensorFlow2环境。压缩包内含49个文件,大小约70.31MB,主体包括Python脚本、yaml/json配…

2026/9/14 11:59:31

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/14 13:53:59

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/14 11:22:57

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码