数据结构刷题训练:用栈实现队列(力扣OJ)

目录

前言

1. 题目:用栈实现队列

2. 思路

3. 分析

 3.1 定义 “ 队列 ”

 3.2 创建队列

3.3 入队

 3.4 队头数据

 3.5 出队

 3.6 判空和销毁

4.题解

总结


前言

        栈和队列是数据结构中的两个重要概念,它们在算法和程序设计中都有着广泛的应用。本文将带你深入了解如何使用栈来模拟实现队列,让你在解决问题时更加灵活和创新,便于大家更深入的理解栈和队列。


1. 题目:用栈实现队列

 题目描述:

 题目链接:

用栈实现队列icon-default.png?t=N6B9https://leetcode.cn/problems/implement-queue-using-stacks/description/

2. 思路

         这道题目的解题思路于队列实现栈有很大的相似点。这道题也是给了两个栈,要求使用两个栈来实现队列。这里我们可以使用两边倒的方式来模拟实现队列。

        假设入栈:1、2、3、4那么出栈的顺序就是4、3、2、1,如果我们按照出栈的顺序再入栈到另一个栈中(空栈),再次出栈就可以达到队列出队的效果(1、2、3、4)

3. 分析

        根据上述的思路我们就可以利用两个栈模拟实现队列。思路的大概过程:

         那么我们来考虑一下特殊的情况,如果我们入队了1、2、3、4,出队了1和2,然后再入队5和6,这时候我们考虑一下是否还需要倒一次(将剩下的3和4入栈到原栈中,然后入栈5和6,再将3、4、5、6依次出栈,入栈到另外一个栈中)?

        这里其实是不需要在倒一次,入队1、2、3、4。出队1和2,然后再入队5和6,然后再出队,出队的顺序是:1、2、3、4、5、6。我们可以将5和6入栈到原栈中,然后将3和4继续出栈,当一个栈为空时再入栈原栈中的数据。过程如下:

         好的过程分析完之后,我们来对每个接口进行实现。题目中依然是没有现成的栈,所以我们依然需要 “ 造轮子 ” 前边我们已经实现的栈可以复制过来使用。

 3.1 定义 “ 队列 ”

         由于我们再模拟队列时需要用到两个栈,但调用函数时传两个栈又太麻烦,这里我们就使用结构体来定义两个栈(MyQueue),这样传参时就可以直接传结构体(MyQueue)指针就可以了。

typedef struct {
    Stack pushst;
    Stack popst;
} MyQueue;

 3.2 创建队列

         创建队列就非常简单了,我们只需要调用前边实现的InItStack函数将两个栈进行初始化就可以了:

MyQueue* myQueueCreate() {
    MyQueue* obj=(MyQueue*)malloc(sizeof(MyQueue));
    InItStack(&obj->pushst);
    InItStack(&obj->popst);

    return obj;
}

         可能对结构体不熟练的同学会有疑惑:

问题一:

        为什么要malloc一个空间?这里注意:前边我们仅仅只是定义了一个模拟实现的队列,定义的是类型,并没有创建结构体变量,这里malloc也仅仅只是创建一个结构体变量。

 问题二:

        那为什么不直接MyQueue obj;这样定义?这是在函数内部,如果这样创建结构体变量它是创建在栈区,一旦出了函数1就会被销毁,为了后续的传参,所以最好使用malloc在堆区开辟空间。

问题三:

        初始化两个栈时需要取地址,那我们可不可以在定义时直接定义成指针类型例如:

Stack* pushst;
Stack* popst;

         这当然可以,但是如果按照这样的写法,那么在创建 “队列” 时就需要malloc给两个栈开辟空间(在调用的初始化函数中并没有开辟空间给栈)。如果是这样定义:

typedef struct {
    Stack pushst;
    Stack popst;
} MyQueue;

 那么在malloc,obj时就已经将两个栈的空间开辟好了。这样也更简单便捷。

3.3 入队

         入队就很简单了,直接将数据入栈到pushst中。

