Leetcode225. 用队列实现栈

news2024/10/3 4:38:39

文章目录

  • 1.题目描述
  • 2.原题链接
  • 3.思路分析
  • 4.代码实现

1.题目描述

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

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

2.原题链接

Leetcode225. 用队列实现栈

3.思路分析

1 . 这道题利用队列先进先出的特性来实现栈 ,使用用两个队列
2. 保证一个队列为空 ,另一个队列存放size个数据 ,
如何实现栈的Pop?
将有数据的队列中的size-1个数据放进另一个空队列 ,然后将剩下的数据Pop,那就有一个问题,如何判断哪个队列为空?
定义两个变量 , emptyQ (空队列 ) , nonemptyQ( 不是空队列) 。假设q1 为空队列, q2 不为空队列 ( q1 ,q2 为两个队列 )。如果q1为空队列, q2 不为空队列,则假设成功 , 如果q1不为空队列, q2 为空队列,则假设失败 ,就将q2变为空队列 , q1 变为非空队列
如何实现栈的Push ?
如果 有队列不为空 ,就往该队列插入数据 , 哪个队列不为空 ,就往哪个队列插入
如何实现栈的Empty ?
两个队列为空即栈为空

4.代码实现

这道题使用的结构体比较多 ,我们画图辅助理解相应的细节 : 图中的QNode* head 、QNodetail , 分别对应下面代码中的 Queue head 、Queue* tail

在这里插入图片描述

typedef int   QueueNodeTypeData;

typedef struct  QueueNode
{
	struct  QueueNode* next;
	QueueNodeTypeData data;
}QueueNodeType;

typedef struct Queue
{
	QueueNodeType * tail; // 队尾
	QueueNodeType * head; //队头
	int size; 
} Queue;  // 链式结构:表示队列


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

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

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

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

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

bool QueueEmpty(Queue* pq); // 判断队列是否为空 

QueueNodeTypeData QueueFront(Queue * pq); //获取队列头部元素

QueueNodeTypeData QueueBack(Queue * pq); //获取队列尾部元素


void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = pq->tail = NULL;
	pq->size = 0;
}

void QueueDestory(Queue* pq) //队列的销毁
{
	assert(pq);
	QueueNodeType * cur = pq->head;
	
	//遍历 
	while (cur)
	{
		QueueNodeType* next = cur->next;  //保存下一个节点的地址
		free(cur); //释放当前节点
		cur = next; 
	}
	  pq->tail = pq->head = NULL;
	pq->size = 0;
}
void QueuePush(Queue* pq, QueueNodeTypeData x) // 入队 
{
	assert(pq);
	QueueNodeType* newnode =(QueueNodeType*) malloc( sizeof(QueueNodeType) );
	if (newnode == NULL)
	{
		printf(" malloc fail");
		exit(-1);
	}
	newnode->data = x;
	newnode->next = NULL;
	//扩容成功

	//第一次入队
	if ( pq->head == NULL)
	{
   		assert(pq->tail == NULL);   //pq->head ==NULL , pq->tail != NULL ,就是出问题了
		pq->tail = pq->head = newnode;
	}
	else //非第一次入队
	{
		pq->tail->next = newnode; // 类似尾插
		pq->tail = newnode; // 更新tail 指针
	}
	pq->size++;
}
void QueuePop(Queue* pq) //队头出队列
{
	assert(pq);
	assert(pq->head != NULL); 

	//只有一个节点

	if (pq->head->next == NULL) 
	{
		free(pq->tail);  //出队
		pq->tail = pq->head = NULL;
	}
	// 多个节点
	else
	{
		QueueNodeType* next = pq->head->next; // 保存下一个节点的地址 
		free(pq->head); // 出队
		pq->head = NULL;
		pq->head = next;  //更新pq->head ,往后走 
	}
	pq->size--;
}


int QueueSize(Queue* pq)//获取队列中有效元素个数
{
	assert(pq);
	
	return pq->size;
}


bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return  pq->head == NULL ;
}

QueueNodeTypeData QueueFront(Queue* pq) //获取队列头部元素
{
	assert(pq);
	assert(!QueueEmpty(pq)); //防止队列为空
	
	return pq->head->data;

}

