【数据结构】如何用栈实现队列?图文解析(LeetCode)

news2024/12/28 2:54:25

LeetCode链接:232. 用栈实现队列 - 力扣(LeetCode)

注:本文默认读者已掌握栈与队列的基本操作

可以看这篇文章熟悉知识点:【数据结构】栈与队列_字节连结的博客-CSDN博客

目录

做题思路

代码实现

1. MyQueue

2. myQueueCreate

 3. myQueuePush

4. myQueuePeek

5. myQueuePop

6. myQueueEmpty

7. myQueueFree

全部代码


做题思路

简单来说,就是把一个栈(栈1)的数据捯入另一个栈(栈2),此时(栈2)出数据的顺序就和队列是一样的。

为了更方便理解,我会画图来演示一下具体思路。

我们需要两个栈来实现队列:

  • push栈:专门入数据的栈
  • pop栈:专门出数据的栈

如下图:

插入数据:直接在push栈内插入即可

push栈内插入数据:1、2、3、4、5

删除数据:需要把push栈内的数据捯入pop栈

  • 栈是后入先出的
  • 当push栈的数据捯入pop栈后,数据顺序会改变

如下图:

可以看到数据顺序逆转了

但是的这些操作跟队列有什么联系呢?

不妨来看看pop栈队列的对比:

由此可见:pop栈出数据的顺序是和队列一样的

到这里思路已经很清晰了:我们需要两个栈,一个专门用来push,一个专门用来pop,捯数据后,pop栈出数据的顺序就跟队列是一样的。

那么如何用代码(C)来实现这个思路呢?


代码实现

由于我们使用的是C语言,不能直接使用栈的操作

所以先把之前模拟实现过的栈复制过来:

//C语言模拟实现栈

typedef int STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;
	int capacity;
}ST;

//初始化栈
void STInit(ST* ps);
//销毁栈
void STDestroy(ST* ps);
//入栈
void STPush(ST* ps, STDataType x);
//出栈
void STPop(ST* ps);
//获取栈顶元素
STDataType STTop(ST* ps);
//获取栈中有效元素个数
int STSize(ST* ps);
//检测栈是否为空,如果为空返回非零结果,如果不为空返回0
bool STEmpty(ST* ps);

void STInit(ST* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}

void STDestroy(ST* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}

void STPush(ST* ps, STDataType x)
{
	assert(ps);
	if (ps->top == ps->capacity)
	{
		int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newCapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity = newCapacity;
	}
	ps->a[ps->top] = x;
	ps->top++;
}

void STPop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);
	ps->top--;
}

STDataType STTop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);
	return ps->a[ps->top - 1];
}

int STSize(ST* ps)
{
	assert(ps);
	return ps->top;
}

bool STEmpty(ST* ps)
{
	assert(ps);
	return ps->top == 0;
}

复制完成之后就是本题的重点内容了。

本题要求:

实现 MyQueue 类:

  • void push(int x) 将元素 x 推到队列的末尾
  • int pop() 从队列的开头移除并返回元素
  • int peek() 返回队列开头的元素
  • boolean empty() 如果队列为空,返回 true ;否则,返回 false

1. MyQueue

由于我们是用两个栈实现队列

所以这里需要定义两个栈

//两个栈模拟实现队列
typedef struct
{
    ST pushst;
    ST popst;
} MyQueue;

2. myQueueCreate

这个函数要求我们开辟空间,并初始化栈

//开辟空间并初始化
MyQueue* myQueueCreate()
{
    MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
    STInit(&obj->pushst);
    STInit(&obj->popst);
    return obj;
}

 3. myQueuePush

直接把数据插入到push栈即可

//将元素X推到队列的末尾
void myQueuePush(MyQueue* obj, int x)
{
    STPush(&obj->pushst, x);
}

4. myQueuePeek

本函数要求返回队列开头的元素

  • 如果pop栈为空:要把push栈的数据捯入pop栈才能找到队列的首元素
  • 如果pop栈不为空:pop栈的栈顶元素就是队列的首元素

