栈和队列OJ题:LeetCode--225.用队列实现栈

news2024/11/17 14:52:46

 朋友们、伙计们,我们又见面了,今天给大家带来的是LeetCode--225.用队列实现栈

数 据 结 构 专 栏:数据结构

个    人   主    页 :stackY、

LeetCode 专  栏 :LeetCode刷题训练营

LeetCode--225.用队列实现栈:https://leetcode.cn/problems/implement-stack-using-queues/

目录

1.题目介绍

2.实例演示

3.解题思路

3.1创建栈

3.2出栈操作

3.3压栈操作

3.4获取栈顶元素

3.5判断栈是否为空

3.6释放栈 

 4.完整代码


1.题目介绍

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。

实现 MyStack 类:

        1. void push(int x) 将元素 x 压入栈顶。
        2. int pop() 移除并返回栈顶元素。
        3. int top() 返回栈顶元素。
        4. boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。

注意:

        1. 你只能使用队列的基本操作 —— 也就是 push to back、peek/pop from front、size 和 is empty 这些操作。
        2. 你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。 

2.实例演示

3.解题思路

3.1创建栈

使用两个队列来实现栈的功能,首先我们得写出一个队列,队列的功能是先进先出,栈的功能是后进先出,在创建栈的时候需要有两个队列,然后为栈创建一块空间,并且将两个队列都进行初始化:

代码演示:

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


MyStack* myStackCreate() {
    //先为栈创建一块空间
    MyStack* obj = (MyStack*)malloc(sizeof(MyStack));
    if(obj == NULL)
    {
        perror("malloc fail");
        return NULL;
    }
    //分别对两个队列进行初始化
    QueueInit(&obj->q1);
    QueueInit(&obj->q2);
    return obj;
}

3.2出栈操作

 题目要求删除之后返回栈顶的元素。

栈的功能是先入后出,然而队列的功能是先入先出,那么我们该怎么操作呢?我们现在有两个队列,出栈是出的最后一个数据(第n个数据),我们可以先将一个队列的前n-1个数据依次插入到另外一个队列中(每插入一个然后再删除一个),这时原来的队列中就剩下最后一个数据,这时再将最后一个数据删除,这样子就达成了出栈时出最后一个数据的操作:我们在这里先假设第一个队列为空,第二个队列不为空,然后进行判断,如果不符合就交换,然后就是导数据的过程,然后就可以进行删除了:

 代码演示:

int myStackPop(MyStack* obj) {
    //假设q1为空
    //q2不为空
    Queue* pEmptyQ = &obj->q1;
    Queue* pNoEmptyQ = &obj->q2;
    //判断是否正确,不正确则交换
    if(!QueueEmpty(&obj->q1))
    {
        pEmptyQ = &obj->q2;
        pNoEmptyQ = &obj->q1;
    }
    //导数据
    //一直取到第Size-1个,这时就剩下的最后一个数据
    while(QueueSize(pNoEmptyQ) > 1)
    {
        //将不为空的队列中的数据插入到为空的队列
        QueuePush(pEmptyQ, QueueFront(pNoEmptyQ));
        QueuePop(pNoEmptyQ);
    }
    //删除最后一个数据
    int top = QueueFront(pNoEmptyQ);
    QueuePop(pNoEmptyQ);
    return top;
}

3.3压栈操作

由于我们是用两个队列来实现栈的功能,所以压栈操作也就是插入数据的操作需要将数据插入到队列中,那么怎么插入呢?对应前面的删除,我们需要将数据插入到不为空的队列中,那么第一次插入的时候两个队列都为空,这时随便插入即可:

代码演示:

void myStackPush(MyStack* obj, int x) {
    //判断是否为空
    if(!QueueEmpty(&obj->q1))
    {
        QueuePush(&obj->q1, x);
    }
    else
    {
        QueuePush(&obj->q2, x);
    }
}

3.4获取栈顶元素

这里的栈顶的元素就表示的是不为空的队列中的队尾的数据,所以只需要将不为空的队列的队尾的数据直接返回:

代码实现:

int myStackTop(MyStack* obj) {
    //q1不为空返回q1的队尾数据
    if(!QueueEmpty(&obj->q1))
    {
        return QueueBack(&obj->q1);
    }
    //q2不为空返回q2的队尾数据
    else
    {
        return QueueBack(&obj->q2);
    }
}