void myQueuePush(MyQueue* obj, int x) {
    StackPush(&obj->pushst,x);
}

 3.4 队头数据

         这里为什么先写队头数据呢?那是因为出队时不仅需要将队头移除,还需要返回被移除队头的数据。所以这里我们先实现队头数据的接口。

        想要得到队头数据,那就需要将pushst中的元素按照出栈顺序入栈到popst中,然后返回popst这个栈的栈顶元素即可,过程如下:

 

int myQueuePeek(MyQueue* obj) {
    if(IsEmpty(&obj->popst))
    {
        while(!IsEmpty(&obj->pushst))
        {
            StackPush(&obj->popst,TopData(&obj->pushst));
            StackPop(&obj->pushst);
        }
    }
    return TopData(&obj->popst);
}

         这里注意:入栈到popst中的条件是popst为空,这也与上述的分析对应,popst栈为空时才可以继续将pushst中入队元素倒到popst中。

 3.5 出队

        有了队头数据的接口,出队接口的实现就非常简单了,在出队前保存一下队头数据(popst栈顶数据),然后将popst中的栈顶元素出栈,最后返回front即可

int myQueuePop(MyQueue* obj) {
    int front=myQueuePeek(obj);
    StackPop(&obj->popst);

    return front;
}

 3.6 判空和销毁

         判空和销毁的接口也非常简单,当两个栈都为空时就表明队列为空,代码如下:

bool myQueueEmpty(MyQueue* obj) {
    return (IsEmpty(&obj->pushst)&&IsEmpty(&obj->popst));
}

         接下来是销毁,销毁队列前我们需要先将两个栈销毁,最后销毁obj。代码如下:

void myQueueFree(MyQueue* obj) {
    DestoryStack(&obj->popst);
    DestoryStack(&obj->pushst);
    free(obj);
}

4.题解

整体代码如下:

typedef int Datatype;
typedef struct Stack
{
	Datatype* a;
	int top;
	int capacity;
}Stack;

void InItStack(Stack* ps);

void DestoryStack(Stack* ps);

void StackPush(Stack* ps, Datatype x);

void StackPop(Stack* ps);

int Stacksize(Stack* ps);

Datatype TopData(Stack* ps);

bool IsEmpty(Stack* ps);


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

