【数据结构与算法】队列和栈的相互实现以及循环队列

目录
- 🌔一.用队列实现栈
- 🌙1.题目描述
- 🌙2.思路分析
- 🌙3.代码实现
- ⛈二.用栈实现队列
- ☔1.题目描述
- ☔2.思路分析
- ☔3.代码实现
- 🌈三.实现循环队列
🌔一.用队列实现栈
🌙1.题目描述
我们先看一下题目链接

🌙2.思路分析
我们知道栈是后进先出的线性表,题目要求我们使用两个队列来实现,队列的特性是先进先出,从队尾进 队头出,图解如下:

那我们如何向队列进元素1 2 3 4出队列是4 3 2 1的顺序呢。假设现在队列中有1 2 3 4:

我们想让4先出队列的话,可以将前面的1 2 3先转移到另一个队列中,再出4,以此类推实现后进先拿出。使得一个队列为空用来出队列时倒元素的目的地,另一个不为空的队列用来插入数据。想要返回栈顶元素 只要返回非空队列的队尾元素即可。
🌙3.代码实现
代码的实现,我们需要先手撕个队列包括队列的基本功能并且定义两个队列:
typedef int QDataType;typedef struct QueueNode
{struct QueueNode* next;QDataType data;
}QNode;typedef struct Queue
{QNode* head;QNode* tail;int size;
}Queue;typedef struct {Queue q1;Queue q2;
} MyStack;
void QueueInit(Queue* pt);
void QueueDestroy(Queue* pt);void QueuePush(Queue* pt, QDataType x);
void QueuePop(Queue* pt);int QueueSize(Queue* pt);bool QueueEmpty(Queue* pt);QDataType QueueFront(Queue* pt);
QDataType QueueBack(Queue* pt);void QueueInit(Queue* pt)
{assert(pt);pt->head = pt->tail = NULL;pt->size = 0;
}void QueueDestroy(Queue* pt)
{assert(pt);QNode* cur = pt->head;while (cur){QNode* next = cur->next;free(cur);cur = next;}pt->head = pt->tail = NULL;pt->size = 0;
}void QueuePush(Queue* pt, QDataType x)
{QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc fail");return;}newnode->next = NULL;newnode->data = x;if (pt->head == NULL){assert(pt->tail == NULL);pt->head = pt->tail = newnode;}else{pt->tail->next = newnode;pt->tail = newnode;}pt->size++;}void QueuePop(Queue* pt)
{assert(pt);assert(pt->head != NULL);if (pt->head->next == NULL){free(pt->head);pt->head = pt->tail = NULL;}else{QNode* next = pt->head->next;free(pt->head);pt->head = next;}pt->size--;
}int QueueSize(Queue* pt)
{assert(pt);return pt->size;
}bool QueueEmpty(Queue* pt)
{assert(pt);return pt->size == 0;
}QDataType QueueFront(Queue* pt)
{assert(pt);assert(!QueueEmpty(pt));return pt->head->data;
}
QDataType QueueBack(Queue* pt)
{assert(pt);assert(!QueueEmpty(pt));return pt->tail->data;
}
紧接着即使栈的实现:
MyStack* myStackCreate() {MyStack*ptr=(MyStack*)malloc(sizeof(MyStack));if(ptr==NULL){perror("malloc fail");return NULL;}QueueInit(&ptr->q1);QueueInit(&ptr->q2);return ptr;}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* noempty=&obj->q2;if(!QueueEmpty(&obj->q1)){empty=&obj->q2;noempty=&obj->q1;}while(QueueSize(noempty)>1){QueuePush(empty,QueueFront(noempty));QueuePop(noempty);}int ret=QueueFront(noempty);QueuePop(noempty);return ret;}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.题目描述
我们先看一下题目链接

☔2.思路分析
这题相反,需要我们实现两个栈来实现队列。究其本质就是使用两个后进先出显示先进先出,我们用图例来理解下:

入栈1 2 3 4后出栈顺序为4 3 2 1我们可以依次顺序入到另一个栈中,再将数据从栈中弹出,即可做到出栈1 2 3 4的顺序。图示如下:

