用队列实现栈——数据结构与算法

news2024/11/22 17:07:02

在这里插入图片描述
请添加图片描述

😶‍🌫️Take your time ! 😶‍🌫️
💥个人主页:🔥🔥🔥大魔王🔥🔥🔥
💥代码仓库:🔥🔥魔王修炼之路🔥🔥
💥所属专栏:🔥魔王的修炼之路–数据结构🔥
如果你觉得这篇文章对你有帮助,请在文章结尾处留下你的点赞👍和关注💖,支持一下博主。同时记得收藏✨这篇文章,方便以后重新阅读。


文章目录

  • 一、题目
  • 二、思路
  • 三、代码
    • 1、队列代码
    • 2、创建两个队列模拟的栈
    • 3、入栈
    • 4、出栈
    • 5、访问栈顶元素
    • 6、判断栈是否为空
    • 7、释放空间
    • 8、总代码
  • 四、总结

一、题目

力扣链接

在这里插入图片描述

二、思路

栈是后进先出,队列是先进先出.

出队列:队列入了1,2,3,4后只能1,2,3,4出,栈入了1,2,3,4后只能4,3,2,1出,所以需要两个队列,当栈出元素时,先让前n-1个入到另一个队列并删除原队列中这n-1个数据,那么原来队列只剩下4了,然后把这个4删除就行。

在这里插入图片描述

入队列:根据出队列发现,把一个队列数据放到另一个数据里面,原来的数据顺序不变,所以入队列时只需要入在那个不为空的队列里就行。

在这里插入图片描述

三、代码

1、队列代码

首先先把之前实现队列的代码粘贴上去,这样就不用再实现一遍队列了。

#include <stdlib.h>

typedef int QDataType;

typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QNode;

typedef struct Queue
{
	QNode* head;
	QNode* tail;
	int size;
}Queue;

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

void QDestroy(Queue* q)
{
	assert(q);
	while (q->head)
	{
		QNode* next = q->head->next;
		free(q->head);
		q->head = next;
	}
	q->tail = NULL;
	q->size = 0;
}

QNode* BuyNewnode(QDataType x)
{
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc error");
		assert(newnode);
	}
	newnode->data = x;
	newnode->next = NULL;
	return newnode;
}

void QPush(Queue* q, QDataType x)
{
	assert(q);
	QNode* newnode = BuyNewnode(x);
	if (q->head == NULL)
	{
		assert(q->head == q->tail);
		q->head = q->tail = newnode;
	}
	else
	{
		q->tail->next = newnode;
		q->tail = newnode;
	}
	q->size++;
}

void QPop(Queue* q)
{
	assert(q);
	assert(q->head && q->tail);
	if (q->head->next == NULL)
	{
		assert(q->head == q->tail);
		free(q->head);
		q->head = q->tail = NULL;
	}
	else
	{
		QNode* newhead = q->head->next;
		free(q->head);
		q->head = newhead;
	}
	q->size--;
}

int QSize(Queue* q)
{
	assert(q);
	return q->size;
}

bool QEmpty(Queue* q)
{
	assert(q);
	//-------------------------1------------------------------------------------
	//1这里的报错,但是其实根本没错,是在下面的2处错的,所以在哪个地方报错可以重点看那个地方,但并不一定就是这个部分错了。
	return q->size == 0;
}

QDataType QFront(Queue* q)
{
	assert(q);
	assert(q->head);
	return q->head->data;
}

QDataType QBack(Queue* q)
{
	assert(q);
	assert(!QEmpty(q));
	return q->tail->data;
}

2、创建两个队列模拟的栈

创建一个结构体,放两个队列作为成员,然后创建并初始化队列。

//匿名结构体,创建一个结构体是我的栈,因为我们使用队列模拟栈,所以里面放两个队列。
typedef struct {
    Queue q1;
    Queue q2;
} MyStack;


//创建我的栈,前面我们的模拟栈的结构体已经创建好了,现在就是要创建一个指针指向我们开辟出的该结构体的空间,并使其初始化。因为这是创建好后用的返回值传给别的函数,所以不能直接创建变量,要malloc,否则除该作用域就销毁了。
MyStack* myStackCreate() {
    MyStack* creat = (MyStack*)malloc(sizeof(MyStack));
    if(creat == NULL)
    {
        perror("malloc error");
        assert(creat);
    }
    QInit(&creat->q1);
    QInit(&creat->q2);
    return creat;
}

3、入栈