QueueNodeTypeData QueueBack(Queue* pq) //获取队列尾部元素
{
	assert(pq);
	assert(!QueueEmpty(pq)); //防止队列为空

	return pq->tail->data;
}









typedef struct
 {
   Queue q1 ;
   Queue q2 ;



} MyStack;


MyStack* myStackCreate() 
{
   MyStack * pst = (MyStack *)malloc ( sizeof( MyStack));      
   if( pst == NULL)
   {
     perror( "malloc fail");
     return NULL ;
   } 
    //初始化两个队列 
    QueueInit(&pst->q1);
    QueueInit(&pst->q2);
  return pst ;
}

void myStackPush(MyStack* obj, int x) 
{
    //q1 不为空 ,插入数据 
    if( !QueueEmpty(&obj->q1))
    {
      QueuePush( &obj->q1 ,x);
    }
    else //q2 不为空 ,插入数据 
    {
         QueuePush( &obj->q2 ,x);
    }
}

int myStackPop(MyStack* obj) 
{
       //假设q1 不为空队列 ,q2 为空队列 
   MyStack* empty = &obj->q2;
   MyStack* nonempty = &obj->q1;

   if( !QueueEmpty(&obj->q2))  // q2 不为空队列 ,q1 为空队列 ,假设失败,重新假设即可 
   {
      empty = &obj->q1 ;
      nonempty = &obj->q2 ;
   }

    //将有数据的队列中的size-1个数据放进另一个空队列  
    while ( QueueSize(nonempty)>1)
    {
          QueuePush( empty , QueueFront(nonempty));
           QueuePop(nonempty);
    }   
   //Pop将剩下的一个数据
   int top  = QueueBack(nonempty);
  QueuePop(nonempty);
  return top ;
   

}

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

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

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

在这里插入图片描述
如果你觉得这篇文章对你有帮助,不妨动动手指给点赞收藏加转发,给鄃鳕一个大大的关注
你们的每一次支持都将转化为我前进的动力!!

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

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

相关文章

树上差分(点差分/边差分)

树上差分一般有两种类型的题目,一种是对边进行差分,另一种就是对点进行差分。 对应的操作也有两种,对边进行差分的对应操作就是给定一对节点(u,v),让我们把u到v之间路径上的边权都加val,对点进行差分的对应操作就是给…

经验正交分解EOF的Matlab的实现示例

在地学中,PCA和EOF通常用于信号提取,从繁杂的时空数据中分离出地理要素的时空变化特征,是进行地学信号分析的前提。本质上PCA和EOF没有什么不同,只是:EOF为空间特征向量,也称为空间模态,在一定程…

信号完整性分析:关于传输线的三十个问题解答(一)

1.什么是真正的传输线?(What is a real transmission line?) 答:真正的传输线由任意两条延长一定长度的导体组成。将一根导线标记为信号路径,将另一根导线标记为返回路径。 A real transmission line is composed o…

2023最经典的Python接口自动化测试中的用例编写问题总结

本篇文章分享几个接口自动化用例编写过程遇到的问题总结,希望能对初次探索接口自动化测试的小伙伴们解决问题上提供一小部分思路。 B站讲的最详细的Python接口自动化测试实战教程全集(实战最新版)_哔哩哔哩_bilibiliB站讲的最详细的Python接…

4月,不要跳槽...

跳槽是每个人都可能面临的选择,但不同的时间点会对跳槽带来不同的影响。对于软件测试人员来说,4月份并不是最适合的跳槽时间。原因如下: 与企业目标和计划相关。一般情况下,公司在1月份会制定本年度的发展目标和计划,而…

力扣sql中等篇练习(五)

力扣sql中等篇练习(五) 1 股票的资本收益 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 # 每个用户的所有Sell的price值减去Buy的price值就可以了 SELECT stock_name,SUM(IF(operationBuy,price*-1,price)) capital_gain_loss FROM Stocks GROUP B…

IT知识百科:什么是SSID?

一、什么是SSID SSID(Service Set Identifier)是无线网络中的一个重要概念,它是一个用于标识无线局域网(WLAN)的名称。SSID可以看作是无线网络的名称,类似于有线网络中的网络名称或者路由器的名称。在无线…

【JavaScript】5.JavaScript内置对象