☔3.代码实现
代码还是需要先手撕个栈以及实现栈的基本功能并定义两个栈分别用来插入和删除:
typedef int STDataType;typedef struct stack
{STDataType* a;STDataType top;STDataType capacity;
}ST;void InitST(ST* s);//初始化栈
void DestroyST(ST* s);//销毁栈void Push(ST* s, int x);//压栈
void Pop(ST* s);//出栈bool STEmpty(ST* s);//判断栈是否为空栈
STDataType STSize(ST* s);//当前栈的元素个数
STDataType STTop(ST* s);//返回栈顶元素
void InitST(ST* s)
{assert(s);s->a = (STDataType*)malloc(sizeof(STDataType) * 4);if (s->a == NULL){perror("malloc fail");return;}s->capacity = 4;s->top = -1;///top记录指向的当前元素
}void DestroyST(ST* s)
{assert(s);s->capacity = 0;free(s->a);s->a = NULL;s->top = -1;
}void Push(ST* s,int x)
{assert(s);if (s->top+1 == s->capacity){s->a = (STDataType*)realloc(s->a,sizeof(STDataType)*s->capacity*2);if (s->a == NULL){perror("malloc fail");return;}s->capacity *= 2;}s->a[s->top+1] = x;s->top++;}void Pop(ST* s)
{assert(s);assert(!STEmpty(s));s->top--;
}bool STEmpty(ST* s)
{assert(s);if (s->top == -1)return true;return false;
}STDataType STSize(ST* s)
{assert(s);return s->top + 1;
}STDataType STTop(ST* s)
{assert(s);return s->a[s->top];
}typedef struct {ST popst;ST pushst;
} MyQueue;
定义时我们就指定了用来插入的栈和删除的栈,我们在创建好自己的队列后,对队列进行插入操作时,只需要向pushst栈插入数据即可,另一个popst栈保持为空,在需要出队列时,将另一个栈的数据倒过来,再出数据 即可保证先进先出的顺序。
MyQueue* myQueueCreate() {MyQueue* ptr=(MyQueue*)malloc(sizeof(MyQueue));if(ptr == NULL){perror("malloc fail");return NULL;}InitST(&ptr->popst);InitST(&ptr->pushst);return ptr;}void myQueuePush(MyQueue* obj, int x) {Push(&obj->pushst,x);
}int myQueuePop(MyQueue* obj) {int ret=myQueuePeek(obj);Pop(&obj->popst);return ret;
}int myQueuePeek(MyQueue* obj) {if(STEmpty(&obj->popst)){while(!STEmpty(&obj->pushst)){Push(&obj->popst,STTop(&obj->pushst));Pop(&obj->pushst); }}return STTop(&obj->popst);
}bool myQueueEmpty(MyQueue* obj) {return STEmpty(&obj->popst)&&STEmpty(&obj->pushst);
}void myQueueFree(MyQueue* obj) {DestroyST(&obj->popst);DestroyST(&obj->pushst);free(obj);}
🌈三.实现循环队列
线性表有顺序存储和链式存储,栈是线性表,具有这两种存储方式。同样,队列作为一种特殊的线性表,也同样存在两种存储方式。队列的链式存储即是进行尾插头删的单链表,所以我们讲解队列的顺序存储———循环队列。
借助题目更好的讲解循环队列题目链接

