队列实现栈———栈实现队列

两个队列实现栈

. - 力扣(LeetCode)

如何用两个队列实现栈的操作呢?

弹出

我们知道栈的特点是后进先出,而队列的特点是先进先出。如何用两个队列实现数据的先进后出。首先我们先抽象一个一个栈用来思考我们该怎么实现

我们先假设栈中插入了五个数据,五个数据都放在队列 q1 中。

当我们要 pop 数据时,由于栈是后进先出的,所以删除的数据是 5 ,而5在队列中又是后插入的,这时候我们就要想办法让 5 到 q1 的队头去,好像除了把前面的四个数据挪到 q2 中也没其他的办法了。于是我们重复取 q1 对头数据尾插到 q2 中,直到 q1 只剩一个数据,

这时候 q1 中 5 就在队头了,我们取出 q1 队头数据,然后 q1 pop,返回5就完成了,但是如果这时候又要删除一个数据该怎么办?

这次我们要弹出的就是 4 了,这时候思路就和上面一样了,先把前三个数据都挪到 q1 中,然后4就到了队头,这时候就可以 pop 掉4了。

这时候我们就能知道如何用队列实现栈的弹出操作了,首先我们一定要有一个空的队列,数据只保存在一个队列中,然后要弹出栈顶元素的时候,就把前面的数据都挪到空队列中,剩下一个数据弹出就行了。这里的关键就是要有一个空队列。

插入

插入数据我们就不用挪动数据了,我们直接插入到有数据的队列的队尾,不要去动空队列,这样才能保证删除数据有地方可以挪,同时也不会改变数据的先后顺序。

这两个关键操作的思路有了之后,我们就能试着实现一下了。

定义和初始化

首先我们要把之前实现的队列的代码复制粘贴到oj中, 定义栈我们直接用两个队列来定义,定义的时候要思考一下用队列还是用队列的指针,由于之前我们实现的队列的接口都是用的队列的指针作为参数,所以我们直接用队列指针。在初始化的函数中,由于他是要返回这个栈的指针的,所以我们要用malloc来定义,而不能定义局部变量,同时在初始化的时候q1和q2也要malloc出来。


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


MyStack* myStackCreate() {
    MyStack*obj=(MyStack*)malloc(sizeof(MyStack));
    if(obj==NULL)
    {
        perror("malloc fail");
        exit(-1);
    }
    obj->q1=(Queue*)malloc(sizeof(Queue));
    obj->q2=(Queue*)malloc(sizeof(Queue));
    QueueInit(obj->q1);
    QueueInit(obj->q2);

    return obj;
}

插入

插入函数我们前面分析了要找空的队列插入,如果两个队列都是空队列的话,就随便找一个都行。

void myStackPush(MyStack* obj, int x) {
    if(QueueEmpty(obj->q2))//q2为空push到q1
    {
        QueuePush(obj->q1,x);
    }
    else
    {
        QueuePush(obj->q2,x);
    }
}

删除

删除操作我们首先要找到空队列和有数据的队列是哪一个,如何挪动数据直到只剩一个,然后返回并删除,同时要注意断言两个队列不能同时为空.

int myStackPop(MyStack* obj) {
    Queue*empty=obj->q1;
    Queue*nonempty=obj->q2;
    if(QueueEmpty(obj->q2))
    {
        empty=obj->q2;
        nonempty=obj->q1;
    }
    while(QueueSize(nonempty)>1)
    {
        int tmp=QueueFront(nonempty);
        QueuePop(nonempty);
        QueuePush(empty,tmp);
    }
    int ret=QueueFront(nonempty);
    QueuePop(nonempty);
    return ret;

}

取栈顶元素

取栈顶元素我们就找到存数据的队列,取队尾数据并返回。


int myStackTop(MyStack* obj) {
    if(QueueEmpty(obj->q1))
    {
        return QueueBack(obj->q2);
    }
    return QueueBack(obj->q1);
}

判空

 如果两个队列都为空就返回真,否则返回假.

bool myStackEmpty(MyStack* obj) {
    return QueueEmpty(obj->q1)&&QueueEmpty(obj->q2);
}

销毁

销毁我们首先要调用接口销毁两个队列,如何释放q1和q2,最后释放 obj

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

