数据结构:栈和队列详解(下)

news/2025/2/22 6:42:28

目录

一.如何用队列实现栈

1.思路:

2.具体代码:

二.如何用栈实现队列

1.思路:

2.具体代码:


一.如何用队列实现栈

原题来源:https://leetcode.cn/problems/implement-stack-using-queues/description/

前言:通过这篇文章我们的主要目的就是加深我们对栈和队列的理解以及其相互实现的算法的互通性,首先我们需要了解队列和栈的结构:队列是一个先进先出的结构,类似于我们生活中的饮水机,而则是一个先进后出的结构,呈现出层层叠叠的结构

并且还有一个重要的区别就在于队列一般使用链表实现而栈则主要通过数组实现,其中的原因自然是涉及到时间复杂度的问题,这里就不再过多赘述,在上一篇文章我应该也有所涉及,接下来就是正式展示如何用队列实现栈的具体思路代码

1.思路:

       当我们在使用先进先出的队列来实现先进后出的栈时,我们可以先从一个简单的例子开始,比如我往队列里插入1234这四个数据,那我就必须通过栈的方式(即4321的顺序)将其输出

       通过观察我们可以发现如果要用队列输出栈,就需要我们每次先输出队列中最后一个数据,因此顺着这样的思路,光光一个队列明显是不够的,因此我们可以大胆设想如果有两个队列供我们使用,当我们想要将1234以4321的形式输出时,我们可以先将有1234的队列的前三个数据先存到另外一个队列中以便输出4,当然,3的输出也如法炮制,

       这样通过在两个队列中的“反复横跳”,我们就可以轻易实现利用队列来实现栈这样的操作,具体要求如下:

理论成立,接下来就是代码的实现了:

2.具体代码:

#include<stdio.h>
#include<stdlib.h>//保函了动态申请malloc,realloc邓一系列函数
#include<assert.h>
#include<stdbool.h>

//定义结点结构
typedef int QDataTpe;
typedef struct QueueNode
{
	struct QueneNode* next;
	QDataTpe data;
}QueueNode;



//定义队列的结构
typedef struct Queue
{
	QueueNode* phead;//队头
	QueueNode* ptail;//队尾
	int size;
}Queue;

//队列的初始化
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->phead = pq->ptail = NULL;
    pq->size=0;
}

//入队(从队尾入)
void QueuePush(Queue* pq, QDataTpe x)
{
	assert(pq);
	//申请一个结点
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	if (newnode == NULL)
	{
		perror("malloc failed");
		exit(1);
	}
	newnode->data = x;
	newnode->next = NULL;
	//队列为空,newnode是对头也是队尾
	if (pq->phead == NULL)
	{
		pq->phead = pq->ptail = newnode;
	}
	else //队列非空,尾插
	{
		pq->ptail->next = newnode;
		pq->ptail = pq->ptail->next;
	}
	pq->size++;
}
//判断队列是否为空
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->phead == 0;
}

//出队(从队头出)
void QueuePop(Queue* pq)
{
	assert(!QueueEmpty(pq));
	//只有一个结点的情况下,要把队尾和队头的两个指针都考虑到
	if (pq->phead == pq->ptail)
	{
		free(pq->ptail);
		pq->phead = pq->ptail = NULL;
	}
	QueueNode* next = pq->phead->next;
	free(pq->phead);
	pq->phead = next;  
	pq->size--;
}

//取队头数据
QDataTpe QueueFront(Queue* pq)
{
	assert(!QueueEmpty(pq));
	return pq->phead->data;
}
//取队尾数据
QDataTpe QueueBack(Queue* pq)
{
	assert(!QueueEmpty(pq));
	return pq->ptail->data;
}
//队列的销毁
void QueueDestory(Queue* pq)
{
	assert(pq);
	QueueNode* pcur = pq->phead;
	while (pcur)
	{
		QueueNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	pq->phead = pq->ptail = NULL;
}
//取队列有效元素个数
int QueueSize(Queue* pq)
{
	return pq->size;
}
///以上是队列的常用方法

typedef struct
{
	Queue q1;
	Queue q2;//定义两个队列

} MyStack;

//初始化
MyStack* myStackCreate()
{
	MyStack* pst = (MyStack*)malloc(sizeof(MyStack));
	QueueInit(&pst->q1);
	QueueInit(&pst->q2);


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

	}
}