直接入到不为空的队列就行,因为两个相互导顺序还是原来的顺序。

在这里插入图片描述

void myStackPush(MyStack* obj, int x) {
	Queue* EmptyQ = &obj->q1;
	Queue* nonEmptyQ = &obj->q2;
	//if (QEmpty(&EmptyQ) == 0)-------------------------2(错的)----------------------------------
	if (QEmpty(EmptyQ) == 0)
	{
		EmptyQ = &obj->q2;
		nonEmptyQ = &obj->q1;
	}
	QPush(nonEmptyQ, x);
}

4、出栈

让不为空的n-1个元素导到空队列中,原队列只剩最后一个,然后pop就行了。

在这里插入图片描述

int myStackPop(MyStack* obj) {
	Queue* EmptyQ = &obj->q1;
	Queue* nonEmptyQ = &obj->q2;
	if (!QEmpty(EmptyQ))
	{
		EmptyQ = &obj->q2;
		nonEmptyQ = &obj->q1;
	}
	while (QSize(nonEmptyQ) != 1)
	{
		QPush(EmptyQ, QFront(nonEmptyQ));
		QPop(nonEmptyQ);
	}
	int ret = QFront(nonEmptyQ);
	QPop(nonEmptyQ);
	return ret;
}

5、访问栈顶元素

可以直接访问非空队列的最上面的元素即可。

//方法1.访问栈顶元素
int myStackTop(MyStack* obj) {
    if(!QEmpty(&obj->q1))
    {
        return QBack(&obj->q1);
    }
    else
    	return QBack(&obj->q2);
}

也可以再导一次,就像出栈一样,只不过不删除最后的元素,而是也导入另一个队列。

//方法2.访问栈顶元素
// 力扣检查比较严格,就算最后的那个return没用,但有返回值的函数结尾还是要加上return 的。
int myStackTop(MyStack* obj) {
	int ret = 0;
		Queue* EmptyQ = &obj->q1;
		Queue* nonEmptyQ = &obj->q2;
		if(!QEmpty(EmptyQ))
		{
				EmptyQ = &obj->q2;
				nonEmptyQ = &obj->q1;
		}
		while(QSize(nonEmptyQ)>0)
		{
			if(QSize(nonEmptyQ) == 1)
			{
				ret = QFront(nonEmptyQ);
				QPush(EmptyQ,QFront(nonEmptyQ));
				QPop(nonEmptyQ);
				return ret;
			}
			QPush(EmptyQ,QFront(nonEmptyQ));
			QPop(nonEmptyQ);
		}
		return ret;
}

6、判断栈是否为空

两个队列同时为空即为空。

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

7、释放空间

malloc了几次就释放几次。

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

8、总代码

#include <stdlib.h>

typedef int QDataType;

typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QNode;

typedef struct Queue
{
	QNode* head;
	QNode* tail;
	int size;
}Queue;

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

void QDestroy(Queue* q)
{
	assert(q);
	while (q->head)
	{
		QNode* next = q->head->next;
		free(q->head);
		q->head = next;
	}
	q->tail = NULL;
	q->size = 0;
}

QNode* BuyNewnode(QDataType x)
{
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc error");
		assert(newnode);
	}
	newnode->data = x;
	newnode->next = NULL;
	return newnode;
}

void QPush(Queue* q, QDataType x)
{
	assert(q);
	QNode* newnode = BuyNewnode(x);
	if (q->head == NULL)
	{
		assert(q->head == q->tail);
		q->head = q->tail = newnode;
	}
	else
	{
		q->tail->next = newnode;
		q->tail = newnode;
	}
	q->size++;
}

void QPop(Queue* q)
{
	assert(q);
	assert(q->head && q->tail);
	if (q->head->next == NULL)
	{
		assert(q->head == q->tail);
		free(q->head);
		q->head = q->tail = NULL;
	}
	else
	{
		QNode* newhead = q->head->next;
		free(q->head);
		q->head = newhead;
	}
	q->size--;
}

int QSize(Queue* q)
{
	assert(q);
	return q->size;
}

bool QEmpty(Queue* q)
{
	assert(q);
	//-------------------------1------------------------------------------------
	//1这里的报错,但是其实根本没错,是在下面的2处错的,所以在哪个地方报错可以重点看那个地方,但并不一定就是这个部分错了。
	return q->size == 0;
}

QDataType QFront(Queue* q)
{
	assert(q);
	assert(q->head);
	return q->head->data;
}

