用队列实现栈oj题——225

在这里插入图片描述在这里插入图片描述

.

个人主页:晓风飞
专栏:LeetCode刷题|数据结构|Linux
路漫漫其修远兮,吾将上下而求索


文章目录

  • 题目要求:
    • 实现 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);
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

进阶学习——Linux系统安全及应用

目录 一、系统安全加固 1.账号安全基本措施 1.1系统账号清理 1.1.1延伸 1.2密码安全控制 1.3命令历史限制 1.4终端自动注销 二、使用su命令切换用户 1.用途及用法 2.密码验证 3.限制使用su命令的用户 4.查看su操作记录 5.sudo&#xff08;superuse do&#xff09;…

How can I be sure that I am pulling a trusted image from docker?

1、Error response from daemon: manifest for jenkins:latest not found: manifest unknown: manifest unknown 2、Error response from daemon: pull access denied for nacos, repository does not exist or may require ‘docker login’: denied: requested access to th…

并发(3)

目录 11.Synchronized本质上是通过什么保证线程安全的&#xff1f; 12.Synchronized使得同时只有一个线程可以执行&#xff0c;性能比较差&#xff0c;有什么提升的方法&#xff1f; 13.Synchronized由什么样的缺陷&#xff1f;Java Lock是怎么弥补这些缺陷的&#xff1f; 1…

攀登者1 - 华为OD统一考试

OD统一考试 分值: 100分 题解: Java / Python / C++ 题目描述 攀登者喜欢寻找各种地图,并且尝试攀登到最高的山峰。 地图表示为一维数组,数组的索引代表水平位置,数组的元素代表相对海拔高度。其中数组元素0代表地面。 例如:[0,1,2,4,3,1,0,0,1,2,3,1,2,1,0],代表如下…

静态网页设计——中医中药网(HTML+CSS+JavaScript)(dw、sublime Text、webstorm、HBuilder X)

前言 声明&#xff1a;该文章只是做技术分享&#xff0c;若侵权请联系我删除。&#xff01;&#xff01; 感谢大佬的视频&#xff1a;https://www.bilibili.com/video/BV11e411i7g8/?vd_source5f425e0074a7f92921f53ab87712357b 源码&#xff1a;https://space.bilibili.com…

浏览器的渲染流程

✨专栏介绍 在当今数字化时代&#xff0c;Web应用程序已经成为了人们生活和工作中不可或缺的一部分。而要构建出令人印象深刻且功能强大的Web应用程序&#xff0c;就需要掌握一系列前端技术。前端技术涵盖了HTML、CSS和JavaScript等核心技术&#xff0c;以及各种框架、库和工具…

如何使用 CMake 来构建一个共享库(动态库)

tutorial_4/CMakeLists.txt # 声明要求的 cmake 最低版本 cmake_minimum_required( VERSION 2.8 )# 声明一个 cmake 工程 project( HelloSLAM )add_subdirectory(src)tutorial_4/src/CMakeLists.txt #工程添加多个特定的头文件搜索路径 include_directories(include)set(LIBR…

Linux基础知识总结

目录 一、Linux权限设置 更改文件属性 chgrp - 更改文件属组 chown - 更改文件所有者&#xff0c;也可以同时更改文件所属组。 chmod - 更改文件属性 二、Linux文件与目录管理 处理目录的常用命令 ls&#xff08;list files&#xff09;- 列出目录及文件名 cd&#xff…

记.backward()报错

最近我在模型训练损失里加入了LPIPS深度感知损失&#xff0c;训练的时候就出现了如上的报错&#xff0c;具体解释为&#xff1a;调用梯度反向传播loss.backward()时&#xff0c;我们计算梯度&#xff0c;需要一个标量的loss(即该loss张量的维度为1,只包含一个元素&#xff09;&…

【北邮国院大四上】Business Technology Strategy 企业技术战略

北邮国院电商大四在读&#xff0c;本笔记仅为PPT内容的整理与翻译&#xff0c;并不代表本课程的考纲及重点&#xff0c;仅为本人复习时方便阅读与思考之作。 写在前面 大家好&#xff0c;欢迎来到大学期间的最后一门课程&#xff0c;本门课程是中方课&#xff0c;所以很庆幸的…

数据库原理与应用期末复习试卷1

数据库原理与应用期末复习试卷1 一.单项选择题 数据库系统是采用了数据库技术的计算机系统&#xff0c;由系统数据库&#xff0c;数据库管理系统&#xff0c;应用系统和&#xff08;C&#xff09;组成。 ​ A.系统分析员 B.程序员 C.数据库管理员 D.操作员 数据库系统的体系…

Mybatis实现增删改查的两种方式-配置文件/注解

环境准备 1.数据库表tb_brand -- 删除tb_brand表 drop table if exists tb_brand; -- 创建tb_brand表 create table tb_brand(-- id 主键id int primary key auto_increment,-- 品牌名称brand_name varchar(20),-- 企业名称company_name varchar(20),-- 排序字段ordered int…