3.5判断栈是否为空

判断栈是否为空就是判断两个队列是否为空:

代码演示:

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

3.6释放栈 

对栈的释放我们先要销毁实现栈的两个队列,然后再将栈空间释放:

代码实现:

void myStackFree(MyStack* obj) {
    //先销毁两个队列
    QueueDestroy(&obj->q1);
    QueueDestroy(&obj->q2);
    //再释放栈空间
    free(obj);
}

 4.完整代码

//链式结构:表示队列
typedef int QDataType;
typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QNode;

//队列的结构
typedef struct Queue
{
	//头指针
	QNode* phead;
	//尾指针
	QNode* ptail;
	//队列中有效元素个数
	int size;
}Queue;


//初始化队列
void QueueInit(Queue* pq);

//销毁队列
void QueueDestroy(Queue* pq);

//队尾入队列
void QueuePush(Queue* pq, QDataType x);

//检测队列是否为空
bool QueueEmpty(Queue* pq);

//对头出队列
void QueuePop(Queue* pq);

//获取队头的元素
QDataType QueueFront(Queue* pq);

//获取队尾的元素
QDataType QueueBack(Queue* pq);

//获取队列有效元素的个数
int QueueSize(Queue* pq);

//初始化队列
void QueueInit(Queue* pq)
{
	assert(pq);

	pq->phead = NULL;
	pq->ptail= NULL;
	pq->size = 0;
}

//销毁队列
void QueueDestroy(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->phead;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}

//队尾入队列
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	
	//创建新的结点
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return;
	}
	newnode->next = NULL;
	newnode->data = x;

	//第一次尾插
	if (pq->ptail == NULL)
	{
		assert(pq->phead == NULL);

		pq->phead = pq->ptail = newnode;
	}
	else
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}
	//有效元素++
	pq->size++;
}

//检测队列是否为空
bool QueueEmpty(Queue* pq)
{
	assert(pq);

	//1.判断头、尾指针
	/*
	return pq->phead == NULL
		&& pq->ptail == NULL;
	*/

	//2.判断有效元素个数
	return pq->size == 0;
}

//队头出队列
void QueuePop(Queue* pq)
{
	assert(pq);
	//判空
	assert(!QueueEmpty(pq));

	//一个结点
	if (pq->phead->next == NULL)
	{
		//直接释放
		free(pq->phead);
		pq->phead = pq->ptail = NULL;
	}
	//多个结点
	else
	{
		//记录头的下一个
		QNode* Next = pq->phead->next;
		//释放
		free(pq->phead);
		//更新头结点
		pq->phead = Next;
	}
	
	pq->size--;
}

//获取队头的元素
QDataType QueueFront(Queue* pq)
{
	assert(pq);
	//先判空
	assert(!QueueEmpty(pq));

	return pq->phead->data;
}

//获取队尾的元素
QDataType QueueBack(Queue* pq)
{
	assert(pq);
	//先判空
	assert(!QueueEmpty(pq));

	return pq->ptail->data;
}

//获取队列有效元素的个数
int QueueSize(Queue* pq)
{
	assert(pq);

	return pq->size;
}


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


MyStack* myStackCreate() {
    //先为栈创建一块空间
    MyStack* obj = (MyStack*)malloc(sizeof(MyStack));
    if(obj == NULL)
    {
        perror("malloc fail");
        return NULL;
    }
    //分别对两个队列进行初始化
    QueueInit(&obj->q1);
    QueueInit(&obj->q2);
    return obj;
}

void myStackPush(MyStack* obj, int x) {
    //判断是否为空
    if(!QueueEmpty(&obj->q1))
    {
        QueuePush(&obj->q1, x);
    }
    else
    {
        QueuePush(&obj->q2, x);
    }
}

int myStackPop(MyStack* obj) {
    //假设q1为空
    //q2不为空
    Queue* pEmptyQ = &obj->q1;
    Queue* pNoEmptyQ = &obj->q2;
    //判断是否正确,不正确则交换
    if(!QueueEmpty(&obj->q1))
    {
        pEmptyQ = &obj->q2;
        pNoEmptyQ = &obj->q1;
    }
    //导数据
    //一直取到第Size-1个,这时就剩下的最后一个数据
    while(QueueSize(pNoEmptyQ) > 1)
    {
        //将不为空的队列中的数据插入到为空的队列
        QueuePush(pEmptyQ, QueueFront(pNoEmptyQ));
        QueuePop(pNoEmptyQ);
    }
    //删除最后一个数据
    int top = QueueFront(pNoEmptyQ);
    QueuePop(pNoEmptyQ);
    return top;
}

