【数据结构】栈与队列OJ题(用队列实现栈)(用栈实现队列)

news2024/9/21 20:02:16

目录

1.用队列实现栈oj题

对比

一、初始化

二、出栈 

三、入栈

四、取队头元素:

2.用栈实现队列 

一、定义

二、入队列

三、出队列

四、队头

五、判空



                                                                                                                                  

前言:如果想了解什么是栈和队列请参考上一篇文章进来一起把【数据结构】的【栈与队列】狠狠玩弄,痛快到大汗淋漓-CSDN博客

本篇不进行详细讲解栈和队列的定义

1.用队列实现栈oj题

. - 力扣(LeetCode)

在这个题目中,用两个队列实现栈,以队列的方法和知识点实现栈

对比

我们先来一个函数对比一下

这是用普通方法来实现的栈的初始化

void STInit(ST* ps)
{
	assert(ps);
	ps->arr = NULL;
	ps->capacity = ps->top = 0;
}

 这是用队列方法实现的初始化

MyStack* MyStackCreat()
{
	MyStack* plt = (MyStack*)malloc(sizeof(MyStack));
	QueueInit(&plt->q1);
	QueueInit(&plt->q2);
	return plt;

	}

差异很明显,队列实现的方式明显要复杂很多,哈哈哈,这就是oj题,锻炼的是你的思维

写代码之前,我们用图解先来解析

一、初始化

首先我们要知道的是,我们用队列实现栈,要定义和初始化的是什么,用队列实现栈,实则是用队列的属性实现栈的属性,所以我们在这里要定义队列

但是为什么要定义两个队列?

题目上说了要用两个队列实现

所以我们定义队列,用结构体实现两个不同的队列。

代码:

typedef int QDataType;
typedef struct QueueNode
{
	QDataType data;
	struct QueueNode* next;
}QueueNode;
typedef struct
{
	QueueNode q1;
	QueueNode q2;

}MyStack;
MyStack* MyStackCreat()
{
	MyStack* plt = (MyStack*)malloc(sizeof(MyStack));
	QueueInit(&plt->q1);
	QueueInit(&plt->q2);
	return plt;

	
}

二、出栈 

1.我们先将所有需要的数据入队列,这里要注意的是入队列的时候是队尾入,队头出,也就是FIFO(先进先出)


2.入完队列之后

我们开始模拟出栈思路,栈的属性是先进后出,队列的属性是先进先出,那么问题就来了,怎么用先进先出的两个数列实现先进后出。这个就是核心思路。

对于q1队列来说,此时q2队列是空的

既然是栈的属性先进的后出,所以就是q1的队尾先出,所以要找到q1的队尾

                           那么你会说这不简单嘛?用指针不就完了?

但是哈,这里要强调,用队列的属性来实现栈的属性,使用的自然是队列的接口。而不是用库函数。

队列的基本操作有什么哪?

入队列,出队列,队列判别空,取队头,取队尾,队列有效个数,销毁

所以第一个思路就来了。


 将队尾前的元素直接移动到空队列q2,这样就q1队列剩下的元素就是队尾元素。

 之后如果再想出栈,再将q2的队尾前的元素移动到空队列q1,队尾元素出栈。

什么时候不能出栈了呢?直到两个队列都为空的时候


这样我们就用两个队列实现了先进后出,后进先出的栈的属性 

void MystackPop(MyStack* pst)
{
	QueueNode* nonequ = &pst->q1;
	QueueNode* emtyqu = &pst->q2;
	if (!QueueEmpty(&pst->q2))
	{

		emtyqu = &pst->q1;
	}

	else
	{
		emtyqu = &pst->q2;
	}

	while (QueueSize(nonequ) > 1)
	{
		int front = QueueFront(nonequ);
		QueuePush(emtyqu, front);
		QueuePop(nonequ);
	}
	int pop = QueueFront(nonequ);
	QueuePop(nonequ);
	return pop;
}

三、入栈