两个栈实现队列

. - 力扣(LeetCode)

实现思路

我们上面用队列实现栈的思路也可以用来参考这个题目。

删除

首先假设我们的队列里插入了1,2,3,4。我们先把这四个数据压栈在一个栈中。

这时候当我们想要 pop 一个数据是该怎么做呢?第一步肯定还是挪动数据,假设我们把前3个数据都挪到 s2 中,这时候s1中就只剩下 1 了,这时候对 s1 pop就能实现队列的删除了

但是我们如果又要删除一个数据呢,这次要删除的应该是 2  ,我们还需要挪动数据吗?好像并不需要挪动数据了,而且我们上一步甚至都不用把 1 留在 s1 ,我们可以把 1 也挪到 s2 中,而把s1变成一个空的栈,

这样我们队列每次pop的时候就直接 pop s2的栈顶元素就行了。为什么呢,我们前面用栈实现队列的时候每次都要倒数据,这是因为队列转移数据时是不会改变数据的顺序的,他是先进先出,反过来说先进到q1的数据必然会先进到q2 .而栈则不一样,栈是先进后出的,意思就是我们将数据从s1全部挪到s2时,数据的顺序就反过来了,这时候这个栈的出栈顺序 就是队列的删除顺序了。

什么时候又要开始挪数据,就是当 s2 为空的时候,如果又要删除的话,我们就会把新插入到 s1 的数据有全部挪到s2中。

插入

上面的删除操作好像都是在一个栈里完成的,当我们删除一个元素的时候,数据就已经全部挪到s2中了,这时候如果要插入数据,是插入到s1还是s2中呢,显而易见不能插入到s2中,所以我们把数据插入到s1中,连续插入会有影响吗? 肯定是不会的。

这时候插入到s1中时,就相当于我们一开始假设的情况了,当s2数据被删完了,如果还要删除数据,这时候就又会把s1的数据全部挪到 s2 中

取队头

队头数据就是即将要被删除的元素,所以很简单我们直接取s2的栈顶元素就行了,如果s2为空,我们就要先把s1的数据全部挪到s2之后取s2的栈顶元素。

取队尾

队尾的元素就是最新插入的元素,当然取s1的栈顶元素,如果s1为空呢?s1为空就把s2的数据又全部挪到s1中,这时候顺序又回到了插入的顺序,s1的栈顶就是最新插入的元素也就是队尾元素。

这时候我们就知道了该如何实现了,首先两个栈一个专门用来插入数据,一个专门用来删除数据,当操作某一个栈时栈为空,就需要挪动数据,所以我们可以专门写一个函数来实现两个栈的数据挪动。

定义和初始化

首先把之前实现的栈的代码复制粘贴到oj中,定义和初始化的代码很简单

typedef struct {
    Stack spush;
    Stack spop;
} MyQueue;


MyQueue* myQueueCreate() {
    MyQueue* obj=(MyQueue*)malloc(sizeof(MyQueue));
    STInit(&obj->spush);
    STInit(&obj->spop);
    return obj;
}


插入

我们前面分析了只要是插入操作就对spush栈插入。那么我们直接调用实现的栈的接口就行了

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

挪动栈的数据

 这个函数就跟前面我们实现的交换队列一样,只是队列只要挪动n-1个数据,而这里要全部挪过去

//挪动两个栈的元素
void SwapStack(ST* src,ST* dest)
{
    assert(!StackEmpty(src)||!StackEmpty(dest));
    while(StackSize(src))
    {
        int tmp=StackTop(src);
        StackPush(dest,tmp);
        StackPop(src);
    }
}

删除

删除操作是对spop进行操作的,所以首先我们要对spop判空,如果为空就要调用挪动函数把spush的数据挪到spop中再删除

int myQueuePop(MyQueue* obj) {
    if(StackEmpty(obj->spop))  
    {
        SwapStack(&obj->spush,&obj->spop);
    }
    int ret=StackTop(&obj->spop);
    StackPop(&obj->spop);
    return ret;
}

取队头数据

取队头数据要取spop的栈顶元素,所以首先也是要对spop判空,如果为空也是要挪动数据的,函数与删除的函数基本一样,但是不用弹出栈顶元素。

