OJ题讲解——栈与队列

目录

一.有效的括号

1.问题描述

2.问题详解

3.代码

二.用队列实现栈

1.问题描述

2.问题详解

3.代码

三.用栈实现队列

1.问题描述

2.问题详解

3.代码

四.设计循环队列

1.问题描述

2.问题详解

3.代码


一.有效的括号

1.问题描述

OJ链接:. - 力扣(LeetCode)

2.问题详解

对于这道题,采用栈来解决

1.如果是左括号就入栈

2.如果是右括号,取栈顶元素与之匹配

        2.1 当栈里面为空时,表明右括号多了,没有左括号与之匹配,返回false

        2.2 由于匹配的情况有很多种,无法一一列全,于是我们来判断不匹配的情况,当左右括号不匹配就返回false

        2.3 当所有的右括号匹配完后还要检查栈是否为空,可能还有左括号没有匹配

3.代码

注意;

本篇博客都是在c语言的环境下,当涉及到用栈和队列,需要用户自己先创建栈或队列

bool isValid(char* s) {
    //1.左括号入栈
    //2.右括号与出栈顶的左括号匹配
    ST st;
    STInit(&st);
    while(*s)
    {
        //左括号入栈
        if(*s=='('||*s=='['||*s=='{')
        {
            STPush(&st,*s);
        }
        else//右括号与出栈顶的左括号匹配
        {
            if(STEmpty(&st))
            {
                STDestroy(&st);
                return false;
            }

            char top=STTop(&st);
            STPop(&st);
            
            //不匹配的情况·
            if((top=='('&&*s!=')')
            ||(top=='['&&*s!=']')
            ||(top=='{'&&*s!='}'))
            {
                STDestroy(&st);
                return false;
            }
        }
        s++;
    }
    //栈不为空,说明左括号比右括号多,不匹配
    bool ret=STEmpty(&st);
    STDestroy(&st);

    return ret;
}

二.用队列实现栈

1.问题描述

OJ链接:. - 力扣(LeetCode)

2.问题详解

1.先创建一个结构体,里面存储俩个队列

2.对于实现栈push,top,pop,empty四个操作中,最麻烦的是pop操作,因为队列pop的是队头元素,而栈pop的是栈顶元素,因此我们需要用到俩个队列,保持一个队列存数据,一个队列为空,pop数据需要通过空队列导一下,将前size-1个数据按顺序边导到空队列中边删除掉,将最后一个数据保存后再删除掉,这样就获取栈顶的数据并且pop成功

3.top操作可以直接返回非空队列的队尾元素

4.push操作直接导入不为空的队列中

5.empty操作需要对俩个队列都进行判空操作

3.代码

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) {
    //假设法
    Queue*empty=&(obj->q1);
    Queue*nonempty=&(obj->q2);
    if(!QueueEmpty(&(obj->q1)))
    {
        empty=&(obj->q2);
        nonempty=&(obj->q1);
    }

    //将有数据的队列的前size-1个导到空队列
    while(QueueSize(nonempty)>1)
    {
        QueuePush(empty,Queuefront(nonempty));
        QueuePop(nonempty);
    }

    int top= Queuefront(nonempty);
    QueuePop(nonempty);

    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) {

    QueueDestroy(&(obj->q1));
    QueueDestroy(&(obj->q2));

    free(obj);
}


三.用栈实现队列

1.问题描述

OJ链接:. - 力扣(LeetCode)

2.问题详解

创建俩个栈,分别为pushst和popst,pushst用来插入数据,popst用来导数据,删除队头元素(注意:与上问题的俩个队列不同,用队列实现栈需要俩个队列相互导数据,保证一个队列始终为空,而这个问题不需要俩个栈相互导数据),如下图所示:

