栈和队列oj题——225. 用队列实现栈


**
专栏: 数据结构| Linux|| C语言
路漫漫其修远兮,吾将上下而求索
文章目录
- 题目要求:
- 实现 MyStack 类:
- 注意:
- 示例:
- 解释:
- 提示:
- 解题核心
- 数据结构的定义
- 初始化栈
- 入栈(Push)操作
- 出栈(Pop)操作
- 获取栈顶元素(Top):
- 检查栈是否为空(Empty):
- 销毁栈(Free):
- 以下是队列的实现:
- 以下是本题的实现:
要做题目的点击这里–>栈和队列oj题——225. 用队列实现栈
题目要求:
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。
实现 MyStack 类:
void push(int x) 将元素 x 压入栈顶。
int pop() 移除并返回栈顶元素。
int top() 返回栈顶元素。
boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。
注意:
你只能使用队列的基本操作 —— 也就是 push to back、peek/pop from front、size 和 is empty 这些操作。
你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
示例:
输入:
[“MyStack”, “push”, “push”, “top”, “pop”, “empty”]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 2, 2, false]
解释:
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.top(); // 返回 2
myStack.pop(); // 返回 2
myStack.empty(); // 返回 False
提示:
1 <= x <= 9
最多调用100 次 push、pop、top 和 empty
每次调用 pop 和 top 都保证栈不为空
进阶:你能否仅用一个队列来实现栈。
myStackCreate - 创建栈
解题核心
这个问题的核心思路在于使用两个队列(Queue)来模拟一个栈(Stack)的行为。栈是一种后进先出(LIFO, Last In First Out)的数据结构,而队列是一种先进先出(FIFO, First In First Out)的数据结构。要用队列模拟栈的行为,关键在于如何实现栈的两个主要操作:入栈(push)和出栈(pop)。
数据结构的定义
初始化两个队列,这两个队列将用于模拟栈的行为。
// 定义一个使用两个队列模拟的栈的结构体
typedef struct
{Queue q1; // 第一个队列Queue q2; // 第二个队列
} MyStack;
初始化栈
动态分配内存给新的栈,如果内存分配失败,输出错误信息并退出。
// 创建一个新的栈
MyStack* myStackCreate()
{// 动态分配内存给新栈MyStack* newStack =(MyStack*)malloc(sizeof(MyStack));if (!newStack){perror("malloc fail"); // 如果内存分配失败,输出错误信息并退出exit(-1);}// 初始化两个队列QInit(&(newStack->q1));QInit(&(newStack->q2));return newStack;
}
入栈(Push)操作
在栈中,最新添加的元素总是被存储在栈的顶部。在使用两个队列模拟栈时,入栈操作相对直接:
选择一个非空队列进行操作:如果两个队列都是空的,可以选择任意一个队列进行操作。如果有一个非空队列,总是将新元素入队到这个非空队列。
// 将一个元素推入栈中
void myStackPush(MyStack* obj, int x)
{assert(obj); // 确保栈对象非空// 总是将元素推入非空队列中if(!QueueEmpty(&obj->q1)){QPush(&obj->q1, x);}else{QPush(&obj->q2, x);}
}
出栈(Pop)操作
确定非空队列和空队列:首先识别出哪个队列是非空的(存有栈元素的队列),哪个队列是空的。
// 从栈中弹出一个元素
int myStackPop(MyStack* obj)
{ assert(obj); // 确保栈对象非空Queue* empty = &obj->q1; // 一个指向可能为空的队列的指针Queue* noEmpty = &obj->q2; // 一个指向非空队列的指针// 确定哪个队列是空的,哪个是非空的if(!QueueEmpty(empty)){empty = &obj->q2;noEmpty = &obj->q1;}// 将元素从非空队列转移到空队列,直到只剩下一个元素while(QueueSize(noEmpty) > 1){QPush(empty, QueueFront(noEmpty));QPop(noEmpty);}// 弹出并返回最后一个元素int top = QueueFront(noEmpty);QPop(noEmpty);return top;
}
获取栈顶元素(Top):
栈顶元素对应于最后进入非空队列的元素。可以通过查看非空队列的尾部元素来得知栈顶元素。
// 获取栈顶元素
int myStackTop(MyStack* obj)
{assert(obj); // 确保栈对象非空// 返回非空队列的尾部元素(栈顶元素)if(!QueueEmpty(&obj->q1)){return QueueBack(&obj->q1);}else{return QueueBack(&obj->q2);}
}
检查栈是否为空(Empty):
如果两个队列都为空,那么栈为空。
// 检查栈是否为空
bool myStackEmpty(MyStack* obj)
{ assert(obj); // 确保栈对象非空// 如果两个队列都为空,栈为空return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}
销毁栈(Free):
释放栈所使用的资源,包括两个队列和栈本身的内存。
// 释放栈所占用的资源
void myStackFree(MyStack* obj)
{assert(obj); // 确保栈对象非空// 销毁两个队列QDestroy(&obj->q1);QDestroy(&obj->q2);// 释放栈对象所占用的内存free(obj);
}
以下是队列的实现:
typedef int QDataType; // 定义队列数据类型为int// 队列节点的结构体定义
typedef struct QueueNode
{QDataType val; // 节点存储的数据struct QueueNode* next; // 指向下一个节点的指针
} QNode;// 队列的结构体定义
typedef struct Queue
{QNode* phead; // 指向队列头部的指针QNode* ptail; // 指向队列尾部的指针int size; // 队列的大小
} Queue;// 函数声明
void QInit(Queue* pq); // 初始化队列
void QDestroy(Queue* pq); // 销毁队列void QPush(Queue* pq, QDataType x); // 向队列中添加元素
void QPop(Queue* pq); // 从队列中移除元素QDataType QueueFront(Queue* pq); // 获取队列头部元素
QDataType QueueBack(Queue* pq); // 获取队列尾部元素bool QueueEmpty(Queue* pq); // 检查队列是否为空
int QueueSize(Queue* pq); // 获取队列的大小// 初始化队列
void QInit(Queue* pq)
{assert(pq); // 断言队列指针非空pq->phead = pq->ptail = NULL; // 将头指针和尾指针都设为NULLpq->size = 0; // 将队列大小设置为0
}// 销毁队列
void QDestroy(Queue* pq)
{assert(pq); // 断言队列指针非空QNode* cur = pq->phead;while (cur){QNode* next = cur->next; // 保存下一个节点free(cur); // 释放当前节点cur = next; // 移动到下一个节点}pq->phead = NULL; // 将头指针设为NULLpq->ptail = NULL; // 将尾指针设为NULLpq->size = 0; // 将队列大小设置为0
}// 向队列中添加元素
void QPush(Queue* pq, QDataType x)
{assert(pq); // 断言队列指针非空QNode* newNode = (QNode*)malloc(sizeof(QNode)); // 分配新节点内存if (newNode == NULL){perror("malloc fail"); // 内存分配失败处理exit(-1);}newNode->val = x; // 设置新节点的值newNode->next = NULL; // 新节点的下一个节点为NULLif (pq->ptail == NULL) // 如果队列为空{pq->phead = pq->ptail = newNode; // 队列头尾都指向新节点}else{pq->ptail->next = newNode; // 将新节点接到队列尾部pq->ptail = newNode; // 更新尾指针}pq->size++; // 队列大小增加
}// 从队列中移除元素
void QPop(Queue* pq)
{assert(pq); // 断言队列指针非空assert(pq->phead); // 断言队列不为空QNode* Del = pq->phead; // 保存要删除的节点pq->phead = pq->phead->next; // 更新头指针free(Del); // 释放节点内存if (pq->phead == NULL) // 如果队列变空{pq->ptail = NULL; // 更新尾指针}pq->size--; // 队列大小减少
}// 获取队列头部元素的值
QDataType QueueFront(Queue* pq)
{assert(pq); // 断言队列指针非空assert(pq->phead); // 断言队列不为空return pq->phead->val; // 返回头部元素的值
}// 获取队列尾部元素的值
QDataType QueueBack(Queue* pq)
{assert(pq); // 断言队列指针非空assert(pq->ptail); // 断言队列不为空return pq->ptail->val; // 返回尾部元素的值
}// 检查队列是否为空
bool QueueEmpty(Queue* pq)
{assert(pq); // 断言队列指针非空return pq->phead == NULL; // 如果头指针为NULL,则队列为空
}// 获取队列的大小
int QueueSize(Queue* pq)
{return pq->size; // 返回队列的大小
}
以下是本题的实现:
// 定义一个使用两个队列模拟的栈的结构体
typedef struct
{Queue q1; // 第一个队列Queue q2; // 第二个队列
} MyStack;// 创建一个新的栈
MyStack* myStackCreate()
{// 动态分配内存给新栈MyStack* newStack =(MyStack*)malloc(sizeof(MyStack));if (!newStack){perror("malloc fail"); // 如果内存分配失败,输出错误信息并退出exit(-1);}// 初始化两个队列QInit(&(newStack->q1));QInit(&(newStack->q2));return newStack;
}// 将一个元素推入栈中
void myStackPush(MyStack* obj, int x)
{assert(obj); // 确保栈对象非空// 总是将元素推入非空队列中if(!QueueEmpty(&obj->q1)){QPush(&obj->q1, x);}else{QPush(&obj->q2, x);}
}// 从栈中弹出一个元素
int myStackPop(MyStack* obj)
{ assert(obj); // 确保栈对象非空Queue* empty = &obj->q1; // 一个指向可能为空的队列的指针Queue* noEmpty = &obj->q2; // 一个指向非空队列的指针// 确定哪个队列是空的,哪个是非空的if(!QueueEmpty(empty)){empty = &obj->q2;noEmpty = &obj->q1;}// 将元素从非空队列转移到空队列,直到只剩下一个元素while(QueueSize(noEmpty) > 1){QPush(empty, QueueFront(noEmpty));QPop(noEmpty);}// 弹出并返回最后一个元素int top = QueueFront(noEmpty);QPop(noEmpty);return top;
}// 获取栈顶元素
int myStackTop(MyStack* obj)
{assert(obj); // 确保栈对象非空// 返回非空队列的尾部元素(栈顶元素)if(!QueueEmpty(&obj->q1)){return QueueBack(&obj->q1);}else{return QueueBack(&obj->q2);}
}// 检查栈是否为空
bool myStackEmpty(MyStack* obj)
{ assert(obj); // 确保栈对象非空// 如果两个队列都为空,栈为空return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}// 释放栈所占用的资源
void myStackFree(MyStack* obj)
{assert(obj); // 确保栈对象非空// 销毁两个队列QDestroy(&obj->q1);QDestroy(&obj->q2);// 释放栈对象所占用的内存free(obj);
}
相关文章:
栈和队列oj题——225. 用队列实现栈
** 个人主页:晓风飞 专栏: 数据结构| Linux|| C语言 路漫漫其修远兮,吾将上下而求索 文章目录 题目要求:实现 MyStack 类:注意:示例:解释:提示: 解题核心数据结构的定义初…...
集合的三种遍历方式
迭代器(Iterator) 概述:Iterator 是个接口,迭代器是集合的专用遍历方式 使用方法,我们想要使用迭代器,必须首先得到集合对象,通过集合对象生成迭代器对象,才能进行集合的遍历 常用…...
Mysql 中的常用命令
在数字化世界中,数据库已经成为数据存储和处理的核心。而MySQL,作为最受欢迎的关系型数据库管理系统之一,其强大的功能和易用性使它成为开发者和企业的首选。掌握MySQL中的常用命令,是每一位数据库管理员和开发者的基本要求。本篇…...
【Java】CompletableFuture使用方法
背景 CompletableFuture是Java 8中引入的一个类,它实现了Future和CompletionStage接口,用于表示异步计算的结果。使用CompletableFuture可以方便地编写异步编程的代码,并且可以链式地组合多个异步操作。 接口 CompletableFuture实现了Future…...
摆烂式学习ssh
摆烂式学习ssh ssh工作原理ssh基本使用sshd配置文件密钥登录1.客户端2.服务器3.注意事项4.使用密钥登录测试 ssh高级使用技巧1.在非正规端口启动2.rsync 命令3.透过 ssh 通道加密原本无加密的服务4.以ssh信道配合x server 传递图形接口5.ssh配合virtualbox虚拟机使用技巧 ssh工…...
用 Python 抓取 bilibili 弹幕并分析!
01 实现思路 首先,利用哔哩哔哩的弹幕接口,把数据保存到本地。接着,对数据进行分词。最后,做了评论的可视化。 02 弹幕数据 平常我们在看视频时,弹幕是出现在视频上的。实际上在网页中,弹幕是被隐藏在源代码…...
目标检测YOLO实战应用案例100讲-基于红外图像处理的无人机光伏组件故障检测(续)
目录 3.2 自适应温度阈值故障检测算法设计 3.3 基于拟合灰度曲线的故障检测方案设计...
go mod 命令详解
文章目录 1.关于模块2.关于 go mod3.格式4.示例参考文献 1.关于模块 模块(Modules)是 Go 1.11 版本引入的一依赖管理机制。 一个模块是 Go packages 的集合,定义在项目根目录下的 go.mod 文件。go.mod 文件定义了模块的路径,这也…...
花了一小时,拿python手搓了一个考研背单词软件
听说没有好用的电脑端背单词软件?只好麻烦一下,花了一小时,拿python手搓了一个考研背单词软件。 代码已经开源在我的github上,欢迎大家STAR! 其中,数据是存放在sqlite中,形近词跳转是根据jaro …...
一篇文章学会Vim
一篇文章学会Vim 声明:以下内容均为我个人的理解,如果发现错误或者疑问可以联系我共同探讨 简介 Vim是一个高度可定制的终端文本编辑器,它可以很方便的创建和修改任何类型的文本。作为vi的升级版,有许多新的特性(以下列出的特性…...
面试算法91:粉刷房子
题目 一排n幢房子要粉刷成红色、绿色和蓝色,不同房子被粉刷成不同颜色的成本不同。用一个n3的数组表示n幢房子分别用3种颜色粉刷的成本。要求任意相邻的两幢房子的颜色都不一样,请计算粉刷这n幢房子的最少成本。例如,粉刷3幢房子的成本分别为…...
js逆向第11例:猿人学第4题雪碧图、样式干扰
任务4:采集这5页的全部数字,计算加和并提交结果 打开控制台查看请求地址https://match.yuanrenxue.cn/api/match/4,返回的是一段html网页代码 复制出来格式化后,查看具体内容如下: <td><img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAA…...
OpenEular23.09(欧拉)操作系统为企业搭建独立的K8S集群环境,详细流程+截图
一.环境; win10,vmware16 pro,openeular23.09,linux内核 6.4.0-10.1.0.20.oe2309.x86_64, docker-engine 2:18.09.0-328,kubernetes 1.25.3,containerd 1.6.22,calico v3.25 集群…...
学生成绩管理系统半成品
C语言的老师在给我们讲指针的时候,讲的并不深入,她用了一个学生成绩管理系统来引入指针这个东西并给我们讲解,但我觉得她的管理系统功能有一些不足,并且不是很美观,所以说心血来潮,自己也动手写了一个学生成…...
国家信息安全水平等级考试NISP二级题目卷⑤(包含答案)
国家信息安全水平等级考试NISP二级题目卷(五) 国家信息安全水平等级考试NISP二级题目卷(五)需要报考咨询可以私信博主! 前言: 国家信息安全水平考试(NISP)二级,被称为校园版”CISP”,由中国信息…...
4.快速实现增删改查,模糊查询功能
打开springboot项目,在com.example下建包common,在common下新建Result.java 4.1封装统一的返回数据结构 1.在Result.java中编写如下代码: private static final String *SUCCESS*"0"; private static final String *ERROR*"-1"; p…...
【Redux】自己动手实现redux和react-redux
1. React提供context的作用 在class组件的世界里,如果后代组件共享某些状态,比如主题色、语言键,则需要将这些状态提升到根组件,以props的方式从根组件向后代组件一层一层传递,这样则需要在每层写props.someData&#…...
代码随想录算法训练营day6|242.有效的字母异位词、349.两个数组的交集、202.快乐数
哈希表理论基础 建议:大家要了解哈希表的内部实现原理,哈希函数,哈希碰撞,以及常见哈希表的区别,数组,set 和map。 什么时候想到用哈希法,当我们遇到了要快速判断一个元素是否出现集合里的时…...
2024.1.4每日一题
LeetCode每日一题 2397.被列覆盖的最多行数 2397. 被列覆盖的最多行数 - 力扣(LeetCode) 题目描述 给你一个下标从 0 开始、大小为 m x n 的二进制矩阵 matrix ;另给你一个整数 numSelect,表示你必须从 matrix 中选择的 不同 …...
C++协程和线程的区别?详细介绍一下C++协程
C协程和线程的区别 线程是操作系统级别的资源,由操作系统负责调度和切换,每个线程都有自己的堆栈和执行上下文。线程之间的切换需要保存和恢复线程的执行上下文,这个过程有一定的开销。协程是用户态的轻量级线程,协程的调度完全由…...
wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...
UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...
selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...
tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...
AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...