入栈操作相比于出栈先简单很多,入队列和入栈的属性其实是相同的,直接入就行了。所以体现在队列上就是先进的先入栈,所以就是队头入栈。 

void MyStackpush(MyStack* pst,int x)
{
	if (!QueueEmpty(&pst->q1))
	{
		QueuePush(&pst->q1, x);

	}
	else
	{
		QueuePush(&pst->q2, x);
	}

}

四、取队头元素:

取队头元素听起来很复杂,其实就是在栈里就是最后一个进入的,在队列里就是队尾 

直接返回队列的队尾元素即可 

int MystackTop(MyStack* pst)
{
	if (!QueueEmpty(&pst->q1))
	{
		return QueueBack(&pst->q1);
	}
	else
	{
		return QueueBack(&pst->q2);

	}
}

2.用栈实现队列 

232. 用栈实现队列 - 力扣(LeetCode)

对于用栈实现队列其实扒开底层逻辑就好,也不难理解,要实现push,pop,top,empty几种接口,其实就是入栈,出栈,返回栈顶,判断是否为空。至于怎么具体实现,接下来就是详细解释

一、定义

这里要定义两个栈,我们分别命名为pop和push队列

typedef struct
{
	ST pushST;
	ST popST;
}MyQU;

MyQU* MyQueueCreat()
{
	MyQU* pst = (MyQU*)malloc(sizeof(MyQU));
	STInit(&pst->pushST);
	STInit(&pst->popST);
	return pst;
}

二、入队列

两者逻辑差不多,直接入队列即可,

void MyqueuePush(MyQU* obj,int x)
{
	StackPush(&obj->pushST, x);
}

三、出队列

其实出队列的逻辑跟出栈的逻辑是相反的,跟上面的逻辑正好是倒过来的,底层逻辑是怎么用两个先进后出的栈实现先进先出的队列但其实方法是大相径庭的。

判断pop是否为空为空的push的数据全部出栈,然后入栈给pop不会空直接出栈,相当于出队列

步骤一 

过程二: 

 

过程三: 

int MyQueuePop(MyQU* obj)
{
	if (StackEmpty(&obj->popST))
	{
		while (&obj->pushST)
		{
			StackPush(&obj->popST, StackTop(&obj->pushST));
			StackPop(&obj->pushST);
		}
	}
	int pop = StackTop(&obj->popST);
	StackPop(&obj->popST);
	return pop;

	
}

四、队头

队列中的队头限速是先进的那个元素,在栈中是最后出栈的那个元素,所以我们将栈的最后元素当作队头即可

五、判空

 判断队列是空的时候,相当于push和pop的栈都为空,只有两个都为空的时候才是空。

要用到的队列和栈的接口源码

队列的接口源码

#define _CRT_SECURE_NO_WARNINGS 1
#include"Queue.h"
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}
// ⼊队列,队尾
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	//申请新节点
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	if (newnode == NULL)
	{
		perror("malloc fail!");
		exit(1);
	}
	newnode->data = x;
	newnode->next = NULL;

	//ptail newnode
	if (pq->phead == NULL)
	{//队列为空
		pq->phead = pq->ptail = newnode;
	}
	else
	{
		//队列不为空
		pq->ptail->next = newnode;
		pq->ptail = pq->ptail->next;//newnode
	}
	pq->size++;
}

//队列判空
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->phead == NULL && pq->ptail == NULL;
}

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

	//只有一个结点的情况,避免ptail变成野指针
	if (pq->ptail == pq->phead)
	{
		free(pq->phead);
		pq->phead = pq->ptail = NULL;
	}
	else
	{
		//删除队头元素、
		QueueNode* 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;
}

//取队尾数据QU
QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));

	return pq->ptail->data;
}
//队列有效元素个数
int QueueSize(Queue* pq)
{
	assert(pq);
	/*int size = 0;
	QueueNode* pcur = pq->phead;
	while (pcur)
	{
		size++ ;
		pcur = pcur->next;
	}
	return size;*/
	return pq->size;
}

