具备教学意义的实操(用队列实现栈)

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

实现逻辑

一个是先进先出(队列),一个是后进先出(栈)

这里用两个队列导入·一下数据

出来数据之后入数据

代码的实现

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int QDataType;
// 链式结构:表示队列 
typedef struct QListNode
{QDataType _data;struct QListNode* _next;
}QNode;
// 队列的结构 (因为队列是先进先出,后进后出,也就是和栈是相反的,此时会尾进头出,所以我们需要更新尾部和头部节点)
// (把头结点,尾结点,链表的实际的大小放里面,这样不需要每次使用的时候进行循环找尾,我们只需要每次更新尾结点就可以)
typedef struct Queue
{QNode* _phead;//头节点QNode* _ptail;//尾结点int size;
}Queue;
// 这里采取一级指针进行实现代码逻辑,如果不创建队列的结构,我们就需要采取二级指针
// 初始化队列 
void QueueInit(Queue* ps);
// 销毁队列 
void QueueDestroy(Queue* ps);
// 队尾入队列 
void QueuePush(Queue* ps, QDataType data);
// 队头出队列 
void QueuePop(Queue* ps);
// 获取队列头部元素 
QDataType QueueFront(Queue* ps);
// 获取队列队尾元素 
QDataType QueueBack(Queue* ps);
// 获取队列中有效元素个数 
int QueueSize(Queue* ps);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* ps);// 初始化队列 
void QueueInit(Queue* ps)
{ps->_phead = NULL;ps->_ptail = NULL;ps->size = 0;
}
// 销毁队列 
void QueueDestroy(Queue* ps)
{assert(ps);QNode* cur = ps->_phead;while (cur){//存下下一个节点的地址,不会出现找空的情况QNode* next = cur->_next;free(cur);cur =next;}
}
// 队尾入队列 
void QueuePush(Queue* ps, QDataType x)
{QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("QueuePush:newnode:error:");exit(1);}//把需要插入的数值插入到节点里面newnode->_next = NULL;newnode->_data = x;// ps->_phead == ps->_ptail 的结果确实是 true,这表明队列中只有一个元素(头尾相接)。// 但是,通常情况下,我们不会使用 ps->_phead == ps->_ptail // 来检查队列中是否只有一个元素。相反,我们通常会使用 ps->size == 1 或者 ps->_phead != NULL && ps->_ptail != NULL // 来检查队列中是否只有一个元素。//插入节点 第一个节点,这里的判断是不能写成ps->_phead ==ps->_ptail;因为都是空指针不能进行比较//ps->_phead == NULLif (ps->size == 0){ps->_phead = ps->_ptail = newnode;}else{//尾插节点ps->_ptail->_next = newnode;ps->_ptail= newnode;}ps->size++;
}
// 队头出队列 
void QueuePop(Queue* ps)
{assert(ps && ps->size);// 改变头结点ps->_phead = ps->_phead->_next;ps->size--;
}
// 获取队列头部元素 
QDataType QueueFront(Queue* ps)
{assert(ps && ps->size);return ps->_phead->_data;
}
// 获取队列队尾元素 
QDataType QueueBack(Queue* ps)
{assert(ps && ps->size);return ps->_ptail->_data;
}
// 获取队列中有效元素个数 
int QueueSize(Queue* ps)
{return ps->size;
}
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* ps)
{assert(ps);return ps->size == 0;
}//匿名结构体(我们需要两个队列,所以采取结构体嵌套的形式解决问题)
typedef struct 
{Queue Q1;Queue Q2;
} MyStack;//初始化(关键在于,初始化的数值出去之后就销毁,所以我们需要创建节点进行初始化)
MyStack* myStackCreate() 
{MyStack* obj = (MyStack*)malloc(sizeof(MyStack));if(obj == NULL){perror("obj:error:");exit(1);}QueueInit(&(obj->Q1));QueueInit(&(obj->Q2));return obj;
}
//入栈 
void myStackPush(MyStack* obj, int x) 
{if(QueueEmpty(&(obj->Q1)))//q1为空{QueuePush(&(obj->Q2), x);}else{QueuePush(&(obj->Q1), x);}
}//删除栈顶元素(核心逻辑)
int myStackPop(MyStack* obj) 
{//判空(假设法假设q1为空)MyStack* Empty = &(obj->Q1);MyStack* noEmpty = &(obj->Q2);if(QueueEmpty(&(obj->Q2)))//如果q1不为空,q2为空,此时颠倒一下{Empty = &(obj->Q2);noEmpty = &(obj->Q1);}//循环导入while(QueueSize(noEmpty) > 1)//这里的关键点是你不知道谁是空,不是空{QueuePush(Empty, QueueFront(noEmpty));//这里 是把不空的数值头部元素,循环导入到空的数值里面去QueuePop(noEmpty);//并且进行出栈操作}//结束之后留下了一个,我们保存下来返回这个节点,并且最后进行删除int ret = QueueFront(noEmpty);QueuePop(noEmpty);return ret;
}//取出栈顶元素
int myStackTop(MyStack* obj) 
{if(QueueEmpty(&(obj->Q1)))//q1为空{return QueueBack(&(obj->Q2));}else{return QueueBack(&(obj->Q1));}
}
//判空
bool myStackEmpty(MyStack* obj) 
{//q1 q2都为空的时候才为空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);
*/

这段代码使用两个队列 Q1Q2 来实现一个栈 MyStack。下面是对每个部分的详细解释:

  1. 数据结构定义

    • QDataType:定义了队列中存储的数据类型,这里使用 int
    • QNode:定义了队列中的节点,包含数据 _data 和指向下一个节点的指针 _next
    • Queue:定义了队列结构,包含指向队列头部和尾部的指针 _phead 和 _ptail,以及记录队列大小的 size
  2. 队列操作函数

    • QueueInit:初始化队列,将头尾指针设置为 NULL,大小设置为0。
    • QueueDestroy:释放队列中所有节点的内存。
    • QueuePush:在队列尾部添加一个新节点。
    • QueuePop:移除队列头部的节点,并减少队列大小。
    • QueueFront:返回队列头部的元素。
    • QueueBack:返回队列尾部的元素。
    • QueueSize:返回队列中元素的数量。
    • QueueEmpty:检查队列是否为空。
  3. 栈操作函数

    • myStackCreate:创建一个新的 MyStack 实例,初始化两个队列 Q1 和 Q2
    • myStackPush:如果 Q1 为空,则将新元素推入 Q2;否则推入 Q1
    • myStackPop:如果 Q2 不为空且 Q1 为空,则交换两个队列的角色。然后,将 Q2 中的元素逐个移动到 Q1,除了最后一个元素。最后,返回并移除 Q2 中的最后一个元素。
    • myStackTop:返回栈顶元素。如果 Q1 不为空,返回 Q1 的尾部元素;否则返回 Q2 的尾部元素。
    • myStackEmpty:如果两个队列都为空,则返回 true,表示栈为空。
    • myStackFree:销毁 MyStack 实例,释放所有相关联的内存。
  4. 使用队列实现栈的逻辑

    • 通过两个队列 Q1 和 Q2 的交替使用,实现了栈的后进先出(LIFO)特性。当一个队列为空时,可以将另一个队列中的元素移动过来,最后一个元素就是栈顶元素。
    • myStackPush 函数根据 Q1 是否为空来决定将新元素推入哪个队列,这样做的目的是保持两个队列中的元素数量大致相等,从而在 myStackPop 操作中能够高效地将元素从一个队列移动到另一个队列。
  5. 注意事项

    • 在 myStackPop 和 myStackTop 函数中,需要检查两个队列的状态,以确定当前栈顶元素所在的队列。
    • myStackDestroy 函数中,确保先销毁队列,再释放 MyStack 实例的内存。

这种使用两个队列实现栈的方法利用了队列的先进先出特性来模拟栈的后进先出特性。这种方法的好处是可以在 O(1) 时间内完成栈的基本操作,同时避免了使用数组实现栈时可能需要的数组扩展和收缩操作。

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

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

相关文章

实体同城商家短视频获客,3天直播课,玩转实体商家私域,引爆门店增长

课程内容&#xff1a; 实体同城3天直播课【资料】 实体商家获客第一天 .mp4 实体商家获客第二天上.mp4 实体商家获客第二天,mp4 实体商家获客第三天.mp4 实体商家获客第4天.mp4 网盘自动获取 链接&#xff1a;https://pan.baidu.com/s/1lpzKPim76qettahxvxtjaQ?pwd0b8x…

什么是翘尾因素

在有关CPI 的分析文章和新闻稿件中&#xff0c;经常会出现“翘尾因素”或“翘尾影响” 等词汇&#xff0c;这是分析同比价格指数变动幅度时所特有的概念。那么什么是“翘尾因素” 或“翘尾影响”呢&#xff1f; 一、什么是翘尾因素 “翘尾因素”是指上年价格上涨&#xff08;…

瀚高数据库(HighGoDB)Windows安装使用

1.下载 2.安装 瀚高数据库下载与安装&#xff08;Windows版&#xff09;-CSDN博客 3.连接工具 4.建库、建表操作 瀚高数据库管理工具-CSDN博客 *报错Cant access non-default database&#xff0c;需要右键数据库-设为活动对象 5.导入外部数据&#xff08;迁移、对比&…

栈实现队列

一、分析 栈的特点是先出再入&#xff0c;而队列的特点为先入先出&#xff0c;所以我们创造两个栈&#xff0c;一个用来存放数据&#xff0c;一个用来实现其它功能此时栈顶为队尾&#xff1b;当要找队头数据时将前n-1个数据移入到另一个栈中&#xff0c;此时剩余那个数据为队头…

新时代背景下的班子建设挑战与对策

一、引言 随着新时代的到来&#xff0c;社会、经济和科技的飞速发展给组织班子建设带来了前所未有的挑战。如何在这一背景下建设一支高效、协作、创新的领导班子&#xff0c;已成为组织发展的核心议题。本文将从挑战与对策两个维度&#xff0c;深入剖析新时代背景下的班子建设…

Coursera吴恩达深度学习专项课程01: Neural Networks and Deep Learning 学习笔记 Week 02

Week 02 of Neural Networks and Deep Learning Course Certificate 本文是学习 https://www.coursera.org/learn/neural-networks-deep-learning 这门课的笔记 Course Intro 文章目录 Week 02 of Neural Networks and Deep LearningLearning Objectives [1] Logistic Regres…

小程序地理位置接口申请教程来啦4步学会

小程序地理位置接口有什么功能&#xff1f; 如果我们提审后驳回理由写了“当前提审小程序代码包中地理位置相关接口( chooseAddress、getLocation )暂未开通&#xff0c;建议完成接口开通后或移除接口相关内容后再进行后续版本提审”&#xff0c;如果你也碰到类似问题&#xff…

汇昌联信科技:拼多多可以做无货源吗?

在探讨电商平台的经营模式时&#xff0c;"无货源"这一概念经常被提及。它指的是卖家在不需要事先囤积大量商品的情况下&#xff0c;通过与供应商的合作&#xff0c;直接将订单信息传递给他们&#xff0c;由供应商完成发货的过程。针对“拼多多可以做无货源吗?”这一…

028.实现 strStr()

题意 给你两个字符串 haystack 和 needle &#xff0c;请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标&#xff08;下标从 0 开始&#xff09;。如果 needle 不是 haystack 的一部分&#xff0c;则返回 -1 。 难度 简单 示例 例 1 输入&#xff1a;hays…

2023版brupsuite专业破解安装

安装教程&#xff0c;分两部分&#xff1a; 1、安装java环境、参考链接JAVA安装配置----最详细的教程&#xff08;测试木头人&#xff09;_java安装教程详细-CSDN博客 2、安装2023.4版本brupsuite&#xff1a;参考链接 2023最新版—Brup_Suite安装配置----最详细的教程&…

语音网关有哪些?

语音网关是一种网络设备&#xff0c;它使得通过传统的电话网络&#xff08;如公共交换电话网络&#xff0c;PSTN&#xff09;和现代的数据网络&#xff08;如互联网或私有数据网络&#xff09;进行的语音通信成为可能。语音网关的主要作用是在模拟或数字电话信号与数据网络的数…

算法学习笔记(2)-前缀和

##前缀和 指的是某序列的前n项和&#xff0c;在数学上我们可以理解称为数列的前n项和。前缀和是一种预处理&#xff0c;用于降低查询的时间复杂度。 ##一维前缀和 有一个一维数组x和该数组的前缀和数组y&#xff0c;则x和y具有以下关系&#xff1a; #python代码示例 #关系&am…