通过上面的三个步骤,我们可以看出,当popst栈中为空,又需要pop队头元素时,我们直接将pushst栈中的元素导导popst栈中,然后删除的栈顶元素就是队头元素,同时当pushst和popst中都有元素,又想删除队头元素时,我们不需要再将pushst栈中的元素导到popst栈中去,只需要删除popst栈顶元素就好了。因此,插入数据只需要插入到pushst中,而删除队头数据,只有当popst栈中没有元素时,才需要将pushst中的元素全部导入popst中去,再删除栈顶元素

3.代码

typedef struct {
    ST pushst;//用来输入数据
    ST popst;//用来倒数据,实现删除
} MyQueue;


MyQueue* myQueueCreate() {
    MyQueue*obj=(MyQueue*)malloc(sizeof(MyQueue));

    STInit(&(obj->pushst));
    STInit(&(obj->popst));

    return obj;
}

void myQueuePush(MyQueue* obj, int x) {
    STPush(&(obj->pushst),x);
}

int myQueuePop(MyQueue* obj) {
    int top=myQueuePeek(obj);
    STPop(&(obj->popst));

    return top;
}

int myQueuePeek(MyQueue* obj) {
    if(STEmpty(&(obj->popst)))
    {
        //倒数据
        while(!STEmpty(&(obj->pushst)))
        {
            int top=STTop(&(obj->pushst));
            STPush(&(obj->popst),top);
            STPop(&(obj->pushst));
        }
    }

    return STTop(&(obj->popst));
}

bool myQueueEmpty(MyQueue* obj) {
    return STEmpty(&(obj->pushst))&&STEmpty(&(obj->popst));
}

void myQueueFree(MyQueue* obj) {
    STDestroy(&(obj->pushst));
    STDestroy(&(obj->popst));

    free(obj);
}

四.设计循环队列

1.问题描述

OJ链接:. - 力扣(LeetCode)

2.问题详解

循环队列是一种空间大小固定,空间能够反复利用的队列,这个队列也可以采用链表和数组来实现。

首先分析链表,用链表的优势在于它可以实现循环,但是创建链表要比队列大小多开一个节点,避免假溢出问题,因为head和tail初始化为头节点,tail实际表示的是最后一个数据指向的下一个节点。而链表的难点在于尾节点的获取,如果是单链表就需要从头开始遍历节点,增加了时间复杂度,或者再定义一个指针指向tail前一个节点,如果是双向链表恰好可以解决这个问题。

如果用数组来实现的话,当head和tail都初始化为0,我们来看看这个式子head==tail表示的是什么?好像表示队列满了又好像队列为空?这意思不矛盾了吗!对于解决这个有俩个办法,一是再定义一个size记录队列中元素的个数和队列空间大小进行比较,二是再开一个空间,当head==tail为空,当(tail+1)%(k+1)==head为满,而在本题,采用的是第二种解法,额外开辟一个空间。

注意:

插入和删除数据时,要确保这个队列是循环的,我们一定要tail=tail%(k+1),同时,在获取队尾元素时,也要时刻注意tail,确保能够形成一个循环队列

3.代码

typedef struct {
    int* a;
    int head;//指向头
    int tail;//指向尾的下一个位置
    int k;
} MyCircularQueue;

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return obj->head==obj->tail;
}

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    return (obj->tail+1)%(obj->k+1)==obj->head;
}

MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue*obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));

    //多开一个解决假溢出
    obj->a=(int*)malloc(sizeof(int)*(k+1));
    obj->head=0;
    obj->tail=0;
    obj->k=k;

    return obj;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(myCircularQueueIsFull(obj))
    {
     return false;
    }

    obj->a[obj->tail]=value;
    obj->tail++;

    obj->tail%=(obj->k+1);

    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
        return false;

    obj->head++;
    obj->head%=(obj->k+1);

    return true;
}

int myCircularQueueFront(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
        return -1;
    else
        return obj->a[obj->head];
}

int myCircularQueueRear(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    return -1;

    int real=obj->tail==0?obj->k:obj->tail-1;
    return obj->a[real];

   //return obj->a[(obj->tail+obj->k)%(obj->k+1)];
}