//返回队列开头的元素
int myQueuePeek(MyQueue* obj)
{
    if (STEmpty(&obj->popst))
    {
        //捯数据
        while (!STEmpty(&obj->pushst))
        {
            STPush(&obj->popst, STTop(&obj->pushst));
            STPop(&obj->pushst);
        }
    }
    return STTop(&obj->popst);
}

5. myQueuePop

  • 要求删除队头元素,也就是pop栈的栈顶元素,直接删除即可
  • 并且要返回队头元素的值,需要先定义一个临时变量来保存队头元素的值
  • 最后返回这个临时变量
//从队列的开头移除并返回元素
int myQueuePop(MyQueue* obj)
{
    int front = myQueuePeek(obj);
    STPop(&obj->popst);
    return front;
}

6. myQueueEmpty

判断队列是否为空,返回一个bool值(true/false)

如果push栈pop栈都为空,则说明队列为空

//如果队列为空,返回true;否则,返回false
bool myQueueEmpty(MyQueue* obj)
{
    return STEmpty(&obj->popst) && STEmpty(&obj->pushst);
}

7. myQueueFree

销毁队列

  • 销毁push栈pop栈
  • 释放动态开辟的空间
//销毁队列
void myQueueFree(MyQueue* obj)
{
    STDestroy(&obj->popst);
    STDestroy(&obj->pushst);
    free(obj);
}

到这里全部函数已经实现完毕,提交代码:

成功通过

下面我会把本题的全部代码整合在一起发出来


全部代码

//C语言模拟实现栈

typedef int STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;
	int capacity;
}ST;

//初始化栈
void STInit(ST* ps);
//销毁栈
void STDestroy(ST* ps);
//入栈
void STPush(ST* ps, STDataType x);
//出栈
void STPop(ST* ps);
//获取栈顶元素
STDataType STTop(ST* ps);
//获取栈中有效元素个数
int STSize(ST* ps);
//检测栈是否为空,如果为空返回非零结果,如果不为空返回0
bool STEmpty(ST* ps);

void STInit(ST* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}

void STDestroy(ST* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}

void STPush(ST* ps, STDataType x)
{
	assert(ps);
	if (ps->top == ps->capacity)
	{
		int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newCapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity = newCapacity;
	}
	ps->a[ps->top] = x;
	ps->top++;
}

void STPop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);
	ps->top--;
}

STDataType STTop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);
	return ps->a[ps->top - 1];
}

int STSize(ST* ps)
{
	assert(ps);
	return ps->top;
}

bool STEmpty(ST* ps)
{
	assert(ps);
	return ps->top == 0;
}

//=======================================================================

//两个栈模拟实现队列
typedef struct
{
    ST pushst;
    ST popst;
} MyQueue;

//开辟空间并初始化
MyQueue* myQueueCreate()
{
    MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
    STInit(&obj->pushst);
    STInit(&obj->popst);
    return obj;
}

//将元素X推到队列的末尾
void myQueuePush(MyQueue* obj, int x)
{
    STPush(&obj->pushst, x);
}

//返回队列开头的元素
int myQueuePeek(MyQueue* obj)
{
    if (STEmpty(&obj->popst))
    {
        //捯数据
        while (!STEmpty(&obj->pushst))
        {
            STPush(&obj->popst, STTop(&obj->pushst));
            STPop(&obj->pushst);
        }
    }
    return STTop(&obj->popst);
}

//从队列的开头移除并返回元素
int myQueuePop(MyQueue* obj)
{
    int front = myQueuePeek(obj);
    STPop(&obj->popst);
    return front;
}

//如果队列为空,返回true;否则,返回false
bool myQueueEmpty(MyQueue* obj)
{
    return STEmpty(&obj->popst) && STEmpty(&obj->pushst);
}

//销毁队列
void myQueueFree(MyQueue* obj)
{
    STDestroy(&obj->popst);
    STDestroy(&obj->pushst);
    free(obj);
}

本文完​​​​​​​

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

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