QDataType QBack(Queue* q)
{
	assert(q);
	assert(!QEmpty(q));
	return q->tail->data;
}

//匿名结构体,创建一个结构体是我的栈,因为我们使用队列模拟栈,所以里面放两个队列。
typedef struct {
    Queue q1;
    Queue q2;
} MyStack;


//创建我的栈,前面我们的模拟栈的结构体已经创建好了,现在就是要创建一个指针指向我们开辟出的该结构体的空间,并使其初始化。因为这是创建好后用的返回值传给别的函数,所以不能直接创建变量,要malloc,否则除该作用域就销毁了。
MyStack* myStackCreate() {
    MyStack* creat = (MyStack*)malloc(sizeof(MyStack));
    if(creat == NULL)
    {
        perror("malloc error");
        assert(creat);
    }
    QInit(&creat->q1);
    QInit(&creat->q2);
    return creat;
}

void myStackPush(MyStack* obj, int x) {
	Queue* EmptyQ = &obj->q1;
	Queue* nonEmptyQ = &obj->q2;
	//if (QEmpty(&EmptyQ) == 0)-------------------------2----------------------------------
	if (QEmpty(EmptyQ) == 0)
	{
		EmptyQ = &obj->q2;
		nonEmptyQ = &obj->q1;
	}
	QPush(nonEmptyQ, x);
}

int myStackPop(MyStack* obj) {
	Queue* EmptyQ = &obj->q1;
	Queue* nonEmptyQ = &obj->q2;
	if (!QEmpty(EmptyQ))
	{
		EmptyQ = &obj->q2;
		nonEmptyQ = &obj->q1;
	}
	while (QSize(nonEmptyQ) != 1)
	{
		QPush(EmptyQ, QFront(nonEmptyQ));
		QPop(nonEmptyQ);
	}
	int ret = QFront(nonEmptyQ);
	QPop(nonEmptyQ);
	return ret;
}

// //方法1.访问栈顶元素
// int myStackTop(MyStack* obj) {
//     if(!QEmpty(&obj->q1))
//     {
//         return QBack(&obj->q1);
//     }
//     else
//         return QBack(&obj->q2);
// }

//方法2.访问栈顶元素
// 力扣检查比较严格,就算最后的那个return没用,但有返回值的函数结尾还是要加上return 的。
int myStackTop(MyStack* obj) {
	int ret = 0;
		Queue* EmptyQ = &obj->q1;
		Queue* nonEmptyQ = &obj->q2;
		if(!QEmpty(EmptyQ))
		{
				EmptyQ = &obj->q2;
				nonEmptyQ = &obj->q1;
		}
		while(QSize(nonEmptyQ)>0)
		{
			if(QSize(nonEmptyQ) == 1)
			{
				ret = QFront(nonEmptyQ);
				QPush(EmptyQ,QFront(nonEmptyQ));
				QPop(nonEmptyQ);
				return ret;
			}
			QPush(EmptyQ,QFront(nonEmptyQ));
			QPop(nonEmptyQ);
		}
		return ret;
}

//方法3.访问栈顶元素
// int myStackTop(MyStack* obj) {
// 	Queue* EmptyQ = &obj->q1;
// 	Queue* nonEmptyQ = &obj->q2;
// 	if (!QEmpty(EmptyQ))
// 	{
// 		EmptyQ = &obj->q2;
// 		nonEmptyQ = &obj->q1;
// 	}
// 	while (QSize(nonEmptyQ) != 1)
// 	{
// 		QPush(EmptyQ, QFront(nonEmptyQ));
// 		QPop(nonEmptyQ);
// 	}
// 	int ret = QFront(nonEmptyQ);
// 	QPush(EmptyQ,QFront(nonEmptyQ));
// 	QPop(nonEmptyQ);
// 	return ret;
// }

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