int myStackPop(MyStack* obj)
{
	//找不为空的队列,将不为空队列的前size-1个苏剧导入空队列
	Queue* emp = &obj->q1;
	Queue* noneEmp = &obj->q2;
	if (QueueEmpty(&obj->q2))
	{
		emp = &obj->q2;
		noneEmp = &obj->q1;
	}
	while (QueueSize(noneEmp) > 1)
	{
		//把noneEmp中的队头元素导入到空队列
		QueuePush(emp, QueueFront(noneEmp));
		QueuePop(noneEmp);
	}
	int top = QueueFront(noneEmp);
	QueuePop(noneEmp);
	return top;
}

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

}

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

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


}

二.如何用栈实现队列

原题出自:https://leetcode.cn/problems/implement-queue-using-stacks/description/

1.思路:

2.具体代码:


http://www.niftyadmin.cn/n/5861825.html

相关文章

【网络安全】从零开始的CTF生活

1、CTF是什么&#xff1f; CTF&#xff08;Capture The Flag&#xff0c;夺旗赛&#xff09;起源于 1996 年 DEFCON 全球大会&#xff0c;是网络安全爱好者之间的竞技游戏。 2、比赛怎么打&#xff1f; 1、解题模式&#xff1a; 与ACM编程竞赛、信息学奥赛类似&#xff0c;…

【Linux网络】认识协议(TCP/UDP)、Mac/IP地址和端口号、网络字节序、socket套接字

⭐️个人主页&#xff1a;小羊 ⭐️所属专栏&#xff1a;Linux 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 1、初识协议2、Mac、IP地址3、端口号4、网络字节序5、socket 1、初识协议 协议就是一种约定。如何让不同厂商生产的计算机之间能…

MySQL日志undo log、redo log和binlog详解

MySQL 日志&#xff1a;undo log、redo log、binlog 有什么用&#xff1f; 一、前言 在MySQL数据库中&#xff0c;undo log、redo log和binlog这三种日志扮演着至关重要的角色&#xff0c;它们各自承担着不同的功能&#xff0c;共同保障了数据库的正常运行和数据的完整性。了解…

DeepSeek 助力 Vue 开发:打造丝滑的缩略图列表(Thumbnail List)

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 Deep…

Spring监听器Listener

目录 1、Spring监听器简介 2、事件&#xff08;Event&#xff09; 3、监听器&#xff08;Listener&#xff09; 3、事件发布器 4、监听器使用 4.1、自定义事件 4.2、自定义监听器 4.3、发布事件 4.4、测试 4.5、使用注解方式监听 4.6、异步事件处理 5、总结 1、Spri…

除了Axios,如何用fetch处理403错误?

使用 fetch API 处理 403 错误与使用 Axios 类似&#xff0c;但需要手动检查响应状态。以下是一些最佳实践和示例&#xff0c;展示如何在使用 fetch 时优雅地处理 403 错误。 1. 基本的 Fetch 请求 首先&#xff0c;您需要进行一个基本的 fetch 请求&#xff0c;并检查响应的…

k8s容器运行时环境选型指南

引言 随着云原生技术的普及&#xff0c;Kubernetes已成为容器编排的事实标准&#xff0c;而容器运行时&#xff08;Container Runtime&#xff09;作为其核心底层组件&#xff0c;直接影响着集群的性能、安全性和运维效率。2022年Kubernetes正式弃用Dockershim&#xff0c;标志…

HTTPS 通信流程

HTTPS 通信流程时序图&#xff1a; #mermaid-svg-HWoTbFvfih6aYUu6 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-HWoTbFvfih6aYUu6 .error-icon{fill:#552222;}#mermaid-svg-HWoTbFvfih6aYUu6 .error-text{fill:#…