JavaScript 内置对象 JavaScript 中的对象分为3种 自定义对象内置对象浏览器对象 前面两种对象是JS 基础 内容,属于 ECMAScript; 第三个浏览器对象属于JS 独有的 内置对象就是指 JS 语言自带的一些对象,这些对象供开发者使用,…

数据通信基础 - 数据通信方式

文章目录 1 概述2 分类2.1 按通信方向分2.2 按同步方式分 3 扩展3.1 网工软考真题 1 概述 分类维度分类解释举例通信方向单工通信信息 只能在一个方向发送,发送方不能接收,接收方不能发送电视、广播半双工通信通信双方可以 交替发送和接收信息&#xff…

分布式锁+AOP实现缓存

分布式锁AOP实现缓存 1、分布式锁AOP实现思想2、不使用AOP的情况2.1 没有使用缓存时代码2.2 使用Redis实现分布式锁的代码2.3 使用Redisson实现分布式锁2.4 测试缓存命中2.5 存在问题 3、分布式锁AOP实现3.1 定义注解3.2 定义一个切面类加上注解3.3 使用注解完成缓存 1、分布式…

函数的缺省参数,函数重载与底层函数名修饰解释,引用的初步介绍

TIPS 使用C输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动控制格式。C的输入输出可以自动识别变量类型。在日常练习中,建议直接using namespace std即可,这样就很方便。using namespace std展开,标准库…

ReetrantLock源码剖析_03公平锁、非公平锁

一直努力就会有offer,一直努力就会有offer,一直努力就会有offer! 文章目录 ReetrantLock公平锁代码解析ReetrantLock公平锁执行流程ReetrantLock非公平锁代码解析ReetrantLock非公平锁执行流程公平锁与非公平锁的比较 ReetrantLock公平锁代码…

前端部署发布项目后,如何通知用户刷新页面、清除缓存

以下只是一些思路,有更好的实现方式可以留言一起交流学习 方式一:纯前端 在每次发布前端时,使用webpack构建命令生成一个json文件,json中写个随机生成的一个字符串(比如时间戳),每次打包程序都…

【Python入门第五十天】Python丨NumPy 数组搜索

搜索数组 可以在数组中搜索(检索)某个值,然后返回获得匹配的索引。 要搜索数组,请使用 where() 方法。 实例 查找值为 4 的索引: import numpy as nparr np.array([1, 2, 3, 4, 5, 4, 4])x np.where(arr 4)pri…

node可以用nvm快速切换版本,golang如何快速切换版本?用gvm就行。

使用 gvm 可以带来以下好处: 快速切换 Golang 版本,方便进行版本测试和开发;可以在多个项目中同时使用不同版本的 Golang 包和工具,避免冲突;可以通过 gvm 管理不同版本的 Golang,方便安装、卸载和更新&am…

STL--vector

一、vector介绍 vector是表示大小可以更改的数组的序列容器 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而…

移动端屏幕适配

文章目录 移动端屏幕适配移动端屏幕适配和响应式布局区别基本知识简单屏幕适配 移动端屏幕适配 移动端屏幕适配和响应式布局区别 移动端适配响应式布局终端移动端PC端和移动端常用单位宽高:rem 或 %字体:px宽:%高、字体:px宽高宽…

Docker网络模式与cgroups资源控制

目录 1.docker网络模式原理 2.端口映射 3.Docker网络模式(41种) 1.查看docker网络列表 2.网络模式详解 4.Docker cgroups资源控制 1.CPU资源控制 2.对内存使用的限制 3.对磁盘IO的配置控制(blkio)的限制 4.清除docker占用…

Vue3教程

文章目录 参考资料1 setup语法糖1.1 vue2中的写法1.2 setup语法糖在vue3中使用 2 ref reactive 事件2.1 ref2.2 reactive2.3 事件:在setup script中,直接定义事件,不需要像vue2那样在method中定义 3 computed & watch & watchEffect3…

详解DHCP和DNS实验汇总

文章目录 1.实验说明2.实验步骤2.1(linux的CentOS 7-2)命令配置2.2 (linux的CentOS 7-3)命令配置2.3 客户端(WIN10)命令配置2.4 客户端(CentOS 7-1)命令配置 1.实验说明 实验要求:要求在一台主机中同时配置DNS服务器和…