int myStackTop(MyStack* obj) {
    //q1不为空返回q1的队尾数据
    if(!QueueEmpty(&obj->q1))
    {
        return QueueBack(&obj->q1);
    }
    //q2不为空返回q2的队尾数据
    else
    {
        return QueueBack(&obj->q2);
    }
}

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

void myStackFree(MyStack* obj) {
    //先销毁两个队列
    QueueDestroy(&obj->q1);
    QueueDestroy(&obj->q2);
    //再释放栈空间
    free(obj);
}

/**
 * Your MyStack struct will be instantiated and called as such:
 * MyStack* obj = myStackCreate();
 * myStackPush(obj, x);
 
 * int param_2 = myStackPop(obj);
 
 * int param_3 = myStackTop(obj);
 
 * bool param_4 = myStackEmpty(obj);
 
 * myStackFree(obj);
*/

今天的博客就分享到这里,喜欢的老铁留下你的三连,感谢感谢!我们下期再见!!

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

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

相关文章

软件测试工程师如何提高自己的竞争力?

案例一来自我们的资深功能测试工程师招聘。当时,有一位拥有近 9 年测试经验的资深测试候选人,我对他的简历还是比较满意的,所以就安排了面谈。但是,在聊的过程中我很快发现,这位候选人绝大多数的测试经验积累都“强”绑…

精彩回顾 | 2022(第二届)超级CSO年度评选颁奖盛典

2023年5月13日,2022(第二届)超级CSO年度评选颁奖盛典在上海举行,来自全国各地近200位来宾、业界专家、企业代表、合作伙伴以及CSO/CISO共同出席。本次盛典得到了包括中国网络安全审查技术与认证中心(CCRC)、…

什么是即时 AI ?有哪些应用场景

什么是即时 AI ? 即时 AI 是全球首款通过自然语言描述,快速生成可编辑的 UI 设计稿的设计工具。 输入文字描述后,即可一次性生成4张 包含矢量图层和图标、支持二次编辑、分层结构清晰 UI 设计稿。 即时 AI 目前已面向全部用户免费开放&#…

无效数据处理攻略: 如何从源头开始预防无效数据带来的风险

数据处理在现代社会中变得越来越重要,而对于数据的可靠性和准确性,我们始终非常关注。然而,即使在对数据进行了精心管理的情况下,无效数据依然可能存在,并可能对数据分析和决策带来不良影响。因此,处理无效…

[Windows驱动开发]-BlackBone实现内存读取的三种方式

文章目录 🛫 导读需求开发环境 升级优化(vs2019)相关地址Blackbone工程中的lib库添加Blackbone工程修改tools工程修改 旧文章整理(vs2017)功能描述内存读取-BlackBone库的集成内存读取-检测参数内存读取-ReadProcessMe…

【 数据处理系统 】(草稿)

文章目录 第3章 总体设计3.1 系统设计目标和原则3.2 系统架构设计3.3 数据采集模块设计3.4 数据预处理模块设计3.4.1 业务数据预处理模块设计3.4.2 日志数据预处理模块设计 3.5 数据存储设计3.6 数据仓库设计3.7 可视化模块设计 第4章 详细设计与实现4.1 数据采集模块4.1.1 数据…

一、11.C内存分配/堆栈

C内存分配/堆栈 01.C内存分配❤️ #include <stdio.h>const int g_A = 10; //常量区 int g_B = 20; //数据段 static<

【小菜鸡刷题记】----双指针篇

【小菜鸡刷题记】----双指针篇 剑指 Offer 18. 删除链表的节点剑指 Offer 22. 链表中倒数第k个节点剑指 Offer 25. 合并两个排序的链表剑指 Offer 52. 两个链表的第一个公共节点剑指 Offer 21. 调整数组顺序使奇数位于偶数前面剑指 Offer 57. 和为s的两个数字剑指 Offer 57 - I…

《斯坦福数据挖掘教程·第三版》读书笔记(英文版) Chapter 6 Frequent Itemsets