//销毁队列
void QueueDestroy(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));

	QueueNode* pcur = pq->phead;
	while (pcur)
	{
		QueueNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}

 栈的接口

#define _CRT_SECURE_NO_WARNINGS 1
#include"Stack.h"

void STInit(ST* ps)
{
	assert(ps);
	ps->arr = NULL;
	ps->capacity = ps->top = 0;
}

void STDestroy(ST* ps)
{
	assert(ps);
	if (ps->arr)
		free(ps->arr);
	ps->arr = NULL;
	ps->top = ps->capacity = 0;
}

void StackPush(ST* ps, STDataType x)
{
	assert(ps);

	//1.判断空间是否足够
	if (ps->capacity == ps->top)
	{
		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		STDataType* tmp = (STDataType*)realloc(ps->arr, newCapacity * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("realloc fail!");
			exit(1);
		}
		ps->arr = tmp;
		ps->capacity = newCapacity;
	}
	//空间足够
	ps->arr[ps->top++] = x;
}
bool StackEmpty(ST* ps)
{
	assert(ps);
	return ps->top == 0;
}
void StackPop(ST* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));
	--ps->top;
}


//取栈顶元素
STDataType StackTop(ST* ps)
{

	assert(ps);
	assert(!StackEmpty(ps));

	return ps->arr[ps->top - 1];
}

//获取栈中有效元素个数
int STSize(ST* ps)
{
	assert(ps);
	return ps->top;
}

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

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

相关文章

Cursor是什么?Cursor Pro Plus 如何订阅升级教程

一、Cursor是什么? Cursor 是一个基于 Visual Studio Code(VS Code)技术构建的高级代码编辑器,专为提高编程效率并更深度地整合 AI 功能而设计。它不仅继承了 VS Code 的强大功能和用户界面,还增加了专门针对 AI 支持…

Kafka3.6.0 linux 安装,非zk模式

1.下载 到kafka官网下载 2.上传到服务器指定位置 3.解压到指定目录,这里我放到/opt下 tar -xzvf kafka_2.13-3.6.0.tgz -C /opt/ 4.修改配置 因为我们不使用zookeeper,所以来到kafka装根目录的下的/config/kraft/ cd /opt/kafka_2.13-3.6.0/config…

前端HTML基础笔记

HTML(HyperText Markup Language,超文本标记语言)是一种用于创建网页的标准标记语言。它通过一系列的元素(或称为标签)来定义网页的结构和内容。HTML文档由一系列的元素组成,这些元素可以包含文本、图片、链…

伽罗华域GF的简单计算

伽罗华域(Galois Field),也称为有限域,是一个包含有限个元素的代数结构,满足加法、减法、乘法和除法(除以零除外)运算。伽罗华域在编码理论、密码学、数字信号处理等领域有广泛的应用。它以法国…

思科网络地址转换5

#网络安全技术实现# #任务五利用动态NAPT实现局域网访问Internet5# #1配置计算机的IP 地址、子网掩码和网关 #2配置路由器A的主机名称及其接口IP地址 Router>enable Router#conf t Router(config)#hostname Router-A Router-A(config)#int f0/0 Router-A(config-if)#i…

【Python报错已解决】 AttributeError: ‘move_to‘ requires a WebElement

🎬 鸽芷咕:个人主页 🔥 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想,就是为了理想的生活! 文章目录 前言一、问题描述1.1 报错示例1.2 报错分析1.3 解决思路 二、解决方法2.1 方法一:检查元素选择器2.2 方法…

计算机毕业设计选题-基于python的企业人事管理系统【源码+文档+数据库】

💖🔥作者主页:毕设木哥 精彩专栏推荐订阅:在 下方专栏👇🏻👇🏻👇🏻👇🏻 实战项目 文章目录 实战项目 一、基于python的企业人事管理系…

