用队列实现栈(C语言版本)

news2025/1/18 13:55:48

在这里插入图片描述

🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨
🐻强烈推荐优质专栏: 🍔🍟🌯C++的世界(持续更新中)
🐻推荐专栏1: 🍔🍟🌯C语言初阶
🐻推荐专栏2: 🍔🍟🌯C语言进阶
🔑个人信条: 🌵知行合一

目录

  • 前言
  • 一、题目介绍
      • (1) 模拟栈的结构:
      • (2 初始化模拟栈(myStackCreate)
      • (3) 压栈(myStackPush)
      • (4) 出栈(myStackPop)
      • (5) 栈顶元素(myStackTop)
      • (6) 栈空(myStackEmpty)
      • (7)栈的释放(myStackFree)
  • 二、总代码示例:
    • 手撕队列的源码

前言

在做这个题目之前,应当熟悉队列这两种数据结构.栈和队列都是常见的数据结构,它们是基于数组或链表实现的线性数据结构。

栈(Stack):
栈是一种后进先出(Last-In-First-Out,LIFO)的数据结构,只允许在栈顶进行插入和删除操作。栈的基本操作包括入栈(push)、出栈(pop)、查看栈顶元素(top)和判断栈是否为空(empty)。

应用场景:实现程序调用的函数堆栈、表达式求值、括号匹配检验等。

队列(Queue):
队列是一种先进先出(First-In-First-Out,FIFO)的数据结构,只允许在队尾插入元素,在队头删除元素。队列的基本操作包括入队(enqueue)、出队(dequeue)、查看队头元素(front)和判断队列是否为空(empty)。

一、题目介绍

题目来源于–力扣
题目链接:传送门

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

实现 MyStack 类:

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

(1) 模拟栈的结构:

模拟栈的结构定义为两个队列

typedef struct {
    Queue q1;
    Queue q2;
} MyStack;

在这里插入图片描述

(2 初始化模拟栈(myStackCreate)

调用两个栈对应的初始化函数.

代码实现:

MyStack* myStackCreate() {
    MyStack* stack=( MyStack*)malloc(sizeof(MyStack));//开辟栈所占的空间(两个队列)
    //初始化栈
    QueueInit(&stack->q1);
    QueueInit(&stack->q2);
    return stack;
}

(3) 压栈(myStackPush)

对于入栈操作,谁是空队列,就往这个队列中正常压数据,模拟压栈的过程.
在这里插入图片描述

代码实现:

void myStackPush(MyStack* obj, int x) {
    if(!QueueEmpty(&obj->q1))//如果其中一个队列是空,就往空的队列中插入元素
    {
        QueuePush(&obj->q1,x);
    }
    else{
        QueuePush(&obj->q2,x);
    }
}

(4) 出栈(myStackPop)

出队列相对麻烦一些:

  1. 倒数据,将非空队列中的数据只保留队尾数据以外,其他全部导入另一个队列(空).
  2. 保存队尾数据.
  3. 将剩余的队尾数据出栈,并返回队尾.

在这里插入图片描述
在这里插入图片描述

代码实现:

int myStackPop(MyStack* obj) {
    Queue* empty=&obj->q1;//假设q1是空队列
    Queue* Notempty=&obj->q2;
    if(!QueueEmpty(&obj->q1))//如果假设错误,则说明q2才是空队列
    {
        empty=&obj->q2;
        Notempty=&obj->q1;
    }
    //将除了最后一个要删除的元素以外其他元素,倒数据到空队列
    while(QueueSize(Notempty)>1)
    {
        //将有元素的队列中的队头的值放入空队列中
        QueuePush(empty,QueueFront(Notempty));
        //弹出这个队头元素
        QueuePop(Notempty);
    }
    int top=QueueFront(Notempty);
    QueuePop(Notempty);//删除剩下的最后一个元素.
   
    return top;
}

(5) 栈顶元素(myStackTop)

哪个队列有数据,则将这个队列的队尾元素返回即可.

在这里插入图片描述
代码实现:

int myStackTop(MyStack* obj) {
    if(!QueueEmpty(&obj->q1))//找到有元素的队列,将其队列尾部的数据打印出来
    {
        return QueueBack(&obj->q1);
    }
    else{
        return QueueBack(&obj->q2);
    }
}

(6) 栈空(myStackEmpty)

两个队列中都没有数据则表示栈为空.

代码实现:

bool myStackEmpty(MyStack* obj) {
   if(QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2))//如果都为空,则为空栈
    {
        return true;
    }
    else 
    return false;
    
    //return QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2);
}

(7)栈的释放(myStackFree)

代码实现:

void myStackFree(MyStack* obj) {
    //先释放栈中申请的链式队列
    QueueDestroy(&obj->q1);
    QueueDestroy(&obj->q2);
    //最后释放栈这个结构体
    free(obj);
}

二、总代码示例:

//手撕队列
/*
...
*/

typedef struct {
    Queue q1;
    Queue q2;
} MyStack;

MyStack* myStackCreate() {
    MyStack* stack=( MyStack*)malloc(sizeof(MyStack));//开辟栈所占的空间(两个队列)
    //初始化栈
    QueueInit(&stack->q1);
    QueueInit(&stack->q2);
    return stack;
}

void myStackPush(MyStack* obj, int x) {
    if(!QueueEmpty(&obj->q1))//如果其中一个队列是空,就往空的队列中插入元素
    {
        QueuePush(&obj->q1,x);
    }
    else{
        QueuePush(&obj->q2,x);
    }
}

int myStackPop(MyStack* obj) {
    Queue* empty=&obj->q1;//假设q1是空队列
    Queue* Notempty=&obj->q2;
    if(!QueueEmpty(&obj->q1))//如果假设错误,则说明q2才是空队列
    {
        empty=&obj->q2;
        Notempty=&obj->q1;
    }
    //将除了最后一个要删除的元素以外其他元素,倒数据到空队列
    while(QueueSize(Notempty)>1)
    {
        //将有元素的队列中的队头的值放入空队列中
        QueuePush(empty,QueueFront(Notempty));
        //弹出这个队头元素
        QueuePop(Notempty);
    }
    int top=QueueFront(Notempty);
    QueuePop(Notempty);//删除剩下的最后一个元素.
   
    return top;
}

int myStackTop(MyStack* obj) {
    if(!QueueEmpty(&obj->q1))//找到有元素的队列,将其队列尾部的数据打印出来
    {
        return QueueBack(&obj->q1);
    }
    else{
        return QueueBack(&obj->q2);
    }
}

bool myStackEmpty(MyStack* obj) {
   if(QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2))//如果都为空,则为空栈
    {
        return true;
    }
    else 
    return false;
    
    //return QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2);
}