int myQueuePeek(MyQueue* obj) {
    if(StackEmpty(obj->spop))  
    {
        SwapStack(&obj->spush,&obj->spop);
    }
    int ret=StackTop(&obj->spop);
    return ret;
}

取队尾数据

队尾数据即最新插入的元素,就是spush的栈顶元素,如果s1为空,就要先把s2的数据挪到s1中再取s1的栈顶元素。但是这里的oj没有要我们实现这个接口。

队列判空

只有两个栈同时为空队列才是空。

bool myQueueEmpty(MyQueue* obj) {
    return StackEmpty(&obj->spush)&&StackEmpty(&obj->spop);
}

释放内存

释放内存我们首先要释放两个栈的内存,调用接口就行,释放完两个栈之后再free掉obj。

void myQueueFree(MyQueue* obj) {
    STDestroy(&obj->spush);
    STDestroy(&obj->spop);
    free(obj);
}

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

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

相关文章

代码随想录阅读笔记-二叉树【总结】

二叉树的理论基础 代码随想录 (programmercarl.com):二叉树的种类、存储方式、遍历方式、定义方式 二叉树的遍历方式 深度优先遍历 代码随想录阅读笔记-二叉树【递归遍历】-CSDN博客:递归三部曲初次亮相代码随想录阅读笔记-二叉树【迭代遍历】-CSDN博…

编写Markdown时如何爽爽地渲染树?

在使用VitePress/Dumi等静态网站生成时,一般均支持直接在Markdown中渲染显示Vue/React组件,这给个网站非常丰富极致的表现力,我们在创建静态网站时开心的使用各种Vue/React组件,但是在输出树结构时,实际场景中存在几个…

李沐25_使用块的网络VGG——自学笔记

VGG架构 1.多个VGG块后接全连接层 2.不同次数的重复块得到不同的架构 VGG-16、VGG-19 3.更大更深的AlexNet ##经典卷积神经网络的基本组成部分是下面的这个序列: 1.带填充以保持分辨率的卷积层; 2.非线性激活函数,如ReLU; …

【规划算法】A星 与 混合A星

理解概念: A星寻路算法详解(C实现 完整代码图片演示 )_a星算法-CSDN博客 A*算法图解_a*算法流程图-CSDN博客 A星(A*、A Star)路径规划算法详解(附MATLAB代码)_a星算法路径规划-CSDN博客 改进A*算法dwa 本文提出了一种改进的A*…

Tmux 使用笔记

Tmux 是一个终端复用器(terminal multiplexer),非常有用,属于常用的开发工具。 本文记录个人使用 Tmux的命令。 1. tmux简介 命令行的典型使用方式是,打开一个终端窗口,连接计算机,在里面输入…

【刷题】备战蓝桥杯 — dfs 算法

送给大家一句话: 风度真美! 即使流泪,也要鼓掌, 即使失望,也要满怀希望。 ——刘宝增 dfs 算法 1 前言2 洛谷 P1030 [NOIP2001 普及组] 求先序排列题目描述算法思路 3 洛谷 P1294 高手去散步题目描述算法思路 4 蓝桥…

1.2.4 采用Java配置类管理Bean

本实战将演示如何使用Java配置类管理Bean,实现基于注解的IoC容器的配置。 创建新包 在net.huawei.spring根包里创建day04子包。 创建杀龙任务类 在day04子包里创建SlayDragonQuest类。在该类上不添加Component注解。 创建勇敢骑士类 在day04子包里创建BraveKnight…

HarmonyOS开发实例:【分布式数据管理】

介绍 本示例展示了在eTS中分布式数据管理的使用,包括KVManager对象实例的创建和KVStore数据流转的使用。 通过设备管理接口[ohos.distributedDeviceManager],实现设备之间的kvStore对象的数据传输交互,该对象拥有以下能力 ; 1、注册和解除注…

大话设计模式——17.状态模式(State Pattern)

简介 对象的行为依赖于它的状态(属性),可以根据状态的改变而改变相关行为。 UML图: 应用场景: 对象的行为取决于其状态,并且必须要在运行时刻根据状态而改变行为代码中包含大量与对象状态有关的条件语句 …