void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->a);
    free(obj);
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

归并排序(分治)

归并排序 概念介绍原理解释:案例步骤:稳定性:画图理解如下 代码实现 概念介绍 归并排序(Merge Sort)是一种经典的排序算法,基于分治的思想,它将待排序数组分成两个子数组,分别排序&…

基于Python+django购物商城系统设计和实现(源码+LW+部署文档+讲解等)

💗博主介绍:✌全网粉丝1W,CSDN作者、博客专家、全栈领域优质创作者,博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌💗 🌟文末获取源码数据库🌟 感兴趣的可以先收藏起来,还…

iPhone的5G设置怎么更改吗?设置好这些能够优化电池的使用寿命

随着5G技术的普及,iPhone用户现在可以享受到更快的网络速度,但这同时也带来了一个问题:如何在使用5G和保持电池寿命之间找到平衡?苹果公司通过引入“5G Auto”设置,为用户提供了一个智能的解决方案,但用户也…

3D模型轻量化:无损精度和细节,轻量化处理3D模型的云原生工具

随着科技的不断发展,三维模型在各个领域的应用愈加广泛。然而,传统的CAD工具生成的模型往往包含大量的面片和数据,这在进行模型查看、分享、协作以及在线展示时带来了诸多不便。模型文件过大不仅导致传输速度慢,还可能因为文件格式…

移远通信携手高通,共启智能出行新时代

5月30-31日,2024高通汽车技术与合作峰会在无锡国际会议中心举行。作为高通“汽车朋友圈”的重要一员,移远通信应邀参会,展示了数十款基于高通平台打造的车载蜂窝通信模组、C-V2X模组、智能座舱模组、Wi-Fi/蓝牙模组,适配高通多个平…

「实战应用」如何用图表控件LightningChart JS创建SQL仪表板应用(一)

LightningChart JS是Web上性能特高的图表库,具有出色的执行性能 - 使用高数据速率同时监控数十个数据源。 GPU加速和WebGL渲染确保您的设备的图形处理器得到有效利用,从而实现高刷新率和流畅的动画,常用于贸易,工程,航…

c++ - priority_queue使用和模拟实现

文章目录 一、priority_queue接口使用二、 priority_queue模拟实现三、模拟代码总览 一、priority_queue接口使用 1、函数接口与作用 接口作用priority_queue< T >构造一个空优先队列priority_queue< T >(迭代区间)通过迭代区间构造一个优先队列push(val)val入队…

计算机视觉与模式识别实验2-1 角点检测算法(Harris,SUSAN,Moravec)

文章目录 &#x1f9e1;&#x1f9e1;实验流程&#x1f9e1;&#x1f9e1;Harris算法SUSAN算法Moravec算法 &#x1f9e1;&#x1f9e1;全部代码&#x1f9e1;&#x1f9e1; &#x1f9e1;&#x1f9e1;实验流程&#x1f9e1;&#x1f9e1; Harris算法 Harris算法实现步骤&…

数据容器的通用操作、字符串大小比较 总结完毕!

1.数据容器的通用操作 1&#xff09;五类数据容器是否都支持while循环/for循环 五类数据容器都支持for循环遍历 列表、元组、字符串都支持while循环&#xff0c;集合、字典不支持&#xff08;无法下标索引&#xff09; 尽管遍历的形式不同&#xff0c;但都支持遍历操作 2&a…

在电脑端实现多个微信同时登录[使用bat脚本登录]

在电脑端实现多个微信同时登录[使用bat脚本登录] 我认为工作和生活应该分开进行&#xff0c;但往往不尽人意。 第一步&#xff0c;找到微信启动程序地址。 第二步 创建txt文本&#xff0c;写入start 你的微信启动程序地址。 start D:\微信文件\WeChat\WeChat.exe start D:\微…

The First项目报告:一场由社区驱动的去中心化加密冒险—Turbo