void DestoryStack(Stack* ps)
{
	assert(ps);
	ps->top = ps->capacity = 0;
	free(ps->a);
	ps->a = NULL;
}
void StackPush(Stack* ps, Datatype x)
{
	assert(ps);
	if (ps->top == ps->capacity)
	{
		int newcapacity = (ps->capacity == 0 ? 4 : ps->capacity * 2);
		Datatype* tmp = (Datatype*)realloc(ps->a, sizeof(Datatype) * newcapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity = newcapacity;
	}
	ps->a[ps->top] = x;
	ps->top++;
}
void StackPop(Stack* ps)
{
	assert(ps);
	assert(ps->top > 0);
	ps->top--;
}
int Stacksize(Stack* ps)
{
	assert(ps);
	return ps->top;
}
Datatype TopData(Stack* ps)
{
	assert(ps);
	assert(ps->top > 0);

	return ps->a[ps->top - 1];
}
bool IsEmpty(Stack* ps)
{
	assert(ps);
	return (ps->top == 0);
}


typedef struct {
    Stack pushst;
    Stack popst;
} MyQueue;


MyQueue* myQueueCreate() {
    MyQueue* obj=(MyQueue*)malloc(sizeof(MyQueue));
    InItStack(&obj->pushst);
    InItStack(&obj->popst);

    return obj;
}

void myQueuePush(MyQueue* obj, int x) {
    StackPush(&obj->pushst,x);
}


int myQueuePeek(MyQueue* obj) {
    if(IsEmpty(&obj->popst))
    {
        while(!IsEmpty(&obj->pushst))
        {
            StackPush(&obj->popst,TopData(&obj->pushst));
            StackPop(&obj->pushst);
        }
    }
    return TopData(&obj->popst);
}

int myQueuePop(MyQueue* obj) {
    int front=myQueuePeek(obj);
    StackPop(&obj->popst);

    return front;
}

bool myQueueEmpty(MyQueue* obj) {
    return (IsEmpty(&obj->pushst)&&IsEmpty(&obj->popst));
}

void myQueueFree(MyQueue* obj) {
    DestoryStack(&obj->popst);
    DestoryStack(&obj->pushst);
    free(obj);
}

 

总结

        使用栈模拟实现队列,让我们在实践中深入思考了数据结构的本质和应用,为我们的编程思维和算法设计能力提供了挑战和提升。希望本期内容对你有些许帮助,最后,感谢阅读!

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

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

相关文章

4.时间与窗口

4.1 时间类型 在Flink中定义了3种时间类型: 事件时间(Event Time):事件的发生事件,数据本身自带时间字段。处理时间(Processing Time):计算引擎处理时的系统时间。和摄取时间(Inge…

(el-Form)操作(不使用 ts):Element-plus 中 Form 表单组件校验规则等的使用

Ⅰ、Element-plus 提供的 Form 表单组件与想要目标情况的对比: 1、Element-plus 提供 Form 表单组件情况: 其一、Element-plus 自提供的 Form 代码情况为(示例的代码): // Element-plus 自提供的代码: // 此时是使用了 ts 语言环…

ELK中grok插件、mutate插件、multiline插件、date插件的相关配置

目录 一、grok 正则捕获插件 自定义表达式调用 二、mutate 数据修改插件 示例: ●将字段old_field重命名为new_field ●添加字段 ●将字段删除 ●将filedName1字段数据类型转换成string类型,filedName2字段数据类型转换成float类型 ●将filedNam…

【移动机器人运动规划】04 ——轨迹生成

文章目录 前言相关代码整理: 介绍Minimum Snap OptimizationDifferential Flatness(微分平坦)Minimum-snapSmooth 1D TrajectorySmooth Multi-Segment TrajectoryOptimization-based Trajectory Generation Convex Optimization(凸优化)凸函数和凸集凸优…

List list=new ArrayList()抛出的ArrayIndexOutOfBoundsException异常

1.应用场景,今天生产日志监控到一组new ArrayList() 进行add 异常,具体日志如下: eptionHandler.handler(178): TXXYBUSSINESS|执行异常 java.util.concurrent.CompletionException: java.lang.ArrayIndexOutOfBoundsException: Index 1 out…

SpringBoot禁用Swagger3

Swagger3默认是启用的&#xff0c;即引入包就启用。 <dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter</artifactId><version>3.0.0</version> </dependency> <dependency><groupId…

理解-面向对象

目录 对象&#xff1a; 举例&#xff1a; 封装: 好处: 继承: 多态&#xff1a; 类和对象之间的关系 对象&#xff1a; 把一个东西看成对象&#xff0c;我们就可以孤立的审查它的性质&#xff0c;行为&#xff0c;进而研究它和其他对象的关系。 对象是一个应用系统中用…

Spring5 AOP 默认使用 JDK

这是博主在使用dubbo实现远程过程调用的时候遇到的问题&#xff1a; 我们如果在服务提供者类上加入Transactional事务控制注解后&#xff0c;服务就发布不成功了。原因是事务控制的底层原理是为服务提供者类创建代理对象&#xff0c;而默认情况下Spring是基于JDK动态代理方式创…

ssh-keygen 做好免密登录后不生效

免密说明 通常情况下&#xff0c;我们ssh到其他服务器需要知道服务器的用户名和密码。对于需要经常登录的服务器每次都输入密码比较麻烦&#xff0c;因此我们可以在两台服务器上做免密登录&#xff0c;即在A服务器可以免密登录B服务器。 在A服务器上登录B服务器时&#xff0c;…

数字图像处理 --- 相机的内参与外参(CV学习笔记)

Pinhole Camera Model&#xff08;针孔相机模型&#xff09; 针孔相机是一种没有镜头、只有一个小光圈的简单相机。 光线穿过光圈并在相机的另一侧呈现倒立的图像。为了建模方便&#xff0c;我们可以把物理成像平面(image plane)上的图像移到实际场景(3D object)和焦点(focal p…

Spring-2-透彻理解Spring 注解方式创建Bean--IOC

今日目标 学习使用XML配置第三方Bean 掌握纯注解开发定义Bean对象 掌握纯注解开发IOC模式 1. 第三方资源配置管理 说明&#xff1a;以管理DataSource连接池对象为例讲解第三方资源配置管理 1.1 XML管理Druid连接池(第三方Bean)对象【重点】 数据库准备 -- 创建数据库 create …

Python基础小项目

今天给大家写一期特别基础的Python小项目&#xff0c;欢迎大家支持&#xff0c;并给出自己的完善修改 &#xff08;因为我写的都是很基础的&#xff0c;运行速率不是很好的 目录 1. 地铁票价题目程序源码运行截图 2. 购物车题目程序源码运行截图 3. 名片管理器题目程序源码运行…

opencv实战项目 实现手势跟踪并返回位置信息(封装调用)

OpenCV 是一个基于 Apache2.0 许可&#xff08;开源&#xff09;发行的跨平台计算机视觉和机器学习软件库&#xff0c;可以运行在Linux、Windows、Android和Mac OS操作系统上。 需要提前准备opencv 和 mediapipe库 pip --default-timeout5000 install -i https://pypi.tuna.tsi…

nodejs+vue+elementui社区流浪猫狗救助救援网站_4a4i2

基于此背景&#xff0c;本研究结合管理员即时发布流浪猫狗救助救援信息与用户的需求&#xff0c;设计并实现了流浪猫狗救助救援网站。系统采用B/S架构&#xff0c;java语言作为主要开发语言&#xff0c;MySQL技术创建和管理数据库。系统主要分为管理员和用户两大功能模块。通过…

【Linux取经路】进程的奥秘

文章目录 1、什么是进程&#xff1f;1.1 自己写一个进程 2、操作系统如何管理进程&#xff1f;2.1 描述进程-PCB2.2 组织进程2.3 深入理解进程 3、Linux环境下的进程3.1 task_struct3.2 task_struct内容分类3.3 组织进程3.4 查看进程属性 4、结语 1、什么是进程&#xff1f; 在…

FreeRTOS

FreeRTOS官网&#xff1a;www.freertos.org 调度 实时操作系统 特点&#xff1a;如果有一个任务需要执行&#xff0c;实时操作系统会马上&#xff08;在较短时间内&#xff09;执行该任务&#xff0c;不会有较长的延时。这种特性保证了各个任务的及时执行。 实现方式&#…

web前端之CSS操作

文章目录 一、CSS操作1.1 html元素的style属性1.2 元素节点的style属性1.3 cssText属性 二、事件2.1 事件处理程序2.1.1 html事件2.1.2 DOM0事件&#xff08;适合单个事件&#xff09;2.1.3 DOM2事件&#xff08;适合多个事件&#xff09; 2.2 事件之鼠标事件2.3 事件之Event事…

详解Kafka分区机制原理|Kafka 系列 二

Kafka 系列第二篇&#xff0c;详解分区机制原理。为了不错过更新&#xff0c;请大家将本号“设为星标”。 点击上方“后端开发技术”&#xff0c;选择“设为星标” &#xff0c;优质资源及时送达 上一篇文章介绍了 Kafka 的基本概念和术语&#xff0c;里面有个概念是 分区(Part…

计算机竞赛 opencv python 深度学习垃圾图像分类系统

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; opencv python 深度学习垃圾分类系统 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;3分创新点&#xff1a;4分 这是一个较为新颖的竞…

pytest结合 allure 打标记之的详细使用

前言 前面我们提到使用allure 可以生成漂亮的测试报告&#xff0c;下面就Allure 标记我们做详细介绍。 allure 标记 包含&#xff1a;epic&#xff0c;feature, story, title, testcase, issue, description, step, serverity, link, attachment 常用的标记 allure.feature…