【使用两个队列实现栈】

news2024/9/23 11:14:35

文章目录

  • 前言
  • 使用两个队列实现栈
    • 1.队列接口函数引入
    • 2.栈的初始化
    • 3.向栈中插入元素
    • 4.出栈操作
    • 5.取出栈顶元素
    • 6.判断栈是否为空
    • 7.释放内存空间
  • 总结


前言

本文章主要介绍栈和队列的相互转换。


使用两个队列实现栈

我们知道,栈的特点是后进先出,而队列的特点是先进先出。

栈的特点:
在这里插入图片描述
队列的特点:
在这里插入图片描述
使用两个队列实现栈的思路是:

1.向两个队列中的任一队列放入元素
2.取出元素时,队列的功能是先进先出,要达到后进先出,需要将前面的所有元素取出,存入另一个空队列中,然后将剩下的最后一个元素释放掉即可。

比如:
在这里插入图片描述
后面如果想继续插入元素的话,应该将插入的元素放在非空队列中,这样就实现了栈的功能。

在这里插入图片描述

这样实现的原因是,两个队列中必有其中一个队列是空队列,保证了栈的后进先出的特点。

下面给出一道题目
两个队列实现栈
在这里插入图片描述
这里我用c语言来实现,所以先先写好队列的基本功能,再将接口函数引入。

1.队列接口函数引入

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

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

void QueueInit(Queue* pq);
void QueueDestroy(Queue* pq);
void QueuePush(Queue* pq, QDataType x);
void QueuePop(Queue* pq);
QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);
bool QueueEmpty(Queue* pq);
int QueueSize(Queue* pq);
void QueueInit(Queue* pq)
{
	assert(pq);

	pq->head = NULL;
	pq->tail = NULL;
	pq->size = 0;
}

void QueueDestroy(Queue* pq)
{
	assert(pq);

	QNode* cur = pq->head;
	while (cur)
	{
		QNode* del = cur;
		cur = cur->next;

		free(del);
		//del = NULL;
	}

	pq->head = pq->tail = NULL;
	pq->size = 0;
}

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);

	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}

	newnode->data = x;
	newnode->next = NULL;

	if (pq->tail == NULL)
	{
		pq->head = pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;
	}

	pq->size++;
}

void QueuePop(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));

	if (pq->head->next == NULL)
	{
		free(pq->head);
		pq->head = pq->tail = NULL;
	}
	else
	{
		QNode* del = pq->head;
		pq->head = pq->head->next;

		free(del);
	}

	pq->size--;
}

QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));

	return pq->head->data;
}

QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));

	return pq->tail->data;
}

bool QueueEmpty(Queue* pq)
{
	assert(pq);

	return pq->head == NULL && pq->tail == NULL;
}

// 1G = 1024MB
// 1024MB = 1024*1024KB
// 1024*1024KB = 1024*1024*1024Byte

int QueueSize(Queue* pq)
{
	assert(pq);

	/*int size = 0;
	QNode* cur = pq->head;
	while (cur)
	{
		cur = cur->next;
		++size;
	}

	return size;*/

	return pq->size;
}

2.栈的初始化

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

栈的初始化就是将两个队列进行初始化。

3.向栈中插入元素