SMT用料全检抽检

下载地址百度网盘: https://pan.baidu.com/s/1kDn_l8P6ReC4Lj5tgt-v4w?pwd5y41 提取码:5y41 1、扫描输入车间线体 2、根据线体获取在线订单 3、选择(全检|抽检|换接新料)开始 4、根据提示扫描站位和料号核对 5、核对成功再扫描核对下一组

<-泛型->

1.泛型的概念 所谓泛型,就是允许在定义类, 接口 时通过一个"标识"表示类中某个属性的类型或者某个方法的返回值或形参类型.这个类型参数将在使用时确定. 2.举例 (1). 集合类在设计阶段/声明阶段不能确定这个容器到底存的是什么对象,所以在JDK…

✌2024/4/3—力扣—整数反转

代码实现: int reverse(int x) {long num 0;while (x ! 0) {num num * 10 x % 10;x x / 10;}if ((int)num ! num) {return 0;}return (int)num; }

第十四届蓝桥杯大赛软件赛省赛C/C++大学 B 组

第十四届蓝桥杯大赛软件赛省赛C/C大学 B 组 文章目录 第十四届蓝桥杯大赛软件赛省赛C/C大学 B 组1、日期统计2、01串的熵3、冶炼金属4、飞机降落5、接龙数列6、岛屿个数7、子串简写8、整数删除9、景区导游10、砍树 1、日期统计 分析: 本题的意思就是2023年一整年&a…

Docker容器嵌入式开发:在Ubuntu上配置Postman和flatpak

在 Ubuntu 上配置 Postman 可以通过 Snap 命令完成,以下是所有命令的总结: sudo snap install postmansudo snap install flatpak在 Ubuntu 上配置 Postman 和 Flatpak 非常简单。以下是一些简单的步骤: 配置 Flatpak 安装 Flatpak&#x…

unity 寻找隐藏节点 transform.find

由于习惯了godot 的路径寻找,学习unity的时候一直在找类似的方式。最终发现transform.find最相似。 但在寻找隐藏(inactive)的节点遇到了坑。 其实transform.find能不能找到隐藏节点是基于你在find中使用的是绝对路径还是相对路径。 绝对路…

【LAMMPS学习】八、基础知识(1.7) LAMMPS 与 MDI 库代码耦合

8. 基础知识 此部分描述了如何使用 LAMMPS 为用户和开发人员执行各种任务。术语表页面还列出了 MD 术语,以及相应 LAMMPS 手册页的链接。 LAMMPS 源代码分发的 examples 目录中包含的示例输入脚本以及示例脚本页面上突出显示的示例输入脚本还展示了如何设置和运行各…

数据结构和算法:回溯

回溯算法 回溯算法(backtracking algorithm)是一种通过穷举来解决问题的方法,它的核心思想是从一个初始状态出发,暴力搜索所有可能的解决方案,当遇到正确的解则将其记录,直到找到解或者尝试了所有可能的选…

招聘小程序里可以展示详细的岗位信息,方便用户自行报名,省时省力

平台目前规定要通过招聘小程序进行报白。报白通过后就可以在直播间正常招聘了,但是必须挂载小程序,否则还是容易被警告限流。 招聘小程序里可以展示详细的岗位信息,方便用户自行报名,省时省力。 抖音直播招聘报白是一种通过直播…

Day36代码随想录(1刷) 贪心

738. 单调递增的数字 当且仅当每个相邻位数上的数字 x 和 y 满足 x < y 时&#xff0c;我们称这个整数是单调递增的。 给定一个整数 n &#xff0c;返回 小于或等于 n 的最大数字&#xff0c;且数字呈 单调递增 。 示例 1: 输入: n 10 输出: 9示例 2: 输入: n 1234 输出: …

IPEX-LLM(原名BigDL-LLM)环境配置

IPEX-LLM 是一个为Intel XPU (包括CPU和GPU) 打造的轻量级大语言模型加速库&#xff0c;在Intel平台上具有广泛的模型支持、最低的延迟和最小的内存占用。 您可以使用 IPEX-LLM 运行任何 PyTorch 模型&#xff08;例如 HuggingFace transformers 模型&#xff09;。在运行过程中…