【数据结构】栈和队列-相互实现OJ题

news2024/11/17 19:45:48

前言:

本题目是关于栈和队列的OJ题目,需对栈和队列有一定了解再进行做题,若不了解可以根据我之前这篇文章进行学习:【数据结构】栈和队列-CSDN博客,题中需要的栈和队列的实现也在该文章中有源代码

目录

前言:

一.用队列实现栈

1.解题思路

2.解题代码

二.用栈实现队列

1.解题思路

2.解题代码

法一:

法二:


一.用队列实现栈

225. 用队列实现栈 - 力扣(LeetCode)

1.解题思路

栈和队列区别在于出数据时的不同,栈遵循“后入先出”,而队列遵循“先入先出”,但在入数据时并没有不同,因此在Push时只需要依照队列的Push即可,将数据进入一个队列。

而在出数据时就不能直接出该队列的数据了,因为此处是模拟栈,需要移除的是队列中的最后一位(最晚进)的数据,而队列只能对队首的数据进行出操作,那么此时第二个队列(此时为空)就有用处了,将第一个队列(有数据的队列)的队首数据插入到第二个队列中,再进行出队,直到第一个队列仅剩最后一个数据(这个数据就是出栈操作要移除的数据),移除该数据不进行插入到第二个队列,如此第一个队列为空,第二个队列就是进行出栈操作后的结果了。

下图大致能演示这个模拟出栈的过程

2.解题代码

队列的实现前言中有,这里不贴出来浪费篇幅了。明白了上图所示的思路,那么整道题就好解决了。关键在于将两个队列分为空队列和非空队列,入栈时与入队操作相同,直接对非空队列(都为空则默认一个)入队即可,出栈时进行两队列的数据交换,其余函数根据两队列性质来即可。

typedef struct {
  Queue q1;
  Queue q2;  
} MyStack;

//初始化
MyStack* myStackCreate() {
    MyStack* s = (MyStack*)malloc(sizeof(MyStack));
    QueueInit(&(s->q1));
    QueueInit(&(s->q2));
    return s;
}

//判断非空与否的条件就是两个队列是否都为空
bool myStackEmpty(MyStack* obj) {
    return QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2);
}

//入栈,与入队是相同的操作,只需要向非空的队列入队即可
void myStackPush(MyStack* obj, int x) {
    if(QueueEmpty(&obj->q1))
    {
        QueuePush(&obj->q2,x);
    }
    else
    {
        QueuePush(&obj->q1,x);
    }

}

//出栈,找到非空队列和空队列进行转换
//注:返回值int是栈顶数据,也就是非空队列的队尾数据(移动后最后一个数据,同时也是队首)
int myStackPop(MyStack* obj) {
    //找到空队列和非空队列
    Queue* empty = &(obj->q1);
    Queue* notempty = &(obj->q2);
    if(QueueEmpty(&obj->q2))
    {
        empty = &obj->q2;
        notempty = &obj->q1;
    }
    while(QueueSize(notempty)>1)
    {
        QueuePush(empty,QueueFront(notempty));
        QueuePop(notempty);
    }
    int ret = QueueFront(notempty);
    QueuePop(notempty);
    return ret;
}

//栈顶数据就是非空队列的队尾数据
int myStackTop(MyStack* obj) {
    if(QueueEmpty(&obj->q1))
    {
        return QueueBack(&obj->q2);
    }
    else
    {
        return QueueBack(&obj->q1);
    }
}

void myStackFree(MyStack* obj) {
    QueueDestroy(&obj->q1);
    QueueDestroy(&obj->q2);
    free(obj);
}

 

二.用栈实现队列

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

1.解题思路

与上道题同理,这次只是反了过来,用栈来实现队列,思路完全可以照搬,区别只在于用出栈模拟出队,不过有一点有差异,取出的栈顶元素(如图中4)插入到Stack2中顺序是相反的,因此需要来转换一下,这里我利用了数组下标进行转化的方法,具体实现方法在下文的方法一中。

 

不过这种方法比较麻烦,也不美观,破坏了封装性,不推荐。在这里给出另一个更为巧妙的方法,直接将两个Stack分为Pushst(插入)和Popst(删除)两个栈,分别对应插入删除,同样能实现。在需要 删除时将Pushst中的数据倒如Popst中即可。巧妙的点在于倒数据的过程中,恰巧使得顺序颠倒,而出栈正好就满足了出队的要求,就如下图所示,具体代码在下方法二。

2.解题代码

法一:

本方法与前一题的方法如出一辙,思路简单,但不推荐。

typedef struct {
    ST s1;
    ST s2;
} MyQueue;


//初始化
MyQueue* myQueueCreate() {
    MyQueue* q = (MyQueue*)malloc(sizeof(MyQueue));
    STInit(&q->s1);
    STInit(&q->s2);
    return q;
}

//对非空栈进行入栈
void myQueuePush(MyQueue* obj, int x) {
    if(STEmpty(&obj->s1))
    {
        STPush(&obj->s2,x);
    }
    else
    {
        STPush(&obj->s1,x);
    }
}

