当前位置: 首页 > news >正文

【数据结构】用栈实现队列

💯💯💯

本篇总结利用栈如何实现队列的相关操作,不难观察,栈和队列是可以相互转化的,需要好好总结它们的特性,构造出一个恰当的结构来实现即可,所以本篇难点不在代码思维,而是对结构的理解。

  • ⏰1.用栈实现队列
    • 🕐"入队列"
    • 🕑"出队列"
    • 🕒"获取队头元素"
    • 🕔"判断队列是否为空"
    • 🕕"销毁队列"
  • ⏰2.完整代码

在这里插入图片描述 请添加图片描述

⏰1.用栈实现队列

在这里插入图片描述
思路:
一个栈专门用来插入数据
一个栈专门用来出数据
在这里插入图片描述

比如如果栈里有5个数据,而要根据队列的特性,出队列肯定出的是队头数据,也就是1,而在栈里,怎么才能将数据1删除掉呢?

我们的做法是:将栈1的数据全部导入到栈2去。这样由原来的数据就倒过来了,那删除栈顶元素即可。
在这里插入图片描述

删除栈顶元素之后,我们分析发现,这时的栈2如果再进行删除,就和队列的删除操作是一致的了,不需要再导回去,如果要再删除队头数据2,直接让栈2删除即可。
所有我们发现经过一次导数据之后,栈2就完全可以当成pop数据的。
那我们如果想插入数据,该怎么插入呢?
根据队列特性,我们只能从队尾插入,也就是元素5的后面插入数据。该怎么插呢?将数据插入栈2里?那可不行,将数据插入栈2中后,原来的顺序就乱了。所以我们将数据插入到栈1去,比如我们要插入数据6,7,8.直接插入到栈1即可。
在这里插入图片描述
这样就不会影响栈2出数据的顺序了,并且插入的顺序也不受出数据的影响。
唯一需要注意的是,当栈2的数据都删除空了,这时就需要将栈1的数据再导入到栈2中,这样就能接着删除队列中的数据了。
在这里插入图片描述
所以我们可以直接定义两个栈,一个栈用来插入数据,一个栈用来删除数据。

typedef struct 
{  ST pushst;ST popst;
} MyQueue;

不过在定义之前我们需要写一个栈的数据结构,因为C语言是没有自己的栈的。