void myStackFree(MyStack* obj) {
    QDestroy(&obj->q1);
    QDestroy(&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);
*/

四、总结

  • -----1-----和-----2-----这两个地方是一个错误,因为在2多写了个取地址,然后在1处报错,结果检查了大半天也检查不出来,因为1处报错很难想出来是2处的问题。所以:报错的地方重点检查,如果真的没错误,可能是其他地方的问题。
  • 分别指向空队列和非空队列时别弄混了,有点绕。

  • 博主长期更新,博主的目标是不断提升阅读体验和内容质量,如果你喜欢博主的文章,请点个赞或者关注博主支持一波,我会更加努力的为你呈现精彩的内容。

🌈专栏推荐
😈魔王的修炼之路–C语言
😈魔王的修炼之路–数据结构初阶
😈魔王的修炼之路–C++
😈魔王的修炼之路–Linux
更新不易,希望得到友友的三连支持一波。收藏这篇文章,意味着你将永久拥有它,无论何时何地,都可以立即找到重新阅读;关注博主,意味着无论何时何地,博主将永久和你一起学习进步,为你带来有价值的内容。

请添加图片描述

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

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

相关文章

【JS交互篇】DOM操作基础

一、DOM概述 1.1 什么是DOM DOM(Document Object Model)文档对象模型&#xff0c;用来表示和操作html或xml文档内容的基础API;当网页被加载时&#xff0c;浏览器会创建页面的文档对象模型DOM&#xff0c;而DOM模型被构造为对象的树&#xff08;Dom Html Tree&#xff09;;DOM包…

真我V3 5G(RMX2200 RMX2201)解锁刷机全过程

安卓系统新Rom包为GSI&#xff0c;更具有通用性&#xff0c;可以比较放心刷。 原厂系统垃圾多、广告多&#xff0c;甚至热点功能不支持ipv6&#xff0c;严重偏离热点机的定位。 主要参考 https://www.bilibili.com/read/cv20730877/https://www.bilibili.com/read/cv2073087…

DSV-080-2NCP-N-MM两位两通常闭先导式电磁阀

该插装阀具有正向关断作用&#xff0c;设计用于负荷保持状态。 动作状况 断电时&#xff0c;DSV -080-2NCP-*-M*为止回阀&#xff0c;允许介质从1到2&#xff0c;同时阻止介质从2到1。 通电时&#xff0c;提升阀提升&#xff0c;打开从 2到1的通通道。 手动关闭选择:按下按…

分布式协议与算法——CAP理论、ACID理论、BASE理论

CAP理论 CAP理论&#xff0c;对分布式系统的特性做了高度抽象&#xff0c;比如抽象成了一致性、可用性和分区容错性&#xff0c;并对特性间的冲突&#xff08;也就是CAP不可能三角&#xff09;做了总结。 CAP三指标 CAP理论对分布式系统的特性做了高度抽象&#xff0c;形成了…

境内金融信息服务报备33家机构名单

2022年01月04日&#xff0c;国家互联网信息办公室关于发布第一批境内金融信息服务机构报备编号的公告&#xff0c;公开发布第一批20家金融信息服务机构的名称及报备编号。 2022年10月28日&#xff0c;国家互联网信息办公室关于发布第二批境内金融信息服务机构报备编号的公告&am…

Linux常用命令学习总结

Linux命令分类 1. Linux目录操作命令2. Linux文件名称3. Linux磁盘命令4. Linux进程与防火墙5. Linux用户与组的关系6. Linux权限操作(chmod命令)7. Linux中的文件类型文件的寻找 最近系统地学习下Linux命令的使用&#xff0c;因此作如下记录&#xff0c;以便随时复习和翻阅。 …

栈和队列的实现以及OJ题讲解

&#x1f493;博主个人主页:不是笨小孩&#x1f440; ⏩专栏分类:数据结构与算法&#x1f440; 刷题专栏&#x1f440; C语言&#x1f440; &#x1f69a;代码仓库:笨小孩的代码库&#x1f440; ⏩社区&#xff1a;不是笨小孩&#x1f440; &#x1f339;欢迎大家三连关注&…

Android安卓实战项目(9)—漂亮的健身APP主页控件+开机动画+BMI计算(源码在文末)可用于比赛项目或者作业参考中

Android安卓实战项目&#xff08;9&#xff09;—漂亮的健身控件APP开机动画BMI计算&#xff08;源码在文末&#x1f415;&#x1f415;&#x1f415;&#xff09; 介绍&#xff1a; BMI&#xff08;Body Mass Index&#xff0c;身体质量指数&#xff09;是一种常用的健康指标…

Spring Cloud Alibaba (一)

1 微服务介绍 1.1 系统架构演变 随着互联网的发展&#xff0c;网站应用的规模也在不断的扩大&#xff0c;进而导致系统架构也在不断的进行变化。 从互联网早起到现在&#xff0c;系统架构大体经历了下面几个过程: 单体应用架构--->垂直应用架构--->分布 式架构--->S…

LeetCode 29题:两数相除

题目 给你两个整数&#xff0c;被除数 dividend 和除数 divisor。将两数相除&#xff0c;要求 不使用 乘法、除法和取余运算。 整数除法应该向零截断&#xff0c;也就是截去&#xff08;truncate&#xff09;其小数部分。例如&#xff0c;8.345 将被截断为 8 &#xff0c;-2.…

一生一芯1——windows与Ubuntu双系统安装

UltraISO下载 下载链接&#xff1a;https://pan.baidu.com/s/18ukDs6yL64qU6thYyZEo-Q?pwdo8he 提取码&#xff1a;o8he 一路傻瓜安装&#xff0c;安装后点击继续试用 Ubuntu系统下载 这里我使用的是官网的22.04版本&#xff0c;由于大于4G&#xff0c;无法上传至百度网盘…

【CSS】CSS 选择器

CSS 选择器 1.基础选择器 1.1 元素选择器 语法&#xff1a;标签名{...} 元素选择器会选中对应标签名的HTML元素&#xff0c;例如&#xff1a;p{...}&#xff0c;div{...}&#xff0c;span{...}等 1.2 类选择器 语法&#xff1a;.类名{...} 类选择器会选中class属性为指定…

老胡的周刊(第102期)

老胡的信息周刊[1]&#xff0c;记录这周我看到的有价值的信息&#xff0c;主要针对计算机领域&#xff0c;内容主题极大程度被我个人喜好主导。这个项目核心目的在于记录让自己有印象的信息做一个留存以及共享。 &#x1f3af; 项目 ChatGPT-Shortcut[2] ChatGPT 快捷指令&…

MyBatis-Plus是什么以及特性[MyBatis-Plus系列] - 第481篇

​ 悟纤&#xff1a;师傅&#xff0c;宝宝不开心呢。 师傅&#xff1a;怎么不开心&#xff1f; 悟纤&#xff1a;感觉好多重复的代码来着。 师傅&#xff1a;是哪个部分重复的代码来着&#xff1f; 悟纤&#xff1a;就是对于一个model的增删改查部分。 师傅&#xff1a;那这…

周赛357(模拟、脑经急转弯、多源BFS+并查集、反悔贪心)

文章目录 周赛357[2810. 故障键盘](https://leetcode.cn/problems/faulty-keyboard/)模拟双端队列O(n) [2811. 判断是否能拆分数组](https://leetcode.cn/problems/check-if-it-is-possible-to-split-array/)脑经急转弯 [2812. 找出最安全路径](https://leetcode.cn/problems/f…

SpringBoot系列---【三种启动传参方式的区别】

三种启动传参方式的区别 1.三种方式分别是什么? idea中经常看到下面三种启动传参方式 优先级 Program arguments > VM options > Environment variable > 系统默认值 2.参数说明 2.1、VM options VM options其实就是我们在程序中需要的运行时环境变量&#xff0c;它需…

实现Jenkins自动发包配置

参考抖音&#xff1a;Java不良人 其中的视频演示代码 不推荐把jenkins端口一直开放&#xff0c;推荐使用时候放开&#xff08;版本不太新&#xff0c;避免漏洞攻击&#xff09; [rootVM-4-12-centos soft]# docker-compose -v Docker Compose version v2.19.1docker-compose.…

TCP三次握手四次断开

一、了解TCP &#x1f345;TCP &#xff1a;传输控制协议&#xff0c;是一种面向连接的可靠的传输协议。 什么是可靠的传输协议&#xff1f;如何保障可靠传输&#xff1f; 保证可靠性&#xff1a; 1.确认机制 2.重传输机制什么是面向连接&#xff1f;如何保障面…

C语言 | 位运算符>>的高级用法

一、人物简介 第一位闪亮登场&#xff0c;有请今后会一直教我们C语言的老师 —— 自在。 第二位上场的是和我们一起学习的小白程序猿 —— 逍遥。 二、优化除法运算 除法运算需要比位移运算需要更多的计算资源&#xff0c;某些情况下采用位移运算可以提高性能 代码示例 #in…

代码随想录算法训练营第51天|动态规划part09|198.打家劫舍、213.打家劫舍II、337.打家劫舍III

代码随想录算法训练营第51天&#xff5c;动态规划part09&#xff5c;198.打家劫舍、213.打家劫舍II、337.打家劫舍III 198.打家劫舍 198.打家劫舍 思路&#xff1a; 仔细一想&#xff0c;当前房屋偷与不偷取决于 前一个房屋和前两个房屋是否被偷了。 所以这里就更感觉到&a…