mycat双主高可用架构部署-MySQL5.7环境部署第一台

MySQL5.7服务器IP是192.168.31.209及192.168.31.210 1、192.168.31.209:3307实例部署 a、配置文件 mkdir -p /data/mysql/mysql3307/{data,logs} #创建MySQL数据及日志目录 vi /data/mysql/mysql3307/my3307.cnf #配置文件整理 [client] #password your_password port …

【LVI-SAM】激光雷达点云处理特征提取LIO-SAM 之FeatureExtraction实现细节

激光雷达点云处理特征提取LIO-SAM 之FeatureExtraction实现细节 1. 特征提取实现过程总结1.0 特征提取过程小结1.1 类 FeatureExtraction 的整体结构与作用1.2 详细特征提取的过程1. 平滑度计算(calculateSmoothness())2. 标记遮挡点(markOcc…

堆-数组的堆化+优先队列(PriorityQueue)的使用

一、堆 1、什么是堆? 以完全二叉树的形式将元素存储到对应的数组位置上所形成的新数组 2、为什么要将数组变成堆? 当数组中的元素连续多次进行排序时会消耗大量的时间,将数组变成堆后通过堆排序的方式将会消耗更少的时间 二、接口 给堆…

python | 字符串字母大小写转换方法

在对字符串所含字母单词进行处理时,经常会对其格式进行转换统一。 python自带了一些判断和处理转换的方法。 一、字符串格式判断方法 islower():str.islower(),判断字符串是否全是小写,是返回True,不是返回False i…

Transiting from CUDA to HIP(三)

一、Workarounds 1. memcpyToSymbol 在 HIP (Heterogeneous-compute Interface for Portability) 中,hipMemcpyToSymbol 函数用于将数据从主机内存复制到设备上的全局内存或常量内存中,这样可以在设备端的内核中访问这些数据。这个功能特别有用&#x…

红黑树——封装map和set

概念 红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平…

MySQL数据库介绍——初始数据库MySQL

作者简介:一名云计算网络运维人员、每天分享网络与运维的技术与干货。 公众号:网络豆云计算学堂 座右铭:低头赶路,敬事如仪 个人主页: 网络豆的主页​​​​​ 目录 写在前面: 一.数据库基础知识 1.…

使用shell脚本安装mysql8,进行主从备份配置

思路 在3台主机上安装mysql进行主从备份配置 使用rpm包yum安装mysql 首先,我们要准备好安装文件,首先下载rpm包 wget -P "/opt/" https://repo.mysql.com//mysql80-community-release-el7-3.noarch.rpm 然后执行安装(默认已配置…

1111111111111113

📢博客主页:https://blog.csdn.net/2301_779549673 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! 📢本文由 JohnKi 原创,首发于 CSDN🙉 📢未来很长&#…

openwrt的旁路模式无法访问国内网站

防火墙: 常规设置-> 区域: lan-> wan :编辑 IP 动态伪装:勾选

【Qt线程】—— Qt线程详解

目录 (一)多线程的概述 (二)Qt线程的使用条件 (三)创建线程的方法 3.1 继承QTread,重写run()函数 3.1.1 为什么要重写 3.2 继承QObject 3.3 核心API介绍 3.4 关闭线程的使用方法 &…

高压挑战:新能源汽车换电连接器的技术革新

摘要 随着汽车行业的电动化、网联化和智能化发展,新能源汽车连接器的使用量从传统汽车的600个左右增加到800至1000个。新能源汽车连接器在电连接和信号连接方面更为复杂,包括低压连接器和高压连接器。高压连接器面临严苛性能要求,如耐热性、…

Tomcat控制台乱码问题已解决(2024/9/7

步骤很详细,直接上教程 问题复现: 情景一 情景二 原因简述 这是由于编码不一致引起的,Tomcat启动后默认编码UTF-8,而Windows的默认编码是GBK。因此你想让其不乱码,只需配置conf\logging.properties的编码格式即可 解决…