2023年3月14日&#xff0c;由OpenAI公司开发自回归语言模型GPT-4发布上线&#xff0c;一时之间引发AI智能领域的轩然大波&#xff0c;同时受到影响的还有加密行业&#xff0c;一众AI代币纷纷出现大幅度拉升。与此同时&#xff0c;一款名为Turbo的Meme代币出现在市场中&#xff…

在美育浸润中成长 ——中山市光后中心小学张峻皓书画作品毕业汇报展成功举办

5 月 30 号下午 3 点&#xff0c;“在美育浸润中成长——广东省中山市光后中心小学张峻皓书画作品毕业汇报展”在中山市三乡镇光后中心小学成功举行&#xff0c;本次共展出张峻皓同学近期创作书法、国画及陶瓷作品共计78幅。 广东省中山市文联兼职副主席、中山市书法家协会主席…

【距离四六级只剩一个星期!】刘晓艳四级保命班课程笔记(1)(可分享治资料~)

大家好&#xff01;距离四级考试也就只剩下一个星期左右了&#x1f635;‍&#x1f4ab;。我也是时候好好补一补四级了&#xff0c;总不能还是不过吧&#x1f62d;&#xff08;已经考了两次了&#xff09;&#xff0c;这次我一定过过过过过过&#xff0c;大家也一定要过&#x…

若依前后端分离Spring Security新增手机号登录

备忘贴 转自&#xff1a;【若依RuoYi短信验证码登录】汇总_数据库_z_xiao_qiang-RuoYi 若依 配置Security: 按照Security的流程图可知&#xff0c;实现多种方式登录&#xff0c;只需要重写三个主要的组件&#xff0c;第一个用户认证处理过滤器&#xff0c;第二个用户认证tok…

Linux Shell脚本编写指南

大家好&#xff0c;在当今快节奏的科技时代&#xff0c;自动化和高效的工作流程对于个人和组织来说变得愈发重要。而Shell脚本编写作为一种强大且广泛应用的技能&#xff0c;成为了实现自动化任务和系统管理的利器。通过编写Shell脚本&#xff0c;我们可以将繁琐的重复任务自动…

【Matplotlib作图-4.Distribution】50 Matplotlib Visualizations, Python实现,源码可复现

目录 04 Distribution 4.0 Prerequisite 4.1 连续变量的直方图(Histogram for Continuous Variable) 4.2 分类变量的直方图(Histogram for Categorical Variable) 4.3 Density Plot 4.4 Density Curves with Histogram 4.5 Joy Plot 4.6 Distributed Dot Plot 4.7 Box P…

前端 video 实现全屏播放

只需要加上这句代码就行 controls <videoid"myVideo":src"detailDate.linkAddress":poster"detailDate.pictureUrl"enable-danmucontrolswebkit-playsinline"true"></video>

绘画参数配置及使用

绘画参数配置及使用 路径&#xff1a;站点后台-功能-AI绘画 进入参数配置 接口选择&#xff1a;多种接口自主选择&#xff08;需自己准备key&#xff09;&#xff0c;对应接口的key对话和绘画通用 存储空间&#xff1a; 位置在超管后台-存储空间 自主选择存储&#xff08;需…

【STL源码剖析】deque 的使用

别院深深夏席清&#xff0c;石榴开遍透帘明。 树阴满地日当午&#xff0c;梦觉流莺时一声。 目录 deque 的结构 deque 的迭代器剖析 deque 的使用 ​编辑 deque 的初始化 deque 的容量操作 deque 的访问操作 在 pos 位置插入另一个向量的 [forst&#xff0c;last] 间的数据​编…

JVMの堆、栈内存存储

1、JVM栈的数据存储 通过前面的学习&#xff0c;我们知道&#xff0c;将源代码编译成字节码文件后&#xff0c;JVM会对其中的字节码指令解释执行&#xff0c;在解释执行的过程中&#xff0c;又利用到了栈区的操作数栈和局部变量表两部分。 而局部变量表又分为一个个的槽位&…