//出栈
int myQueuePop(MyQueue* obj) {
    //找出非空栈和空栈
    ST* empty = &obj->s1;
    ST* notempty = &obj->s2;
    if(STEmpty(&obj->s2))
    {
        empty = &obj->s2;
        notempty = &obj->s1;
    }

    //注意此处要用size保存,否则在后续循环内STPop时top变化会导致错误
    int size = notempty->top;
    //移入空栈(顺序是正确的)
    for(int i = 1;i<size;i++)
    {
        STPush(empty,notempty->a[i]);
    }
   
    //得到返回的数据,并将原非空栈Pop为空
    int ret = notempty->a[0];
    for(int i = 0;i<size;i++)
    {
        STPop(notempty);
    }
    return ret;
}

int myQueuePeek(MyQueue* obj) {
    if(STEmpty(&obj->s1))
    {
        return obj->s2.a[0];
    }
    else
    {
        return obj->s1.a[0];
    }
}

bool myQueueEmpty(MyQueue* obj) {
    return STEmpty(&obj->s1) && STEmpty(&obj->s2);
}

void myQueueFree(MyQueue* obj) {
    STDestroy(&obj->s1);
    STDestroy(&obj->s2);
}

法二:

推荐该方法,更为巧妙简单。

typedef struct {
    ST Pushst;
    ST Popst;
} MyQueue;


MyQueue* myQueueCreate() {
    MyQueue* q = (MyQueue*)malloc(sizeof(MyQueue));
    STInit(&q->Pushst);
    STInit(&q->Popst);
    return q;
}

//插入直接向Pushst插入即可
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);
}

//需要取得队首,使用peek既可以倒数据,又能得到队首数据,一举两得
int myQueuePop(MyQueue* obj) {
    int ret = myQueuePeek(obj);
    STPop(&obj->Popst);
    return ret;
}

bool myQueueEmpty(MyQueue* obj) {
    return STEmpty(&obj->Pushst) && STEmpty(&obj->Popst);
}

void myQueueFree(MyQueue* obj) {
    STDestroy(&obj->Pushst);
    STDestroy(&obj->Popst);
}

两种方法均能通过该题的全部样例。 

 

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

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

相关文章

转运机器人帮助物流行业实现无人化运输,自动分拣

在物流行业日新月异的今天&#xff0c;智能化、无人化已成为大势所趋。富唯智能转运机器人凭借其卓越的性能和广泛的应用场景&#xff0c;正引领着物流行业的新一轮变革。 1、高效转运&#xff0c;轻松应对 富唯智能转运机器人&#xff0c;拥有高达1000kg的负载能力&#xff…

django学习入门系列之第三点《BootSrap初了解》

文章目录 初识BootStrap往期回顾 初识BootStrap BootSrap是什么&#xff1f; 是别人帮我们已写好的CSS样式&#xff0c;我们如果想要使用这个BootSrap&#xff1a; 下载BootStrap使用 在页面上引入BootStrap编写HTML时&#xff0c;按照BootStrap的规定来编写 自定制 官网&…

GoogleAI大动作:发布Gemma 2,开启新篇章

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

window上部署sql server改动端口、和sqlserver的一些还原、批量插入存储过程的命令

1.端口的查看和启动 --windows上安装上sql server数据库后&#xff0c;搜索界面搜索sql&#xff0c;会出现配置管理器&#xff0c;点击进入 --进入后再次选择配置管理器 2. sqlserver数据库还原图形化 sqlserver还原数据库时会使数据库进入一个restore的还原状态&#xff0c;…

20240701在飞凌的OK3588-C开发板的Android12系统下使用i2cdetect确认I2C总线

console:/ # i2cdetect -y -r 0 console:/ # i2cdetect -l console:/ # i2cdetect -F 0 20240701在飞凌的OK3588-C开发板的Android12系统下使用i2cdetect确认I2C总线 2024/7/1 11:30 在CAM1、CAM2挂载OV13850。 在CAM3、CAM4和CAM5挂载OV5645了。 console:/ # i2 i2cdetect i2…

超声波气象站的科技创新

在现代科技的快速发展下&#xff0c;气象监测设备也在不断革新&#xff0c;其中超声波气象站以其独特的优势&#xff0c;成为了气象监测领域的新宠。这款体积小巧、重量轻盈的气象站&#xff0c;凭借其高精度、高稳定性和长寿命&#xff0c;为气象数据的采集提供了强有力的支持…

JMeter--定时执行的方法

原文网址&#xff1a;JMeter--定时执行的方法_IT利刃出鞘的博客-CSDN博客 简介 本文介绍JMeter如何使用定时器定时执行测试任务。 Java技术星球&#xff1a;way2j.com 方法 第一步&#xff1a;新建定时器 右键测试任务> Add > Timer> Constant Timer 如下图所示…

Android平台崩溃和 ANR 问题进行符号化解析、解析崩溃日志的内存地址