void myStackFree(MyStack* obj) {
    //先释放栈中申请的链式队列
    QueueDestroy(&obj->q1);
    QueueDestroy(&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);
*/

手撕队列的源码

//手撕队列
typedef int QDatatype;

typedef struct QueueNode
{
	struct QueueNode* next;
	QDatatype data;
}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);
int QueueSize(Queue* pq);
bool QueueEmpty(Queue* pq);
QDatatype QueueFront(Queue* pq);
QDatatype QueueBack(Queue* pq);
void QueueInit(Queue* pq)//队列的初始化
{
	assert(pq);
	pq->head = pq->tail = NULL;
	pq->size = 0;
}

void QueueDestroy(Queue* pq)//销毁队列操作
{
	assert(pq);
	QNode* cur = pq->head;
	QNode* next = cur;
	while (next)
	{
		next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = pq->tail = NULL;
	pq->size = 0;
}

void QueuePush(Queue* pq, QDatatype x)//入队列操作
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	newnode->data = x;
	newnode->next = NULL;
	if (newnode == NULL)
	{
		perror("newnode malloc fail:");
		return;
	}
	if (pq->head == NULL)//第一次插入
	{
		assert(pq->tail==NULL);
		pq->head = pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
    pq->size++;
}
bool QueueEmpty(Queue* pq)//队列的判空操作
{
	assert(pq);
	if (pq->head == pq->tail && pq->head == NULL)
	{
		return true;
	}
	return false;
}
void QueuePop(Queue* pq)//出队列
{
	assert(pq);
	assert(!QueueEmpty(pq));
	if (pq->head->next == NULL)//代表还剩下一个结点
	{
		free(pq->head);//释放这个结点.
		pq->head = pq->tail = NULL;
	}
	else
	{
		QNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}
    pq->size--;
}

int QueueSize(Queue* pq)//队列元素的大小
{
	assert(pq);
	return pq->size;
}
QDatatype QueueFront(Queue* pq)//队首元素
{
	assert(pq);
	assert(pq->head);
	return pq->head->data;
}
QDatatype QueueBack(Queue* pq)//队尾元素
{
	assert(pq);
	assert(pq->head);
	return pq->tail->data;
}

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

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

相关文章

ArcGIS 10.5安装教程!

软件介绍: ArcGIS Desktop 10.5中文特别版是一款功能强大的GSI专业电子地图信息编辑和开发软件,ArcGIS Desktop 包括两种可实现制图和可视化的主要应用程序,即 ArcMap 和 ArcGIS Pro。ArcMap 是用于在 ArcGIS Desktop 中进行制图、编辑、分析…

滴滴:二季度中国出行营收同比增长57%,6月日均单量超3000万单

9月9日,滴滴在其官网发布2023年第二季度业绩报告,二季度滴滴实现总收入488亿元,同比增长52.6%;归属于滴滴普通股股东的净亏损为3亿元,经调整EBITA亏损1000万元。 分业务来看,二季度滴滴中国出行&#xff0…

北京运营《乡村振兴战略下传统村落文化旅游设计》许少辉八一新书

北京运营《乡村振兴战略下传统村落文化旅游设计》许少辉八一新书

当所有行业都在数字化转型时,企咨行业如何快速“破局”

党的二十大报告指出,“加快发展数字经济,促进数字经济和实体经济深度融合,打造具有国际竞争力的数字产业集群。”随着新一轮科技革命和产业变革深入发展,数字化转型已经不是一道“选择题”,而是一堂“必修课”。 数字…

国产触控笔哪个牌子好?开学平价好用触控笔排行榜

很多学生在新学期的时候,都会用到电容笔,这说明电容笔的重要性。苹果推出了ipad专用的电容笔后,这种电容笔便成为了市场上最热门的产品,只是因为Apple Pencil的价格过于昂贵,所以很多人并没有购买得起。所以&#xff0…

一文读懂官方给出torch.nn.RNN API的参数及手写RNN API复现

理论部分 官方给出的文档解释: 计算公式: 该公式对应的结构框图: 其中 xt 表示当前 t 时刻的输入,Wih表示 “输入层” 到 “隐藏层” 的权重矩阵。即 Wih 会将输入映射至隐藏层。bih表示输入层到隐藏层的偏置,ht-1表…

【我的第一千篇文章】

作为一名Java开发者,我很自豪地宣布,这里是我输出的第一千篇文章。在过去的六年里,我一直坚持每月输出优质内容,并将其分享给了全世界的读者们。这一千篇文章中,有很多关于Java编程的技巧、经验分享、优秀实践示例、案…

16 “count(*)“ 和 “count(1)“ 和 “count(field1)“ 的差异

前言 经常会有面试题看到这样的问题 “ select count(*) ”, “ select count(field1) ”, “ select count(1) ” 的效率差异啥的 然后 我们这里 就来探索一下 这个问题 我们这里从比较复杂的 select count(field1) 开始看, 因为 较为复杂的处理过程 会留一下一些关键的调试…

C4D国潮场景3D模型合集

110个国潮场景3D模型,C4D源文件,部分效果图如下: 微信扫描下方二维码 回复关键字获取 100004

神经网络输出中间特征图

在进行神经网络的训练过程中,会生成不同的特征图信息,这些特征图中包含大量图像信息,如轮廓信息,细节信息等,然而,我们一般只获取最终的输出结果,至于中间的特征图则很少关注。 前两天师弟突然…

第24章 互斥锁实验(iTOP-RK3568开发板驱动开发指南 )

在上一章节中对信号量进行了学习,而本章节要学习的互斥锁可以说是“量值”为 1 的信号量,最终实现的效果相同,既然有了信号量,那为什么还要有互斥锁呢,带着疑问,让我们来进行本章节的学习吧! 2…

古尔曼表示不服?郭明錤:苹果可能不会在10月发布M3芯片的机型

9月9日消息,据天风证券分析师郭明錤所言,苹果可能不会在今年发布搭载M3芯片的MacBook Air/Pro机型。这一说法与此前彭博社的马克古尔曼所透露的消息有所不同。根据古尔曼的消息,苹果最快在10月会发布M3款苹果MacBook Air和Pro电脑。他表示&am…

美国封锁激励中国制造业数字化转型的崛起 | 百能云芯

上海在近日公布了第二批工赋链主培育企业名单,共有15家企业入选。这些被称为“链主”的企业在上海制造业数字化转型的过程中扮演着关键角色,类似于领头大雁,它们是上海制造业的数字化网络中的关键节点。 中新社的报道指出,“数字技…

软件源码开发,网络中的“摄像头”:运维监控系统

在日常生活中,我们不管是在大街小巷,还是在商场大厦都可以见到一个圆形或是方形带有镜片的“小盒子”,这个“小盒子”就是摄像头,摄像头作为一个能实时录制记录它能照到范围内的视频图像的工具,可以在丢失物品、抓捕坏…

判断动物知识竞猜答案正误

判断动物知识竞猜答案正误 教学目标 1. 知识与技能: 结合实例,理解选择结构。掌握if语句的基本格式,掌握关系运算符。 过程与方法: 学会使用if编程解决实际生活中的一些问题。 情感态度与价值观: 教…

通讯软件018——分分钟学会UaExpert OPC UA Client配置

本文介绍如何配置UaExpert OPC UA Client,通过本文可以对OPC UA的基本概念有所了解,掌握OPC UA的本质。相关软件请登录网信智汇(wangxinzhihui.com)。 创建OPC UA 连接 这里需要掌握一下OPC UA的安全机制。 1)安全模式: OPC UA安…

