用队列实现栈

news2024/11/25 0:31:01

题目:

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

准备工作

这题明确说明了需要用队列来实现栈,介于C语言没有队列的库,所以在此之前我们需要用调用之前学的队列,详见队列

typedef int QDataType;

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

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

void QueueInit(Queue* pq);
void QueueDestory(Queue* pq);

// 队尾入
void QueuePush(Queue* pq, QDataType x);
// 队头出
void QueuePop(Queue* pq);
QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);
int QueueSize(Queue* pq);
bool QueueEmpty(Queue* pq);

void QueueInit(Queue* pq)
{
    assert(pq);
    pq->head = pq->tail = NULL;
}

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

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

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

// 队尾入
void QueuePush(Queue* pq, QDataType x)
{
    assert(pq);
    QNode* newnode = (QNode*)malloc(sizeof(QNode));
    if (newnode == NULL)
    {
        printf("malloc fail\n");
        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;
    }
}

// 队头出
void QueuePop(Queue* pq)
{
    assert(pq);
    assert(pq->head);

    // 1、一个
    // 2、多个
    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;
    }
}


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;
}

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

    return size;
}

bool QueueEmpty(Queue* pq)
{
    assert(pq);
    return pq->head == NULL;
}

看懂题

这样之后,我们有些小伙伴觉得自己英语不好,看不懂那些函数名,从而放弃这题,其实这里和英语好不好是没有太多关系的。注意看:

我们通过观察返回值,从而进一步确认意思。

创建结构体

“typedef struct”这个函数,有过对数据结构的基础认识,看到“struct”肯定是创建结构体。创建出的结构体决定了我们之下来的解题思路。

所以我们先来了解一下实现这题的基本思路:

基本思路

我们如此反复倒数据,每次到最后一个元素就把它pop掉,所以我们避免不了要用到两个指针,指向两个链表的指针。

如此一来“typedef struct”这个函数就容易实现了。

typedef struct 
{
    Queue* q1;
    Queue* q2;

} MyStack;

创建空间

“MyStack* myStackCreate() “:我们有了结构体,一定要初始化,不初始化会导致结构体内部的值不确定,容易出错。现在最新的“vs”如果不初始化,都编译不了了。

MyStack* myStackCreate() 
{
    MyStack* pq = (MyStack*)malloc(sizeof(MyStack));
    if(pq == NULL)
    {
        perror("malloc:");
        exit(-1);
    }
    QueueInit(&pq->q1);
    QueueInit(&pq->q1);
    return pq;
}

入栈

这个比较简单,谁不为空就进谁

void myStackPush(MyStack* obj, int x) 
{
    if(!QueueEmpty(&obj->q1))
    {
        QueuePush(&obj->q1, x);
    }
   else
    {
        QueuePush(&obj->q2, x);
    }
}

出栈

首先我们要注意我们不能知道是q1是空的还是q2是空的,所以我们干脆假设一个是空的,然后再来判断,又由于我们队列是可以直接头删,我们直接倒到空的那一个。

int myStackPop(MyStack* obj) 
{
    Queue* empty = &obj->q1;
    Queue* nonempty = &obj->q2;
    if(!QueueEmpty(&obj->q1))
    {
        empty = &obj->q2;
        nonempty = &obj->q1;
    }
    while(QueueSize(nonempty) > 1)
    {
        QueuePush(empty, QueueFront(empty));
        QueuePop(nonempty);
    }
    //尾部
    int ret = QueueFront(nonempty);
    QueuePop(nonempty);
    return ret;
}

取数据

谁不为空,就尾删(出队列)。

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

判空

两个队列同时为空

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

释放空间

释放两个链表的同时,不要忘记释放两个指针,避免内存泄漏。

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

    free(ps);
    ps = NULL;
}

总结

我们可以发现原理(几幅图就能搞定)都不难,主要是代码的实现,需要注意许多细节,一定要注意避免内存泄漏。

欢迎大家点赞和评论。

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

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

相关文章

Ubuntu上安装 Hadoop 3详细过程(验证+填坑总结)

Ubuntu上安装 Hadoop 3 前提条件: Python 推荐3.8JDK 推荐1.8 解压安装 sudo tar -zxvf hadoop-3.3.0.tar.gz -C /usr/local cd /usr/local sudo mv hadoop-3.3.0 hadoop sudo chown -R hadoop ./hadoop 配置环境变量 vim ~/.bashrc # hadoop export H…

云原生安全系列 5:ETCD 安全加固

引言 etcd是一个强一致性的分布式键值存储,它提供了一种可靠的方式来存储需要被分布式系统或机器集群访问的数据。通过 raft 算法它能在网络分区期间优雅地处理领导者的选举,并能容忍机器故障,甚至在领导者节点上。除此之外, etc…

存储过程的基础知识

本文来简单说下存储过程的基础知识 文章目录概述什么是存储过程存储过程的优缺点概述 mysql官网提供的储存过程:https://www.mysqlzh.com/doc/225/499.html 什么是存储过程 简单的说,存储过程是一条或者多条SQL语句的集合,可视为批文件&…

Windows下更改yarn的安装位置,减小C盘占用