来源&#xff1a;《斯坦福数据挖掘教程第三版》对应的公开英文书和PPT Chapter 6 Frequent Itemsets The market-basket model of data is used to describe a common form of many-many relationship between two kinds of objects. On the one hand, we have items, and on…

YOLOv8 独家原创改进:独家首发最新原创EfficiCLNMS改进点,改进有效可以直接当做自己的原创改进点来写,新的增强预测帧

💡该教程为属于《芒果书》📚系列,包含大量的原创首发改进方式, 所有文章都是全网首发原创改进内容🚀 💡本篇文章为YOLOv8改进:独家首发最新EfficiCL-NMS改进点,新的增强预测帧率。 💡对自己数据集改进有效的话,可以直接当做自己的原创改进点来写!!!改进点先到…

小白量化《穿云箭集群量化》(7) 巡航导弹策略

小白量化《穿云箭集群量化》&#xff08;7&#xff09; 巡航导弹策略 量化交易策略比较有名的是网格策略&#xff0c;网格策略的缺点是对网格定义不容易&#xff0c;另外通过网格穿越交易也不是最优价格。 穿云箭量化平台提供了巡航导弹策略&#xff0c;可以利用巡航导弹技术自…

无效数据大揭秘——你不知道的那些坑!

进行数据管理时&#xff0c;无效数据可能会对生产力和决策质量造成严重的影响。如何发现和处理无效数据变得愈发重要。一起来唠唠各位大佬是如何处理的&#xff1f; ⭐ 什么是无效数据&#xff1f;⭐ 如何处理无效数据&#xff1f;⭐ 如何减少无效数据&#xff1f;⭐ 无效数据管…

Python入门(十一)while循环(一)

while循环&#xff08;一&#xff09; 1.简介2.使用while循环3.让用户选择何时退出4.使用标志5.使用break退出循环6.在循环中使用continue7.避免无限循环 作者&#xff1a;xiou 1.简介 for循环用于针对集合中的每个元素都执行一个代码块&#xff0c;而while循环则不断运行&am…

css3:精灵图sprite的使用

文章目录 精灵图sprite简介原理优缺点实例通过精灵图实现一个导航栏 精灵图sprite 简介 CSS精灵技术&#xff08;也称CSS Sprites、CSS雪碧&#xff09;&#xff0c;简单来说就是从一张有各种小图标的大图上截取下来一个小图标来使用。 正因为只要加载一张大图片&#xff0c;…

Restful路径下编写controller层及其增删改查

前置&#xff1a;需要先创建好项目&#xff0c;并且使用mabtis根据数据表生成好代码 mybatis plus自动生成代码&#xff08;代码生成器&#xff09;_wa1ttinG的博客-CSDN博客 一、controller层定义 controller层就是和用户打交道&#xff0c;直接与前端进行交互。可调用service…

安全中级1-nginx_host与php处理不同绕过

一、nginx配置证书 1.生成一个ssl.key密钥 openssl genrsa -des3 -out ssl.key 2096 2.创建一个key的目录,并将ssl.key放入到key目录下 mkdir key mv ssl.key key/ cd key 3.将ssl.key修改为xxx.key mv ssl.key xxx.key 4.创建ssl.key密钥 openssl rsa -in xxx.key -out ssl.…

【计算机组成原理】实验二

文章目录 实验二 运算器实验一、实验目的二、实验原理三、运算器功能编码四、设置初始状态任务一 算术运算任务二 逻辑运算任务三 移位运算任务四 进位控制与零标志 实验二 运算器实验 一、实验目的 完成算术、逻辑、移位运算实验&#xff0c;熟悉ALU运算类型的控制位运用。…

华为OD机试真题 Java 实现【硬件产品销售方案】【2023Q1 200分】

一、题目描述 某公司目前推出了AI开发者套件、AI加速卡、AI加速模块、AI服务器、智能边缘多种硬件产品&#xff0c;每种产品包含若干个型号。 现某合作厂商要采购金额为amount元的硬件产品搭建自己的AI基座。 假设当前库存有N种产品&#xff0c;每种产品的库存量充足&#x…

Python爬虫urllib的基础使用详解

文章目录 1、urllib的使用response 服务器返回的数据&#xff1a;一个类型&#xff0c;六个方法urllib.request.urlretrieve(url,filename) 请求下载网页 请求下载图片 请求下载视频 2、请求对象的定制3.编解码post请求方式ajax的get请求ajax的post请求cookie模拟登录使用handl…