相关文章

windows10 docker 安装在D盘

win10安装docker后发现c盘空间急速减少,360管家查看发现images镜像安装在C盘,于是重装docker desktop以为在安装过程中能够选择,遗憾的是没有提供选择权限,默认直接就安装到了c盘。 desktop 迁移 百度得知可以将c盘的docker安装…

【Sublime Text 】Sublime Text 设置中文 超详细 持续更新中

Sublime Text 设置中文 超详细 持续更新中 概述开发环境一、Sublime Text 设置中文 概述 一个好的安装教程能够帮助开发者完成更便捷、更快速的开发。书山有路勤为径,学海无涯苦作舟。我是秋知叶i、期望每一个阅读了我的文章的开发者都能够有所成长。 开发环境 开…

微积分基本概念

微分 函数的微分是指对函数的局部变化的一种线性描述。微分可以近似地描述当函数自变量的取值作足够小的改变时,函数的值是怎样改变的。。对于函数 y f ( x ) y f(x) yf(x) 的微分记作: d y f ′ ( x ) d x d_y f^{}(x)d_x dy​f′(x)dx​ 微分和…

STTran: Spatial-Temporal Transformer for Dynamic Scene Graph Generation

文章目录 0 Abstract1 Introduction2 Related Work3 Method3.1 Transformer3.2 Relationship Representation3.3 Spatio-Temporal Transformer3.3.1 Spatial Encoder3.3.2 Frame Encoding3.3.3 Temporal Decoder 3.4 Loss Function3.5 Graph Generation Strategies 4 Experimen…

最新ChatGPT网站AI系统源码+详细图文搭建教程/支持GPT4/AI绘画/H5端/Prompt知识库

一、AI系统 如何搭建部署AI创作ChatGPT系统呢?小编这里写一个详细图文教程吧! SparkAi使用Nestjs和Vue3框架技术,持续集成AI能力到AIGC系统! 1.1 程序核心功能 程序已支持ChatGPT3.5/GPT-4提问、AI绘画、Midjourney绘画&#…

3.1、BGP的通告原则

BGP的通告原则 1、BGP通过network、.import-route、aggregate聚合方式生成BGP路由后,通过Update?报文将BGP路由传递给对等体。 2、BGP通告遵循以下原则: 只发布最优且有效路由。从EBGP对等体获取的路由,会发布给所有对等体。IBGP水平分割…

R语言画样本不均衡组的箱线图

# 导入 ggplot2 包 library(ggplot2)# 示例数据框&#xff0c;包含数值数据和分组信息 data <- data.frame(Group c(rep("Group A",10), rep("Group B",15),rep("Group C",20)),Value c(rnorm(10, mean 10, sd 2),rnorm(15, mean 15, sd…

渗透测试漏洞原理之---【XSS 跨站脚本攻击】

文章目录 1、跨站 脚本攻击1.1、漏洞描述1.2、漏洞原理1.3、漏洞危害1.4、漏洞验证1.5、漏洞分类1.5.1、反射性XSS1.5.2、存储型XSS1.5.3、DOM型XSS 2、XSS攻防2.1、XSS构造2.1.1、利用<>2.1.2、JavaScript伪协议2.1.3、时间响应 2.2、XSS变形方式2.2.1、大小写转换2.2.2…

【设备树笔记整理6】中断系统中的设备树

1 中断概念的引入与处理流程 1.1 中断处理框图 1.2 中断程序的使用 主函数() while(1) {do_routine_task(); }中断处理函数() {handle_interrupt_task(); }如何调用中断处理函数&#xff1f; 1.3 ARM对异常(中断)的处理过程 &#xff08;1&#xff09;初始化 ① 设置中断…

springboot+mp完成简单案例

目录 1.框架搭建 2.前端搭建 3.后端编写 需求&#xff1a;完成简单的连表条件查询以及添加即可 1.框架搭建 1.创建springboot项目 2.相关依赖 <!--web依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boo…

Java 时间日期处理,工作必用(建议收藏)