保证其中一个队列不为空
//首先需要判断哪个队列为空,可以用ifelse来判断,但是这样操作冗余的,所以可以使用假设
int myStackPop(MyStack*
void myStackPush(MyStack* obj, int x) {
    if(!QueueEmpty(&obj->q1))
    {
        QueuePush(&obj->q1,x);
    }
    else
    {
        QueuePush(&obj->q2,x);
    }
}

由于无法得知哪一个队列为空,则需要判断或者假设,使用判断的化,代码比较冗余,在这里我使用假设,假设第一个队列是空。

4.出栈操作

int myStackPop(MyStack* obj) {
    Queue*EmptyQ = &obj->q1;
    Queue*NonEmptyQ = &obj->q2;
    if(!QueueEmpty(&obj->q1))
    {
        //如果q1不为空,返回假,!就返回真,进入if
        //意思就是我们假设错误了。
        EmptyQ = &obj->q2;
        NonEmptyQ = &obj->q1;
    }
    //来到这里已经知道哪个是空了,把所有元素导入非空队列,将最后一个不导
    while(QueueSize(NonEmptyQ)>1)
    {
        QueuePush(EmptyQ,QueueFront(NonEmptyQ));
        QueuePop(NonEmptyQ);
    }
    int top = QueueFront(NonEmptyQ);
    QueuePop(NonEmptyQ);
    return top;

}

5.取出栈顶元素

int myStackTop(MyStack* obj) {
    //取出栈顶元素
    //在首先的队列中,我们虽然不能删除队尾元素,但是我们可以取出队尾的元素
    if(!QueueEmpty(&obj->q1))
    {
        return QueueBack(&obj->q1);
    }
    else
    {
        return QueueBack(&obj->q2);
    }
}

6.判断栈是否为空

bool myStackEmpty(MyStack* obj) 
{   
    //判断栈是否为空,需要判断两个队列是否为空
    return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}

判断栈是否为空,需要判断两个队列是否为空

7.释放内存空间

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

注意,由于两个队列的维护是依靠指针,所以两个队列申请的空间先释放,再释放栈结构体空间


总结

本文章介绍了两个队列实现栈的方法。
使用队列实现栈和使用栈实现队列都是可以的
下篇文章介绍使用两个栈实现队列

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

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

相关文章

[工具笔记]1.UnityEngine.Plane

public struct Plane : IFormattable{} Plane是存在于 3D 空间中,无限大的平坦表面,将空间划分为两半(称为半空间)。可方便地确定特定点处于两个半空间的哪一个中,以及确定该点与平面相距多远。 此对象在unity并不可见…

一分钟掌握技术术语:API(接口)

很多产品经理在项目开发过程中经常听到:你调我这个接口就好了;这个功能你写个接口给我;有什么不懂的就看下API接口文档。 开发经常说的接口是什么意思呢?术语解释:API(Application Programming Interface&…

【C++】泛型编程——模板初阶

文章目录1. 泛型编程2. 函数模板2.1 函数模板的概念2.2 函数模板的使用2.3 函数模板的原理2.4 函数模板的实例化隐式实例化显式实例化2.5 模板参数的匹配原则3. 类模板1. 泛型编程 首先我们来思考一个问题:如何实现一个通用的交换函数呢? 即我们想交换两…

神经网络中的激活函数

文章目录为什么要使用激活函数常用的激活函数如何选择激活函数ReLU激活函数的优点及局限性为什么Sigmoid和Tanh会导致梯度消失的问题为什么Tanh收敛速度⽐Sigmoid快?为什么要使用激活函数 在真实情况中,我们往往会遇到线性不可分问题,需要非…

汇编指令学习(MOV,MOVSX,MOVZX,LEA,XCHG)

一、MOV指令1、将十六进制0x1234数值,赋值给eax寄存器mov eax,0x12342、将十六进制0x123数值,赋值给内存地址为ebxmov dword [ebx],0x1233、将edx的高八位赋值给eax的低八位ax,eax的低16位,al,eax的低8位,a…

RedisTemplate 的基本使用手把手教

下载实例源码 使用步骤 1、引入 spring-boot-starter-data-redis 依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId> </dependency>2、在 application.yml 配置 R…

一文分析Linux虚拟化KVM-Qemu之virtqueue

说明&#xff1a; KVM版本&#xff1a;5.9.1QEMU版本&#xff1a;5.0.0工具&#xff1a;Source Insight 3.5&#xff0c; Visio 1. 概述 前边系列将Virtio Device和Virtio Driver都已经讲完&#xff0c;本文将分析virtqueue&#xff1b;virtqueue用于前后端之间的数据交换&…

[4.10]-AutoSAR零基础学习-Secure Debug(SHE+)(一)

目录 1 内部调试保护概述 2 UCB confirmation AURIXTM 设备提供多个安全保护层&#xff0c;以限制调试器访问整个微控制器。 保护层的配置基于用户配置块 UCB&#xff0c;存在于DFlash上&#xff08;DF_UCB&#xff09;。UCB 包含保护设置参数和其他可由用户配置的参数。 DF_…

使用Python对excel中的数据进行处理

一、读取excel中的数据首先引入pandas库&#xff0c;没有的话使用控制台安装 —— pip install pandas 。import pandas as pd #引入pandas库&#xff0c;别名为pd#read_excel用于读取excel中的数据&#xff0c;这里只列举常用的两个参数&#xff08;文件所在路径&#xff…

华为OD机试模拟题 用 C++ 实现 - 连续子串(2023.Q1)

最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 最多获得的短信条数(2023.Q1)) 文章目录 最近更新的博客使用说明连续子串题目输入输出示例一输入输出说明Code使用说明 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。 华为 OD …

SQL Server开启CDC的完整操作过程

这里写自定义目录标题写在前面SQL Server开启CDC1. 将指定库的实例先开启CDC2. 开启需要开启CDC的表3. 关闭CDC功能更详细信息参照官网写在前面 鉴于老旧数据的结构和项目都在sqlserver上存储&#xff0c;且迁移成本巨大&#xff0c;当下要为sqlserver的存储过程减负。要将一部…

深入理解Spring MVC下

上一篇博客从理论概念上来梳理Spring MVC相关知识&#xff0c;此篇博客将通过spring官网提供showcase代码为例子&#xff0c;详细介绍showcase代码中包含的各个例子是如何实现的。官网的showcase代码包含的主要例子包括&#xff0c;Demo地址&#xff1a;Mapping Requests&#…

2023王道考研数据结构笔记第一章绪论

第一章 绪论 1.1 数据结构的基本概念 1.数据&#xff1a;数据是信息的载体&#xff0c;是描述客观事物属性的数、字符以及所有能输入到计算机中并被程序识别和处理的符号的集合。 2.数据元素&#xff1a;数据元素是数据的基本单位&#xff0c;通常作为一个整体进行考虑和处理…

【LeetCode】2363. 合并相似的物品

2363. 合并相似的物品 题目描述 给你两个二维整数数组 items1 和 items2 &#xff0c;表示两个物品集合。每个数组 items 有以下特质&#xff1a; items[i] [valuei, weighti] 其中 valuei 表示第 i 件物品的 价值 &#xff0c;weighti 表示第 i 件物品的 重量 。items 中每…

cpp之STL

STL原理 STL ⼀共提供六⼤组件&#xff0c;包括容器&#xff0c;算法&#xff0c;迭代器&#xff0c;仿函数&#xff0c;适配器和空间配置器&#xff0c;彼此可以组合套⽤。容器通过配置器取得数据存储空间&#xff0c;算法通过迭代器存取容器内容&#xff0c;仿函数可以协助算…

电子科技大学软件工程期末复习笔记(九):项目管理

目录 前言 重点一览 软件项目管理的四大要素 团队组织方式 虚拟团队 软件范围 项目计划 P-CMM的5个级别 本章小结 前言 本复习笔记基于王玉林老师的课堂PPT与复习大纲&#xff0c;供自己期末复习与学弟学妹参考用。 重点一览 本节是软件工程复习笔记的最后一篇&…

Hive---Zeppelin安装教程

Zeppelin安装教程 安装zeppelin必须基于Hadoop和Hive上 文章目录Zeppelin安装教程简介安装步骤1.上传zeppelin压缩包2.解压并更名3.修改配置文件编辑zeppelin-site.xml---将配置文件的ip地址和端口号进行修改编辑 zeppelin-env.sh---添加JDK和Hadoop环境拷贝hive文件切换目录拷…

数据结构与算法(六):图结构

图是一种比线性表和树更复杂的数据结构&#xff0c;在图中&#xff0c;结点之间的关系是任意的&#xff0c;任意两个数据元素之间都可能相关。图是一种多对多的数据结构。 一、基本概念 图&#xff08;Graph&#xff09;是由顶点的有穷非空集合和顶点之间边的集合组成&#x…

嵌入式小白的进阶之路

学习嵌入式采用的是2021年华清远见嵌入式课程 安装虚拟机 &#xff1a; 懒人版 目标&#xff1a;快速上手 问题一&#xff1a; 在Linux虚拟环境中运行一个c语言程序步骤 1、激活虚拟环境&#xff1a;source venv/bin/activate 2、进入Hello文件夹&#xff1a;cd Hello 3、新…

【Python学习笔记】第二十节 Python 网络编程

Python 网络编程简单来说&#xff0c;网络是用物理链路将各个孤立的工作站或主机相连在一起&#xff0c;组成数据链路&#xff0c;从而达到资源共享和通信的目的。所谓的网络编程就是&#xff0c;让在不同的电脑上的软件能够进行数据传递&#xff0c;即进程之间的通信Python 提…