Windows下更改yarn的安装位置,减小C盘占用 绷不住了,yarn的C盘占用太高了,我这C盘感觉以后会受不了,太大了~~(捂脸~~ nnd,撸他,更改yarn的位置开始! 先看看yarn目前的位置 检查当前…

「自控原理」2.4 信号流图与梅逊公式、闭环传递函数

本节引入了信号流图以及梅逊增益公式,可以据此快速对系统进行化简 本节引入了闭环传递函数的概念,并介绍了常用的闭环传递函数 文章目录信号流图的基本概念信号流图与方框图的关系从结构图绘制信号流图从信号流图绘制结构图梅逊(Mason)增益公式Mason公式…

Workfine5.0扩展功能——如何识别身份证信息?

哈喽,我是办公助手小W,又到了跟大家分享办公小技巧的时候啦! 最近Workfine5.0最新版本上线后,大家最感兴趣的就是它的扩展功能了,今天要跟大家分享的就是如何实现身份证信息的提取。 首先咱们先要知道如何下载安装扩…

(第五章)OpenGL超级宝典学习:缓冲

缓冲 前言 本篇在讲什么 关于OpenGL数据缓冲的相关内容 本篇适合什么 适合初学OpenGL的小白 想了解OpenGL缓冲对象的同学 本篇需要什么 对C语法有简单认知 对OpenGL有简单认知 最好是有OpenGL超级宝典蓝宝书 依赖Visual Studio编辑器 本篇的特色 具有全流程的图文…

使用OpenCV透视变换技术实现坐标变换实践

1. 概述 1.1. 需求 在局部空间(无GPS定位)视频监控过程中,把视频识别到物体位置,投射到空间平面坐标系中,获取物体在局部空间的平面坐标。 1.2. 解决方案 使用图像透视变换技术。 1.3. 透视变换概念 透视变换是指…

链路追踪组件Skywalking使用

前言Skywalking是一个国产开源框架,2015年由吴晟开源 , 2017年加入Apache孵化器,其用于追踪多微服务模块调用之间日志的追踪,协助程序员进行排除问题Skywalking架构Skywalking架构图大概如下SkyWalking OAP: SkyWalkin…

如何格式化U盘?以及优盘格式化的恢复方法

我们经常使用U盘来进行存储和传输数据,使用时间久了,可能需要我们进行优盘格式化。需要注意!优盘格式化之前,记得对里面的数据进行备份,防止数据清空造成不必要的损失。 如何进行U盘格式化?格式化优盘后&a…

“深度学习”学习日记。误差反向传播法--加法层、乘法层、激活函数层的实现

2023.1.16 1、加法层、乘法层: 前两篇文章都在讲述理论,今天实现代码操作:关于加法节点,乘法节点的内容在这篇文章。 https://blog.csdn.net/m0_72675651/article/details/128695488 在以后的学习中,将把构建神经网…

AHOcoder声码器

AHOcoder声码器 目前最常见的声码器有WORLD,STRAIGHT,Griffin_Lim等,AHocoder算是少见的,但也可以学习一下。 代码下载网址:AHOcoder 简介 AHOcoder 语音声码器由 Daniel Erro 在巴斯克大学的 AHOLAB 信…

若依配置教程(一)运行若依系统

一、下载源代码 若依的源代码是开源的,所以我们在若依的官方网站即可进行下载,若依的官网是:http://doc.ruoyi.vip/ruoyi-vue/,进入官网后,会显示代码下载的地址:https://gitee.com/y_project/RuoYi-Vue&a…

【进阶】Bean作用域和生命周期

努力经营当下,直至未来明朗! 文章目录一、通过⼀个案例来看 Bean 作⽤域的问题1. 被修改的Bean案例2. 原因分析二、作用域Scope定义1. Bean的六种作用域(重点)1)singleton2)prototype3)request4…

JVM——类加载与字节码技术(2)

三、编译期处理 所谓的 语法糖 ,其实就是指 java 编译器把* .java 源码编译为* .class 字节码的过程中,自动生成和转换的一些代码,主要是为了减轻程序员的负担,算是 java 编译器给我们的一个额外福利 【注意】以下代码的分析&am…

Python爬虫之基于 selenium 实现文献信息获取

目录初识 selenium网页分析代码实现踩过的坑最近有小伙伴后台跟我说,临近毕业,写毕业论文需要上知网查找大量的文献,但是一篇一篇看文献信息以及文献摘要又有点麻烦,能不能让我写一个爬虫去批量获取文献相关信息 我一听好家伙&am…

【算法】二叉树遍历

目录1.概述2.代码实现2.1.二叉树定义2.2.前序遍历2.3.中序遍历2.4.后序遍历2.5.层序遍历3.应用本文参考: LABULADONG 的算法网站 1.概述 (1)所谓遍历 (Traversal) 是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问…

《从零开始编写一个直播服务器》 C++ 实现一个最简单的HTTP-FLV流媒体服务器

流媒体服务系列文章 文章目录流媒体服务系列文章前言一、http flv?二、使用步骤服务器代码总结前言 HTTP FLV通过http传输,时延可控制在2秒以内,浏览器可基于bilibili开源的flv.js(采用h5 mse技术)开发,比起rtsp、rtmp等免插件播…

Spring BeanPostProcessor

BeanPostProcessor,是bean的增强器,在bean初始化前后调用,常用的方法有postProcessBeforeInitialization和postProcessAfterInitialization,在Spring启动并初始化bean前后通过它们做一些扩展操作。 1、BeanPostProcessor 接口说明…

【信管9.1】​项目沟通及过程

项目沟通及过程沟通这个东西,可以说是整个项目成功失败最关键的因素。9成以上失败的项目在最后总结的时候,沟通不畅或者信息对接问题都会占据前三甲。其实只要是做项目,那么必须有团队,有团队有人,那么沟通就是不可避免…