工作中经常会遇到对时间日期进行处理的业务&#xff0c;像日期类的API个人觉得不需要背&#xff0c;需要的时候去查资料就行。我整理了Java8之前及之后日期类常用的时间日期处理方法&#xff0c;方便工作需要时查找&#xff0c;觉得有用的朋友可以收藏。 一、日期格式化和解析 …

ElasticSearch - 海量数据索引拆分的一些思考

文章目录 困难解决方案初始方案及存在的问题segment merge引入预排序 拆分方案设计考量点如何去除冗余数据按什么维度拆分&#xff0c;拆多少个最终的索引拆分模型演进历程整体迁移流程全量迁移流程流量回放比对验证异步转同步多索引联查优化效果 总结与思考参考 困难 索引数据…

DaVinci Resolve(达芬奇)软件安装包分享(附安装教程)

目录 一、软件简介 二、软件下载 一、软件简介 DaVinci Resolve是一款专业的影视后期制作软件&#xff0c;被广泛应用于电影、电视剧、广告、纪录片等影视制作领域。它提供了全面的后期制作工具&#xff0c;包括色彩校正、颜色分级、视觉效果处理、音频处理等&#xff0c;能够…

【前端工程化】万字拆解package.json (一)

什么是package package 指拥有 package.json 的一个文件夹&#xff08;或压缩包&#xff09;&#xff0c;而 package 的属性就是 package.json 文件的内容&#xff0c;比如&#xff1a; name&#xff1a;这个包叫什么名字&#xff0c;唯一version&#xff1a;这个包的版本号是…

第三方检测检验实验室信息化建设

检测公司配置先进的信息化管理系统&#xff0c;信息化管理系统采用适宜的、先进的架构&#xff0c;具备开放性、扩展性、前瞻性、安全性等。先期建设按照实验室的规格及整体配套设施&#xff0c;整个实验室信息化系统的结构化数据考虑本地存储&#xff0c;且应考虑高速存储应用…

python3GUI--模仿一些b站网页端组件By:PyQt5(详细介绍、附下载地址)

文章目录 一&#xff0e;前言二&#xff0e;展示1.banner1.静图2.动图 2.一般视频组件1.静图2.动图 3.排行榜1.静图2.动图 三&#xff0e;设计心得(顺序由简到难)1.排行榜2.一般视频组件3.banner 四&#xff0e;总结五&#xff0e;下载地址 一&#xff0e;前言 播客二连发&…

React Hooks 全解:零基础入门

Hooks 的由来 你还在为该使用无状态组件&#xff08;Function&#xff09;还是有状态组件&#xff08;Class&#xff09;而烦恼吗&#xff1f; ——拥有了hooks&#xff0c;你再也不需要写Class了&#xff0c;你的所有组件都将是Function。 你还在为搞不清使用哪个生命周期钩…

RT-Thread 线程间同步

多个执行单元&#xff08;线程、中断&#xff09;同时执行临界区&#xff0c;操作临界资源&#xff0c;会导致竟态产生。 RTT使用信号量、互斥量、事件集来解决这种问题。 同步&#xff08;按顺序&#xff09;、互斥&#xff08;排它&#xff09;。 信号量 信号量是一种轻型…

Adobe Media Encoder软件安装包分享(附安装教程)

目录 一、软件简介 二、软件下载 一、软件简介 Adobe Media Encoder是一款由Adobe公司开发的视频和音频后期制作软件&#xff0c;它集成了多种编码格式和输出选项&#xff0c;可以帮助用户将视频和音频文件转换成适合各种用途的格式。该软件可以与Adobe Premiere Pro、After …

使用delphi XE10.3.2 开发linux 上的Daemon

delphi 10.3.2支持linux, 而且官方只是支持命令行编程,目地就是做linux 服务器端的开发。 既然是做linux服务器端的开发,那么普通的命令行运行程序,然后等待开一个黑窗口的方式就 太low了(目前就有个别语言大咖,经常在Windows 上开个黑窗口,看起来非常恶心),那么如果…