首先我们创建结构体用来存储数据,其中包含指向存储数据地址的指针,记录队列有效长度的整形变量,还有两个记录循环队列头和尾数组下标的变量。
typedef struct {int *a;int rear;int front;int k;} MyCircularQueue;
接着我们初始化队列,对于给定的有效长度k我们malloc比k多一的存储空间,方便表示存储满的情况另一种解决方法是增加size变量 用于记录当前数据个数。
MyCircularQueue* myCircularQueueCreate(int k) {MyCircularQueue* obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));obj->rear=obj->front=0;obj->k=k;obj->a=(int*)malloc(sizeof(int)*(k+1));return obj;
}
队列为空的即是头尾指针指向同一地方的情况。
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {return obj->front == obj->rear;
}
判断队列是否满,由于rear有可能比front大,也可能小,所以尽管他们只相差一个位置时就是满的情况,但可能相差整整一圈。为了避免判断错误,则需要取模判断。
bool myCircularQueueIsFull(MyCircularQueue* obj) {return (obj->rear+1)%(obj->k+1) == obj->front;
}
剩余代码
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {if(myCircularQueueIsFull(obj))return false;obj->a[obj->rear++]=value;obj->rear%=(obj->k+1);return true;
}bool myCircularQueueDeQueue(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj))return false;obj->front++;obj->front%=(obj->k+1);return true;
}int myCircularQueueFront(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj))return -1;return obj->a[obj->front];
}int myCircularQueueRear(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj))return -1;int x=obj->rear == 0? obj->k:obj->rear-1;//防止数据存储到最后一位return obj->a[x];
}void myCircularQueueFree(MyCircularQueue* obj) {free(obj->a);free(obj);
}
相关文章:
【数据结构与算法】队列和栈的相互实现以及循环队列
目录🌔一.用队列实现栈🌙1.题目描述🌙2.思路分析🌙3.代码实现⛈二.用栈实现队列☔1.题目描述☔2.思路分析☔3.代码实现🌈三.实现循环队列🌔一.用队列实现栈 🌙1.题目描述 我们先看一下题目链接…...
mysql连接不上问题解决
公司新搭内网测试环境,mysql远程登录问题解决 远程登录: 1 修改host, mysql> select user,host,plugin from user; ---------------------------------------------------- | user | host | plugin | ------------------------…...
利用nginx实现动静分离的负载均衡集群实战
前言 大家好,我是沐风晓月,今天我们利用nginx来作为负载,实现两台apache服务器的动静分离集群实战; 本文收录于沐风晓月的专栏《linux基本功-系统服务实战》,更多内容可以关注我的博客: https://blog.csd…...
与chatGPT神聊,引领你深入浅出系统调用
在操作系统的教学中,系统调用的作用不言而喻,但是,对系统调用常常是雾里看花,似乎明白,又难以真正的触及,即使在代码中调用了系统调用,比如调用fork()创建进程࿰…...
自学大数据第十天~Hbase
随着数据量的增多,数据的类型也不像原来那样都是结构化数据,还有非结构化数据; Hbase时google 的bigtable的开源实现, BigtableHbase文件存储系统GFSHDFS海量数据处理MRMR协同管理服务chubbyzookeeper虽然有了HDFS和MR,但是对于数据的实时处理是比较困难的,没有办法应对数据的…...
vue更高效的工具-vite
目录 1.webpack 2.vite是什么 3.使用vite创建项目 4.最后总结 🐼webpack 简单来说,Webpack是一个打包工具。 站在2018年的角度,成为一个优秀的前端工程师,除了要会写页面样式和动态效果之外,还需要会用主流的单页…...
HFish蜜罐的介绍和简单测试(一)
目录 0、什么是蜜罐 0.1、蜜罐的定义 0.2、蜜罐的优势 0.3、蜜罐与情报 1、HFish介绍 1.1、设计理念 1.2、HFish架构 1.3、HFish特点 1.4、常见蜜罐场景 2、快速部署 2.1、环境要求 2.2、联网环境,一键安装 2.3、安装效果 3、错误排查 3.1、管理端问题…...
2023面试题汇总二
一、CSS面试题 1. 清除浮动的方式有哪些? 为什么要清除浮动?因为浮动的盒子脱离标准流,如果父盒子没有设置高度的话,下面的盒子就会撑上来。 额外标签法(在最后一个浮动标签后,新加一个标签,给其设置cle…...
C# 支付宝接口在线收款退款
收款 在C#中使用支付宝在线支付功能,需要使用支付宝开放平台提供的SDK(软件开发工具包),通过SDK中提供的API(应用程序接口)实现在线支付功能。 以下是使用C#实现支付宝在线支付的大致步骤: 获…...
python例程:《企业编码生成系统》程序
目录《企业编码生成系统》程序使用说明主要代码演示源码及说明文档下载路径《企业编码生成系统》程序使用说明 在PyCharm中运行《企业编码生成系统》即可进入如图1所示的系统主界面。在该界面中可以选择要使用功能对应的菜单进行不同的操作。在选择功能菜单时,只需…...
基于EB工具的TC3xx_MCAL配置开发04_ADC模块软件触发Demo配置
目录 1.概述2. EB配置2.1 添加HwUnit2.2 AdcPrescale配置2.3 添加ADC通道2.4 添加Adc Group2.5 Adc Group配置2.5.1 AdcGroup->General2.5.2 AdcGroup->AdcNotification2.5.3 AdcGroup->AdcGroupDefinition2.5.4 AdcGroup->AdcResRegDefinition2.6 中断配置1.概述 …...
内存操作函数
前言 🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨ 🐻推荐专栏: 🍔🍟🌯 c语言进阶 🔑个人信条: 🌵知行合一 🍉本篇简介:>:介绍c语言中有关指针更深层的知识. 金句分享: ✨未来…...
免费搭建个人博客
免费搭建个人博客,并发布到公网 利用hexo搭建个人博客,通过gitee的pages发布到公网 1 前置准备 安装git、安装node.js(尽量选择长期支持的版本) node.js官网:https://nodejs.org/en/ git官网:https://git-scm.com/book/zh/v2 安装…...
【Vue全家桶】详解Vue Router(一)
【Vue全家桶】Vue Router详解(一) Vue系列文章目录: 内容参考链接Vue(一)【Vue全家桶】邂逅Vue、Vue的多种引入方式Vue(二)【Vue全家桶】声明式编程、MVVMVue(三)【Vue…...
9大 HIVE SQL 最频繁被问到的面试题
SQL是用于数据分析和数据处理的最重要的编程语言之一,因此与数据科学相关的工作(例如数据分析师、数据科学家和数据工程师)在面试时总会问到关于 SQL 的问题。 SQL面试问题旨在评估应聘者的技术和解决问题的能力。因此对于应聘者来说&#x…...
学大数据算跟风吗?
随着互联网、物联网和人工智能等技术的不断发展,大数据技术逐渐进入人们的视野,成为一个备受关注的热点话题。那么,大数据专业好学吗?前景如何?下面我们来一起探讨一下。 一、大数据专业的学习难度 大数据技术是一种综…...
[C#]关于ListBox的坑
在用C#写个Demo程序的时候,使用ListBox保存读取到的每行内容。然后在重复读取的时候需要清除ListBox中的内容,我看到ListBox有清除的函数:lsbFiles.Items.Clear();以为这个函数就可以解决所有的问题,但是....于是想了个方法准备一…...
Apache POI 入门·第一话
文章目录1 摘要2 Apache POI2.1 介绍2.2 应用场景2.3 入门案例2.3.1 将数据写入Excel文件2.3.1.1 导入POI maven坐标2.3.1.2 代码开发2.3.1.3 实现效果2.3.2 读取Excel文件中的数据2.3.3 实现效果2.4 开发案例——导出运营数据Excel报表2.4.1 产品原型2.4.2 接口设计2.4.3 代码…...
8个python自动化脚本提高打工人幸福感~比心~
人生苦短,我用Python 最近有许多打工人都找我说打工好难 每天都是执行许多重复的任务, 例如阅读新闻、发邮件、查看天气、打开书签、清理文件夹等等, 使用自动化脚本,就无需手动一次又一次地完成这些任务, 非常方便…...
【嵌入式烧录/刷写文件】-1-详解Motorola S-record(S19/SREC/mot/SX)格式文件
目录 1 什么是Motorola S-record 2 Motorola S-record的格式 2.1 Motorola S-record的结构 2.1.1 “Record type记录类型”的说明 2.1.2 “Record length记录长度”的说明 2.1.3 如何计算“Checksum校验和” 2.2 Record order记录顺序 2.3 Text line terminator文本行终…...
Llama-3.2V-11B-cot企业级落地:保险定损图片自动归因与责任链推理
Llama-3.2V-11B-cot企业级落地:保险定损图片自动归因与责任链推理 想象一下,你是一名保险公司的定损员。每天,你的邮箱里塞满了上百张事故现场照片——撞瘪的车头、破碎的挡风玻璃、划痕累累的车门。你需要从这些照片里,像侦探一…...
窗口大小强制调整工具终极指南:如何轻松掌控任意应用程序窗口尺寸
窗口大小强制调整工具终极指南:如何轻松掌控任意应用程序窗口尺寸 【免费下载链接】WindowResizer 一个可以强制调整应用程序窗口大小的工具 项目地址: https://gitcode.com/gh_mirrors/wi/WindowResizer 还在为那些顽固的应用程序窗口而烦恼吗?某…...
Tessent Shell双Pass插入策略深度解读:为什么MemoryBIST要先于EDT/OCC插入?
Tessent Shell双Pass插入策略:MemoryBIST优先于EDT/OCC的技术本质解析 在芯片测试领域,Tessent Shell的双Pass插入流程(Two-Pass Insertion Process)是一个被广泛采用却鲜少深入探讨的核心方法论。当工程师首次接触"先Memory…...
从逗号到标签:用React 19 + TailwindCSS V4构建智能选项解析器
1. 为什么需要智能标签解析器? 在日常开发中,我们经常遇到这样的场景:用户需要输入多个选项,比如商品标签、兴趣关键词或者任务分类。传统做法是让用户手动输入每个标签后按回车,这种体验既笨拙又低效。而一个优秀的智…...
XUnity.AutoTranslator技术指南:从入门到精通的游戏翻译解决方案
XUnity.AutoTranslator技术指南:从入门到精通的游戏翻译解决方案 【免费下载链接】XUnity.AutoTranslator 项目地址: https://gitcode.com/gh_mirrors/xu/XUnity.AutoTranslator 一、核心价值:打破语言壁垒的游戏翻译引擎 🚀 在全球…...
终极指南:如何用Zotero PDF Translate插件快速突破学术语言壁垒
终极指南:如何用Zotero PDF Translate插件快速突破学术语言壁垒 【免费下载链接】zotero-pdf-translate 支持将PDF、EPub、网页内容、元数据、注释和笔记翻译为目标语言,并且兼容20多种翻译服务。 项目地址: https://gitcode.com/gh_mirrors/zo/zotero…...
mPLUG-Owl3-2B多模态交互工具效果展示:高精度图像理解+自然语言问答真实案例
mPLUG-Owl3-2B多模态交互工具效果展示:高精度图像理解自然语言问答真实案例 1. 开篇:多模态交互的全新体验 想象一下,你随手拍了一张照片,然后像和朋友聊天一样问:"这张图片里有什么有趣的东西?&quo…...
Home Assistant ARM版在CasaOS上的完美配置指南(含时区设置技巧)
Home Assistant ARM版在CasaOS上的完美配置指南(含时区设置技巧) 对于智能家居爱好者来说,Home Assistant(HA)无疑是最强大的开源平台之一。而在ARM架构设备上运行HA,尤其是通过CasaOS这样的轻量级容器管理…...
AI辅助开发:打造你的智能编程技能教练——基于快马平台实践
最近在学编程时,发现一个痛点:遇到问题经常要反复查文档、搜论坛,效率很低。刚好体验了InsCode(快马)平台的AI辅助功能,用它做了个"智能编程教练"的小项目,效果意外地好。分享下具体实现思路和实际体验&…...
PDF-Parser-1.0一键部署教程:5分钟搞定文档解析神器,小白也能轻松上手
PDF-Parser-1.0一键部署教程:5分钟搞定文档解析神器,小白也能轻松上手 1. 为什么你需要这个文档解析工具? 你是不是经常遇到这样的烦恼? 下载了一份重要的PDF报告,想把里面的表格数据整理到Excel里,结果…...