typedef int STData;
typedef struct Stack
{int* a;int top;int capicty;
}ST;
void STInit(ST*ps);//初始化栈表
void STDestroy(ST* ps);//销毁栈表
void STpush(ST* ps,STData x);//压栈,在栈顶压入一个元素
void STpop(ST* ps);//出栈,在栈顶弹出一个元素。
STData STTop(ST* ps);//访问栈顶元素
int STSize(ST* ps);
int STEmpty(ST*ps);//
void STInit(ST* ps)//初始化栈表
{assert(ps);//判断结构体指针不为NULL;//一上来可以给栈表初始化容量ps->a = (STData*)malloc(sizeof(STData) * 4);if (ps->a == NULL)//判断是否开辟成功{perror("malloc");}//初始话容量为4ps->capicty = 4;ps->top = 0;//top=0 表示的是指向栈顶元素的下一个位置//top如果为-1,则表示栈顶元素的位置
}
void STDestroy(ST* ps)//销毁栈表
{assert(ps);free(ps->a);ps->a = NULL;ps->capicty = 0;ps->top = 0;}
void STpush(ST* ps, STData x)//压栈,在栈顶压入一个元素--在压入之前也要考虑是否需要增容
{assert(ps);//断言判断if (ps->top == ps->capicty){//增容STData* tmp = (STData*)realloc(ps->a, sizeof(STData) * ps->capicty * 2);if (tmp == NULL){perror("realloc");}ps->a = tmp;ps->capicty *= 2;}ps->a[ps->top] = x;//将元素压入栈顶,一开始top是0,当元素进去后,再让top指向该栈顶元素后一个位置ps->top++;
}
int STEmpty(ST* ps)
{assert(ps);return ps->top == 0;
}void STpop(ST* ps)//出栈,在栈顶弹出一个元素。
{assert(ps);//删除元素之前要检查栈表是否还有元素可删assert(!STEmpty(ps));//当栈表为NULL是断言ps->top--;}
int STSize(ST* ps)//计算栈表长度
{assert(ps);return ps->top;//top的长度就是栈表的长度
}
STData STTop(ST* ps)//访问栈顶元素
{assert(ps);return ps->a[ps->top - 1];
}

接下来就是获取一个指向 MyQueue队列的指针。


MyQueue* myQueueCreate() //发现没有传入参数并且返回值是指向栈的指针说明里面是用malloc开辟的内存而不是在栈上开辟的
{MyQueue *q=(MyQueue*)malloc(sizeof(MyQueue));if(q==NULL){perror("malloc");}STInit(&q->pushst);//一开始需要对两个栈进行初始化STInit(&q->popst);return q;
}

🕐"入队列"

入队列,即插入数据,直接在push栈进行插入即可,不用担心顺序什么的,因为当pop栈没有数据时,就会让push栈导数据过来,这时的顺序就符合队列的要求了

void myQueuePush(MyQueue* obj, int x) 
{//只管往pushst里插入即可,不需要管其他STpush(&obj->pushst,x);
}

🕑"出队列"

出队列呢就指望pop栈即可,不过在出队列之前,我们需要检查一下pop栈里是否为空,如果为空,就需要将push栈里的数据导过来,如果不为空,那就可以进行删除操作了。


int myQueuePop(MyQueue* obj) 
{//需要讨论下,当pop这个栈为空时,需要将push栈中的数据导过来if(STEmpty(&obj->popst)){while(!STEmpty(&obj->pushst))//将push栈中的所有数据都导过去即可{STpush(&obj->popst,STTop(&obj->pushst));STpop(&obj->pushst);//删除push栈里的这个数据}}//走到这里有两种情况,可能push栈里的数据导光了,也可能是pop栈里本来就有数据,不为空int top=STTop(&obj->popst);//将这个栈顶元素记录下来,最后需要返回STpop(&obj->popst);return top;
}

🕒"获取队头元素"

获取队头数据,这个操作与刚刚的删除操作基本一样,只不过该操作不需要将数据删除,直接返回栈顶元素即可,所以大部分代码是一样的。

int myQueuePeek(MyQueue* obj) 
{//这里跟pop数据很像,直接return 栈顶元素即可//需要讨论下,当pop这个栈为空时,需要将push栈中的数据导过来if(STEmpty(&obj->popst)){while(!STEmpty(&obj->pushst))//将push栈中的所有数据都导过去即可{STpush(&obj->popst,STTop(&obj->pushst));STpop(&obj->pushst);}}//走到这里有两种情况,可能push栈里的数据导光了,也可能是pop栈里本来就有数据,不为空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);
}

⏰2.完整代码


typedef int STData;
typedef struct Stack
{int* a;int top;int capicty;
}ST;
void STInit(ST*ps);//初始化栈表
void STDestroy(ST* ps);//销毁栈表
void STpush(ST* ps,STData x);//压栈,在栈顶压入一个元素
void STpop(ST* ps);//出栈,在栈顶弹出一个元素。
STData STTop(ST* ps);//访问栈顶元素
int STSize(ST* ps);
int STEmpty(ST*ps);//
void STInit(ST* ps)//初始化栈表
{assert(ps);//判断结构体指针不为NULL;//一上来可以给栈表初始化容量ps->a = (STData*)malloc(sizeof(STData) * 4);if (ps->a == NULL)//判断是否开辟成功{perror("malloc");}//初始话容量为4ps->capicty = 4;ps->top = 0;//top=0 表示的是指向栈顶元素的下一个位置//top如果为-1,则表示栈顶元素的位置
}
void STDestroy(ST* ps)//销毁栈表
{assert(ps);free(ps->a);ps->a = NULL;ps->capicty = 0;ps->top = 0;}
void STpush(ST* ps, STData x)//压栈,在栈顶压入一个元素--在压入之前也要考虑是否需要增容
{assert(ps);//断言判断if (ps->top == ps->capicty){//增容STData* tmp = (STData*)realloc(ps->a, sizeof(STData) * ps->capicty * 2);if (tmp == NULL){perror("realloc");}ps->a = tmp;ps->capicty *= 2;}ps->a[ps->top] = x;//将元素压入栈顶,一开始top是0,当元素进去后,再让top指向该栈顶元素后一个位置ps->top++;
}
int STEmpty(ST* ps)
{assert(ps);return ps->top == 0;
}void STpop(ST* ps)//出栈,在栈顶弹出一个元素。
{assert(ps);//删除元素之前要检查栈表是否还有元素可删assert(!STEmpty(ps));//当栈表为NULL是断言ps->top--;}
int STSize(ST* ps)//计算栈表长度
{assert(ps);return ps->top;//top的长度就是栈表的长度
}
STData STTop(ST* ps)//访问栈顶元素
{assert(ps);return ps->a[ps->top - 1];
}
typedef struct 
{  ST pushst;ST popst;
} MyQueue;MyQueue* myQueueCreate() 
{MyQueue *q=(MyQueue*)malloc(sizeof(MyQueue));if(q==NULL){perror("malloc");}STInit(&q->pushst);STInit(&q->popst);return q;
}void myQueuePush(MyQueue* obj, int x) 
{//只管往pushst里插入即可,不需要管STpush(&obj->pushst,x);
}int myQueuePop(MyQueue* obj) 
{//需要讨论下,当pop这个栈为空时,需要将push栈中的数据导过来if(STEmpty(&obj->popst)){while(!STEmpty(&obj->pushst))//将push栈中的所有数据都导过去即可{STpush(&obj->popst,STTop(&obj->pushst));STpop(&obj->pushst);}}//走到这里有两种情况,可能push栈里的数据导光了,也可能是pop栈里本来就有数据,不为空int top=STTop(&obj->popst);STpop(&obj->popst);return top;
}int myQueuePeek(MyQueue* obj) 
{//这里跟pop数据很像,直接return 栈顶元素即可//需要讨论下,当pop这个栈为空时,需要将push栈中的数据导过来if(STEmpty(&obj->popst)){while(!STEmpty(&obj->pushst))//将push栈中的所有数据都导过去即可{STpush(&obj->popst,STTop(&obj->pushst));STpop(&obj->pushst);}}//走到这里有两种情况,可能push栈里的数据导光了,也可能是pop栈里本来就有数据,不为空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);
}/*** Your MyQueue struct will be instantiated and called as such:* MyQueue* obj = myQueueCreate();* myQueuePush(obj, x);* int param_2 = myQueuePop(obj);* int param_3 = myQueuePeek(obj);* bool param_4 = myQueueEmpty(obj);* myQueueFree(obj);
*/

相关文章:

【数据结构】用栈实现队列

💯💯💯 本篇总结利用栈如何实现队列的相关操作,不难观察,栈和队列是可以相互转化的,需要好好总结它们的特性,构造出一个恰当的结构来实现即可,所以本篇难点不在代码思维,…...

[Netty源码] 服务端启动过程 (二)

文章目录1.ServerBootstrap2.服务端启动过程3.具体步骤分析3.1 创建服务端Channel3.2 初始化服务端Channel3.3 注册selector3.4 端口绑定1.ServerBootstrap ServerBootstrap引导服务端启动流程: //主EventLoopGroup NioEventLoopGroup master new NioEventLoopGroup(); //从E…...

Week 14

代码源每日一题Div2 106. 订单编号 原题链接:订单编号 思路:这题本来没啥思路,直到获得了某位佬的提示才会做( 我们可以用set来维护一些区间,这些区间为 pair 类型,表示没有使用过的编号,每次…...

【微信小程序】-- 使用 Git 管理项目(五十)

💌 所属专栏:【微信小程序开发教程】 😀 作  者:我是夜阑的狗🐶 🚀 个人简介:一个正在努力学技术的CV工程师,专注基础和实战分享 ,欢迎咨询! &…...

leetcode每日一题:134. 加油站

系列:贪心算法 语言:java 题目来源:Leetcode134. 加油站 题目 在一条环路上有 n 个加油站,其中第 i 个加油站有汽油 gas[i] 升。 你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i1 个加油站需要消耗汽油 cost[…...

开放式基金实时排行 API 数据接口

开放式基金实时排行 API 数据接口 多维度参数返回,实时数据,类型参数筛选。 1. 产品功能 返回实时开放式基金排行数据可定义查询基金类型参数;多个基金属性值返回多维指标,一次查询毫秒级返回;数据持续更新与维护&am…...

Android开发中synchronized的实现原理

synchronized的三种使用方式 **1.修饰实例方法,**作用于当前实例加锁,进入同步代码前要获得当前实例的锁。 没有问题的写法: public class AccountingSync implements Runnable{//共享资源(临界资源)static int i0;/*** synchronized 修饰实例方法*/p…...

【华为OD机试 2023最新 】 统一限载货物数最小值(C++)

题目描述 火车站附近的货物中转站负责将到站货物运往仓库,小明在中转站负责调度2K辆中转车(K辆干货中转车,K辆湿货中转车)。 货物由不同供货商从各地发来,各地的货物是依次进站,然后小明按照卸货顺序依次装货到中转车,一个供货商的货只能装到一辆车上,不能拆装,但是…...

【生活工作经验 十】ChatGPT模型对话初探

最近探索了下全球大火的ChatGPT,想对此做个初步了解 一篇博客 当今社会,自然语言处理技术得到了迅速的发展,人工智能技术也越来越受到关注。其中,基于深度学习的大型语言模型,如GPT(Generative Pre-train…...

基于Spring Boot房产销售平台的设计与实现【源码+论文】分享

开发语言:Java 框架:springboot JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7 数据库工具:Navicat11 开发软件:eclipse/myeclipse/idea Maven包:Maven3.3.9 摘要 信息技术的发展…...

不同类型的电机的工作原理和控制方法汇总

电机控制是指对电机的启动、调速(加速、减速)、运转方向和停止进行的控制,不同类型的电机有着不同的工作原理和控制方法。 一、无刷电机 无刷电机是由电机主体和电机驱动板组成的一种没有电刷和换向器的机电一体化产品。在无刷电机中&#xf…...

计算机网络管理 TCP三次握手的建立过程,Wireshark抓包分析并验证TCP三次握手建立连接的报文

⬜⬜⬜ ---🟧🟨🟩🟦🟪 (*^▽^*)欢迎光临 🟧🟨🟩🟦🟪---⬜⬜⬜ ✏️write in front✏️ 📝个人主页:陈丹宇jmu 🎁欢迎各位→…...

HTTP/2.x:最新的网页加载技术,快速提高您的SEO排名

2.1 http2概念HTTP/2.0(又称HTTP2)是HTTP协议的第二个版本。它是对HTTP/1.x的更新,旨在提高网络性能和安全性。HTTP/2.0是由互联网工程任务组(IETF)标准化的,并于2015年发布。2.2 http2.x与http1.x区别HTTP…...

机器学习----线性回归

第一关:简单线性回归与多元线性回归 1、下面属于多元线性回归的是? A、 求得正方形面积与对角线之间的关系。 B、 建立股票价格与成交量、换手率等因素之间的线性关系。 C、 建立西瓜价格与西瓜大小、西瓜产地、甜度等因素之间的线性关系。 D、 建立西瓜…...

MS2131 USB 3.0 高清音视频采集+HDMI 环出+混音处理芯片 应用网络直播一体机

MS2131 是一款 USB 3.0 高清视频和音频采集处理芯片,内部集成 USB 3.0 Device 控制器、 数据收发模块、音视频处理模块。MS2131 可以通过 USB 3.0 接口将 HDMI 输入的音视频信号传 送到 PC、智能手机、平板电脑上预览或采集。MS2131 支持 HDMI 环出功能,…...

基于堆与AdjustDown的TOP-K问题

TIPSTOP-K问题TOP-K问题:就是说现在比如说有n个数据,然后需要从这n个数据里面找到最大的或最小的前k个。一般来讲思路的话就是:先把这n个数据给他建一个堆,建堆完成之后,然后就去调堆,然后大概只需要调k次&…...

在CentOS上安装Docker引擎

1,先决条件#### 1-1操作系统要求1-2 卸载旧版本 2,安装方法2-1使用存储库安装设置存储库安装 Docker 引擎 本文永久更新地址: 官方地址:https://docs.docker.com/engine/install/centos/ 1,先决条件 #### 1-1操作系统要求 要安装 Docker Engine,您需要…...

【10】核心易中期刊推荐——模式识别与机器学习

🚀🚀🚀NEW!!!核心易中期刊推荐栏目来啦 ~ 📚🍀 核心期刊在国内的应用范围非常广,核心期刊发表论文是国内很多作者晋升的硬性要求,并且在国内属于顶尖论文发表,具有很高的学术价值。在中文核心目录体系中,权威代表有CSSCI、CSCD和北大核心。其中,中文期刊的数…...

【数据结构】并查集

目录 一:用途 二:实现 O(1) 三:例题 例题1:集合 例题2:连通图无向 例题3:acwing 240 食物链 一:用途 将两个集合合并询问两个元素是否在一个集合当中 二:实现 O(1) 每…...

软考--网络攻击分类

网络攻击的主要手段包括口令入侵、放置特洛伊木马程序、拒绝服务(DoS)攻击、端口扫描、网络监听、欺骗攻击和电子邮件攻击等。口令入侵是指使用某些合法用户的账号和口令登录到目的主机,然后再实施攻击活动。特洛伊木马(Trojans)程序常被伪装…...

蓝桥杯刷题冲刺 | 倒计时17天

作者:指针不指南吗 专栏:蓝桥杯倒计时冲刺 🐾马上就要蓝桥杯了,最后的这几天尤为重要,不可懈怠哦🐾 文章目录1.长草2.分考场1.长草 题目 链接: 长草 - 蓝桥云课 (lanqiao.cn) 题目描述 小明有一…...

冲击蓝桥杯-并查集,前缀和,字符串

目录 前言 一、并查集 1、并查集的合并(带路径压缩) 2、询问是否为同一个集合 3、例题 二、前缀和 1 、前缀和是什么 2、经典题目 三- 字符串处理 1、字符串的插入 2、字符串转化为int类型 3、字符反转 前言 并查集合前缀,字符串…...

【matlab学习笔记】线性方程组求解方法

线性方程组求解方法2.1 求逆法实现方式例子2.2 分解法LU分解(Doolittle分解)实现方法例子QR分解法实现方法例子Cholesky 分解法实现方法例子奇异值分解法实现方法例子Hessenberg 分解实现方法例子Schur 分解实现方法例子2.3 迭代法逐次迭代法里查森迭代法…...

Python带你一键下载到最新章节,不付费也能看

前言 大家早好、午好、晚好吖 ❤ ~欢迎光临本文章 完整源码、素材皆可点击文章下方名片获取此处跳转 开发环境: python 3.8 运行代码 pycharm 2022.3 辅助敲代码 requests 发送请求/第三方模块 模块安装:win R 输入cmd 输入安装命令 pip install 模块名 如果…...

【sentinel】熔断降级规则详解及源码分析

概述 除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。一个服务常常会调用别的模块,可能是另外的一个远程服务、数据库,或者第三方API等。例如,支付的时候,可能需要远程调用银联…...

ffplay源码分析-main函数入口分析

ffplay源码分析-main函数入口分析 基于ffmpeg6.0源码分析。 流程 使用ffplay播放视频文件,会触发main函数的调用。main函数中会进行以下操作: 从命令行中解析日志级别、日志是否需要落文件、是否要输出banner信息。banner信息包含版权、库的版本。注…...

C++三种继承方式

C继承的一般语法为:class 派生类名:[继承方式] 基类名{派生类新增加的成员};继承方式限定了基类成员在派生类中的访问权限,包括 public(公有的)、private(私有的)和 protected&#…...

【Android -- 软技能】《软技能:代码之外的生存指南》之好书推荐(一)

前言 这是一本由美国的一个软件开发人员写的,但书中除了有 Java 、C# 几个单词外,没有一行代码。 因为这本书讲的是代码之外的东西。 文章目录结构: 1. 职业 从业心态:说白了就是要有责任心,把每份工作要当成是自…...

Nginx可视化管理工具 - Nginx Proxy Manager

一、介绍 nginx-proxy-manager 是一个反向代理管理系统,它基于Nginx,具有漂亮干净的 Web UI。还可以获得受信任的 SSL 证书,并通过单独的配置、自定义和入侵保护来管理多个代理。 其官网地址如下: https://nginxproxymanager.com/ 二、安装 第一步:192.168.1.108服务…...

https是如何保证安全的

在学习http与https的区别的时候,我们通常从以下几点出发:http是超文本传输协议,是明文传输,有安全风险,https在TCP和http网络层之间加入了SSL/TLS安全协议,使得报文能够加密传输http连接简单,三…...

衡水做网站公司/seo发贴软件

一、概念 // 有name的属于具名插槽&#xff0c;没有name属于匿名插槽 <app><div slot"a">xxxx</div><div slot"b">xxxx</div> </app> <slot name"a"></slot> <slot name"b">&…...

上海网站建设app/无锡网站排名公司

LockSupport是什么&#xff1f; “用于创建锁和其他同步类的基本线程阻塞原语。 ”&#xff0c;对于JDK官方文档上的介绍&#xff0c;听起来并不好懂。 是对线程唤醒机制Wait/Notify机制的改良版&#xff0c;提供Park()和unPark()两个方法来阻塞线程和解除阻塞。 Wait/Notif…...

我想学网站建设/全国网站排名

支持功能 话题查看节点查看和按字母搜索用户资料查看话题回复话题创建未读提醒查看常用分类节点话题浏览节点下的话题翻页话题回复翻页滑动手势返回其他功能 实现了节点、话题、用户三个Scheme,通过话题、节点、用户链接直接打开客户端进行相关信息浏览对用户已经浏览过的话题作…...

模板网站设计报价/免费做网站网站的软件

本篇的思维导图: 正则表达式-re 模块 正则表达式(Regular Expression)是一种文本模式的描述方法。例如,\d是一个正则表达式,表示一位数字字符,即任何一位0到9的数字。 在 Python 语言中re 模块提供了全部的正则表达式函数,例如:compile 函数。 compile 函数 compile 函…...

个人制作一个网站的费用/交换友情链接的方法

http://www.cnblogs.com/hh54188/archive/2011/04/09/1996469.html 动画队列解释 animate 必需的 params 参数定义形成动画的 CSS 属性。 可选的 speed 参数规定效果的时长。它可以取以下值&#xff1a;"slow"、"fast" 或毫秒。 可选的 callback 参数是动…...

数字营销证书/高级seo

因为看到很多公司招聘需要有linux平台下的开发经验&#xff0c;所以今天在笔记本上装了一个Kubuntu作为以后学习的平台。本文采用的是win7Kubuntu双系统的模式&#xff0c;尽管最后安装成功了&#xff0c;但是中间有很多波折在此记下来以备以后再次发生同样的事情。首先&#x…...