史上最详细的PyCharm安装教程,小白建议收藏!

前言:Hello大家好,我是小哥谈。PyCharm是由JetBrains公司开发的一款Python开发工具,在Windows、Mac OS和Linux操作系统中都可以使用,它具有语法高亮显示、Project(项目)管理、代码跳转、智能提示、自动完成…

初识集合框架 -Java

目录 一、集合框架的概念 二、集合框架的重要性 三、涉及的数据结构和算法 3.1 什么是数据结构 3.2 集合框架(容器)背后对应的数据结构 3.3 相关的Java知识 3.4 什么是算法 3.5 如何学好数据结构和算法 一、集合框架的概念 Java 集合框架,…

【图卷积神经网络】1-入门篇:为什么使用图神经网络(下)

为什么使用图神经网络? 在本书中,我们将重点介绍图学习技术中的深度学习家族,通常称为图神经网络。GNNs是一种新的深度学习架构类别,专门设计用于处理图结构化数据。与主要用于文本和图像的传统深度学习算法不同,GNNs明确地用于处理和分析图数据集(见图1.4)。 图1.4 - …

Vue3+Ts+Vite项目(第一篇)——使用Vite创建Vue3项目

概述 保姆级详解,带你使用 Vite 创建 Vue3 项目,全程cv即可 文章目录 概述一、 安装 Vite二、 创建项目2.1 运行上述命令后,会让我们输入项目名称。可以写一个 vue3-study2.2 选择项目模板,此处选择 Vue,然后回车确定…