使用Android Logcat Stacktrace Utility | Android Logcat | 1.2.3 1.设置so库路径 2.打开Stacktrace Utility工具 3.在Original粘贴报错内存地址 4.点击Resolve Stacktraces,就会解析出内存地址 如果是红色,解析失败了,缺少原生so库,可以在第一步添加so库文件再次尝试…

2-22 基于matlab的NSGA-2求解多目标柔性车间调度算法

基于matlab的NSGA-2求解多目标柔性车间调度算法,计算最大完工时间、计算总延期时长、计算调度方案的总能耗、计算设备总负荷。输出四项结果&#xff0c;多次运行可寻找最佳的调度计划。程序已调通&#xff0c;可直接运行。 2-22 NSGA-2求解多目标柔性车间调度算法 - 小红书 (xi…

python sklearn机械学习模型-分类

&#x1f308;所属专栏&#xff1a;【机械学习】✨作者主页&#xff1a; Mr.Zwq✔️个人简介&#xff1a;一个正在努力学技术的Python领域创作者&#xff0c;擅长爬虫&#xff0c;逆向&#xff0c;全栈方向&#xff0c;专注基础和实战分享&#xff0c;欢迎咨询&#xff01; 您…

常用的限流算法有哪些?你听说过几种?

限流&#xff0c;就是指限制流量请求的频次。 在高并发情况下&#xff0c;它是一种保护系统的策略&#xff0c;避免了在流量高峰时系统崩溃&#xff0c;造成系统的不可用。 常见的限流算法有&#xff1a; 计数器限流算法滑动窗口限流算法漏桶限流算法令牌桶限流算法 1. 计数器…

LeetCode题练习与总结:二叉树的前序遍历--144

一、题目描述 给你二叉树的根节点 root &#xff0c;返回它节点值的 前序 遍历。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,2,3]示例 2&#xff1a; 输入&#xff1a;root [] 输出&#xff1a;[]示例 3&#xff1a; 输入&#xff1a;roo…

ARM功耗管理软件之DVFSAVS

安全之安全(security)博客目录导读 思考&#xff1a;功耗管理软件栈及示例&#xff1f;WFI&WFE&#xff1f;时钟&电源树&#xff1f;DVFS&AVS&#xff1f; 目录 一、ARM功耗管理软件之DVFS 二、ARM功耗管理软件之AVS 一、ARM功耗管理软件之DVFS 有一个实现特定…

招生报名系统教培招生小程序

招生报名系统&#xff1a;轻松实现教培招生新高度 &#x1f680; 招生报名系统&#xff0c;开启智慧教育新时代 在当今数字化快速发展的时代&#xff0c;教育行业也迎来了变革的浪潮。招生报名系统作为这一变革的先锋&#xff0c;为教育机构提供了全新的招生渠道和管理方式。通…

jmeter-beanshell学习1-vars使用获取变量和设置变量

最近又开始了用jmeter做自动化&#xff0c;不管怎么实现&#xff0c;都逃离不了用beanshell&#xff0c;最后把所有校验都放在了beanshell判断&#xff0c;效果还不错。 首先jmeter有很多beanshell相关的元件&#xff0c;取样器、前置处理器、后置处理器、断言&#xff0c;暂时…

传输距离3000M|低延迟|48K采样音频传输模块-SA356大功率发射模块

无线音频应用中&#xff0c;远距离音频传输在许多领域具有广泛的应用需求&#xff0c;例如大型会议系统、公共广播、户外活动和音乐演出等。为了满足这些需求&#xff0c;音频传输模块需要具备一些关键特性&#xff0c;包括长距离传输能力、高音质、低延迟、稳定性以及抗干扰能…

UE5 动画蓝图

文章目录 一、State Machines二、Blend Spaces三、Aim Offset四、Montage 初步介绍 Unreal Engine 5 Tutorial - Animation Blueprint Part 1: State Machines (youtube.com) Unreal Engine 5 Tutorial - Animation Blueprint Part 2: Blend Spaces (youtube.com) Unreal Engi…

RK3568平台(USB篇)TYPE-C接口与PD协议

一.TYPE-C接口简介 type-c 插座&#xff1a; type-c 插头&#xff1a; type-c 线缆&#xff1a; type-c 接口定义之插座&#xff1a; type-c 硬件原理图&#xff1a; VBUS&#xff1a;供电引脚&#xff0c;用于传输电源电压&#xff0c;一般为5V或12V。 GND&#xff1a;地引…

类与对象(3)

1.首先我们先介绍一下 赋值重载 我们来举个例子来实现一下 赋值重载也叫赋值拷贝 void operator(const Date& d){//赋值拷贝 是拷贝给一个已经赋值好的对象 也叫赋值重载cout << "赋值重载" << endl;year d.year;month d.month;day d.day;} 如果…

Linux 高级编程——线程控制

线程控制&#xff1a;互斥与同步 概念&#xff1a; 互斥 》在多线程中对临界资源的排他性访问。 互斥机制 》互斥锁 》保证临界资源的 访问控制。 pthread_mutex_t mutex; 互斥锁类型 互斥锁变量 内核对象 框架&#xff1a; 定义互斥锁 》初始化锁 》加…