栈和队列(二) 队列操作详解及栈与队列的相互实现

文章目录

  • 四、队列
    • 1、什么是队列
    • 2、队列的基本操作
      • Queue.h
      • Queue.c
        • 初始化队列
        • 队尾入队列
        • 队头出队列
        • 获取队列头部元素
        • 获取队列队尾元素
        • 获取队列中有效元素个数
        • 检测队列是否为空,如果为空返回非零结果,如果非空返回0
        • 销毁队列
  • 五、设计循环队列
  • 六、栈与队列的相互实现
    • 1、用栈实现队列
    • 2、用队列实现栈

栈操作实现:栈和队列(一) 栈操作详解

在这里插入图片描述

四、队列

1、什么是队列

队列就像是高速公路上的一个隧道一样,所有的车辆只允许从入口驶入,从出口驶出,先进先出,不允许逆行。

队列(queue)是一种线性数据结构,队列的元素只能先入先出(First In First Out,简称FIFO)。
入队列:进行插入操作的一端称为队尾
出队列:进行删除操作的一端称为队头

在这里插入图片描述

2、队列的基本操作

利用单链表来实现队列的基本操作

在这里插入图片描述

代码结构设计:

  • Queue.h: 存放队列结构及需要用到的头文件,函数声明等
  • Queue.c: 各种操作函数的具体实现

Queue.h

#pragma once#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>//方便修改数据类型
typedef int QDataType;// 链式结构:表示队列 
typedef struct QListNode
{struct QListNode* next;QDataType data;
}QNode;// 队列的结构 
typedef struct Queue
{QNode* front;//队头QNode* rear;//队尾
}Queue;// 初始化队列 
void QueueInit(Queue* q);
// 队尾入队列 
void QueuePush(Queue* q, QDataType data);
// 队头出队列 
void QueuePop(Queue* q);
// 获取队列头部元素 
QDataType QueueFront(Queue* q);
// 获取队列队尾元素 
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数 
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* q);
// 销毁队列 
void QueueDestroy(Queue* q);

Queue.c

#include "Queue.h"

初始化队列

void QueueInit(Queue* q)
{assert(q);q->front = NULL;q->rear = NULL;
}

队尾入队列

void QueuePush(Queue* q, QDataType data)
{assert(q);//创建一个节点放数据QNode* newNode=(QNode*)malloc(sizeof(QNode));if (newNode == NULL){perror("malloc fail");exit(-1);}newNode->data = data;newNode->next = NULL;//判断是否是第一个入队元素if (q->rear == NULL){q->front = q->rear = newNode;}else{q->rear->next= newNode;q->rear = newNode;}
}

在这里插入图片描述

队头出队列

void QueuePop(Queue* q)
{assert(q);assert(!QueueEmpty(q));//判断是否只有一个元素if (q->front->next == NULL){free(q->front);q->front = q->rear = NULL;}else{QNode* del = q->front;q->front = q->front->next;free(del);}
}

在这里插入图片描述

获取队列头部元素

front是队头节点,它的数据便是队头元素

QDataType QueueFront(Queue* q)
{assert(q);assert(!QueueEmpty(q));return q->front->data;
}

获取队列队尾元素

rear是队尾节点,它的数据便是队尾元素

QDataType QueueBack(Queue* q)
{assert(q);assert(!QueueEmpty(q));return q->rear->data;
}

获取队列中有效元素个数

遍历一遍链表就能得到有效元素个数,也可以直接给队列的结构里加上一个size

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

检测队列是否为空,如果为空返回非零结果,如果非空返回0

int QueueEmpty(Queue* q)
{assert(q);//队头节点为空说明队列为空return q->front == NULL;
}

销毁队列

void QueueDestroy(Queue* q)
{assert(q);QNode* cur = q->front;while (cur){QNode* curNext = cur->next;free(cur);cur = curNext;}q->front = q->rear = NULL;
}

五、设计循环队列

循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。
循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。

设计循环队列实现以下操作:

  • MyCircularQueue(k): 构造器,设置队列长度为 k 。
  • Front: 从队首获取元素。如果队列为空,返回 -1 。
  • Rear: 获取队尾元素。如果队列为空,返回 -1 。
  • enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
  • deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
  • isEmpty(): 检查循环队列是否为空。
  • isFull(): 检查循环队列是否已满。

创建队列时多开辟一个空间来区分空和满
如下是一个队列长度k=4的循环队列:
在这里插入图片描述
用数组实现

//循环队列结构
typedef struct {int* a;int front;int rear;int k;
} MyCircularQueue;
//初始化创建
MyCircularQueue* myCircularQueueCreate(int k) {MyCircularQueue* obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));//多开一个空间方便区分空和满obj->a=(int*)malloc(sizeof(int)*(k+1));obj->front=0;obj->rear=0;obj->k=k;return obj;
}
//判断队列是否为空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {//当队头和队尾相等时队列为空return obj->front==obj->rear;
}
//判断队列是否已满
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->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];
}
//获取队尾元素
//rear是队尾元素下一个元素的下标,所以队尾元素的下标为rear-1
//但当rear等于0的时候队尾元素下标为k,需要特殊处理
int myCircularQueueRear(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj)){return -1;}// if(obj->rear==0)// {//     return obj->a[obj->k];// }else// {//     return obj->a[obj->rear-1];// }return obj->a[((obj->rear)+(obj->k))%(obj->k+1)];
}

在这里插入图片描述

//销毁队列
void myCircularQueueFree(MyCircularQueue* obj) {free(obj->a);free(obj);
}

六、栈与队列的相互实现

1、用栈实现队列

实现 MyQueue 类:

  • void push(int x) 将元素 x 推到队列的末尾
  • int pop() 从队列的开头移除并返回元素
  • int peek() 返回队列开头的元素
  • boolean empty() 如果队列为空,返回 true ;否则,返回 false

思路:

用两个栈实现先入先出队列,当有元素入队时,就是在pushst入栈

在这里插入图片描述
当出队时,将pushst中元素依次出栈放进popst中,然后对popst进行出栈操作

在这里插入图片描述

代码实现:

用的是前面自己实现的栈来实现的

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 myQueuePeek(MyQueue* obj) {if(STEmpty(&obj->popst)){while(!STEmpty(&obj->pushst)){STPush(&obj->popst,STTop(&obj->pushst));STPop(&obj->pushst);}}return STTop(&obj->popst);
}int myQueuePop(MyQueue* obj) {int ret=myQueuePeek(obj);STPop(&obj->popst);return ret;
}bool myQueueEmpty(MyQueue* obj) {return STEmpty(&obj->pushst)&&STEmpty(&obj->popst);
}void myQueueFree(MyQueue* obj) {STDestroy(&obj->pushst);STDestroy(&obj->popst);free(obj);
}

2、用队列实现栈

实现 MyStack 类:

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

思路:

用两个队列q1和q2来实现一个后入先出的栈

入栈:放进不为空的那个队列
在这里插入图片描述

出栈:不为空队列的前n-1个出队列插入空队列,删除剩下的一个即可

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

用的是前面自己实现的队列来实现的

typedef struct {Queue q1;Queue q2;
} MyStack;MyStack* myStackCreate() {MyStack* p=(MyStack*)malloc(sizeof(MyStack));QueueInit(&p->q1);QueueInit(&p->q2);return p;
}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 top=QueueFront(noEmpty);QueuePop(noEmpty);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);
}

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

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

相关文章

前端面试自我介绍

前端面试自我介绍精选篇1 各位面试官大家好&#xff0c;我叫__&#xff0c;就读于__大学__学&#xff0c;大学本科学历&#xff0c;我的求职意向是与金融专业相关的职位&#xff0c;本人拥有较强的学习能力&#xff0c;能快速适应工作环境&#xff0c;兴趣爱好广泛&#xff0c…

日常BUG ——乱码

&#x1f61c;作 者&#xff1a;是江迪呀✒️本文关键词&#xff1a;日常BUG、BUG、问题分析☀️每日 一言 &#xff1a;存在错误说明你在进步&#xff01; 一、问题描述 A系统使用Feign调用B系统时&#xff0c;传递的String字符串&#xff0c;到了B系统中变为了乱…

HCIP STP(生成树)

目录 一、STP概述 二、生成树协议原理 三、802.1D生成树 四、STP的配置BPDU 1、配置BPDU的报文格式 2、配置BPDU的工作过程 3、TCN BPDU 4、TCN BPDU的工作过程 五、STP角色选举 1、根网桥选举 2、根端口选举 3、指定端口选举 4、非指定端口选举 六、STP的接口状…

QT中的PRO文件怎么进行相关的信息的注释?

小白学开发之QT下的PRO文件怎么进行注释&#xff0c;以及Pro文件的作用 Hello大家好&#xff0c;这里是程序员小白学开发&#xff0c;我是一个刚入门QT的初学者&#xff0c;晕乎晕乎的&#xff01;希望能够随时随地将自己所学的知识分享给大家&#xff0c;带着大学从零基础开始…

MySQL刷题遇到的盲点(五)窗口函数

窗口函数 语法&#xff1a; <窗口函数> over (partition by <用于分组的列名>order by <用于排序的列名>) partition by&#xff1a;用来对表分组&#xff08; partition 子句可以省略&#xff0c;省略就是不指定分组&#xff09; order by&#xff1a;是…

Docker 大热,还不了解 Dockerfile 你就OUT啦~

♥ 前 言 前言&#xff1a;近年来 Docker 非常火&#xff0c;想要玩好 Docker 的话 Dockerfile 是绕不开的&#xff0c;这就好比想要玩好 Linux 服务器绕不开 shell 道理是一样的。今天我们就来聊一聊 Dockerfile 怎么写&#xff0c;那些指令到底是什么意思。 一、先来看一…

【深度学习】StyleGANv2 2019 论文,Analyzing and Improving the Image Quality of StyleGAN

StyleGAN论文&#xff1a; 《A Style-Based Generator Architecture for Generative Adversarial Networks》 论文&#xff1a;https://arxiv.org/abs/1812.04948 代码&#xff1a; https://github.com/NVlabs/stylegan StyleGANv2论文&#xff1a; 《Analyzing and Improving …

绝了!学编程的还有不知道的吗?这个Java开发工具免费了!

智能开发正在迅速走红&#xff01; 随着ChatGPT的广泛应用&#xff0c;智能开发越来越受到关注。然而&#xff0c;实际上&#xff0c;在数年前开始尝试智能开发的探索。 自从2014年ForresterResearch提出"低代码"的概念以来&#xff0c;低代码平台的发展非常迅速。…

混合云环境中 Kubernetes 可观测性的 6 个有效策略...

2023 年&#xff0c;原生云应用程序和平台将快速增长。组织不断努力最大限度地发挥其应用程序的潜力&#xff0c;确保无缝的用户体验并推动业务增长。 混合云环境的兴起以及 Kubernetes 等容器化技术的采用彻底改变了现代应用程序的开发、部署和扩展方式。 在这个数字领域&am…

MCUXpresso for VS Code -- 基于VSCode开发RT1176

MCUXpresso for VS Code 是nxp推出插件&#xff0c;旗下MCX LPC, Kinetis和i.MX rt等MCU&#xff0c;都能在VS Code平台进行嵌入式开发。功能框图如下&#xff1a; 前期准备&#xff1a; 软件环境: windows(实际可以跨系统&#xff0c;linux和mac没有测试) VS Code ninja CMa…

【01】基础知识:typescript安装及使用,开发工具vscode配置

一、typescript 了解 typeScript 是由微软开发的一款开源的编程语言。 typeScript 是 javascript 的超级&#xff0c;遵循最新的 es6、es5规范。 typeScript 扩展了 javaScript 的语法。 typeScript 更像后端 java、C# 这样的面向对象语言&#xff0c;可以让 js 开发大型企…

Oracle-创建PDB

Oracle-创建PDB 创建PDB的方式 从PDB$SEED新建PDB克隆已存在的PDB 本地PDB克隆到同一个CDB中将远程PDB克隆到CDB中将非CDB插入或克隆到CDB中通过插拔的方式创建PDB sql 命令语法 条件 CDB必须open并且read write模式连接CDB$ROOT 用户并且具有CREATEPLUGGABLEDATABASE系统权…

如何快速解决集成环信IM遇到的问题?

1、环信FAQ频道发布了 环信FAQ帮助中心提供了各客户端、RESTful API、环信控制台以及商务相关的集成环信常见问题及解决方法&#xff0c;帮您快速解决集成问题 2、当我有问题时&#xff0c;从哪里进FAQ&#xff1f; 干脆收藏这个网址&#xff1a;https://faq.easemob.com/ 环…

Android的学习系列之Android Studio Setup安装

Android的学习系列之Android Studio Setup安装 [TOC](Android的学习系列之Android Studio Setup安装) 前言Android平台搭建总结 前言 还是项目需要&#xff0c;暂时搭建安卓的运行平台。 Android平台搭建 安装包 双击安装包&#xff0c;进入安装。 下一步 根据自己需求&a…

Flink源码之JobMaster启动流程

Flink中Graph转换流程如下&#xff1a; Flink Job提交时各种类型Graph转换流程中&#xff0c;JobGraph是Client端形成StreamGraph后经过Operator Chain优化后形成的&#xff0c;然后提交给JobManager的Restserver&#xff0c;最终转发给JobManager的Dispatcher处理。 Completa…

24数据结构-图的基本概念与存储结构

目录 第六章 图6.1 图的基本概念知识回顾 6.2 图的储存结构&#xff08;邻接矩阵法&#xff09;1. 数组表示法(1) 有向图&#xff0c;无向图的邻接矩阵 2. 定义邻接矩阵的结构3. 定义图的结构4. 构造图G5. 特点 第六章 图 6.1 图的基本概念 图是一种非线性结构 图的特点&am…

手把手教你快速实现内网穿透

快速内网穿透教程 文章目录 快速内网穿透教程前言*cpolar内网穿透使用教程*1. 安装cpolar内网穿透工具1.1 Windows系统1.2 Linux系统1.2.1 安装1.2.2 向系统添加服务1.2.3 启动服务1.2.4 查看服务状态 2. 创建隧道映射内网端口3. 获取公网地址 前言 要想实现在公网访问到本地的…

海康威视iVMS综合安防系统任意文件上传(0Day)

漏洞描述 攻击者通过请求/svm/api/external/report接口任意上传文件,导致获取服务器webshell权限,同时可远程进行恶意代码执行。 免责声明 技术文章仅供参考,任何个人和组织使用网络应当遵守宪法法律,遵守公共秩序,尊重社会公德,不得利用网络从事危害国家安全、荣誉和…

为什么商业基础软件需要开源

Bytebase 本身是一家商业软件公司&#xff0c;而作为最核心资产的代码从 Day 0 却是开源的。同时我们还是 star-history.com 的运营者&#xff0c;大家在各种开源渠道会看到它生成的图&#xff1a; 一直以来&#xff0c;常会被别人问起的一个问题&#xff0c;就是为什么 Byteba…

【学习日记】【FreeRTOS】任务句柄、任务控制块TCB、任务栈、任务、就绪表详解

写在前面 本文是对FreeRTOS中任务句柄、任务控制块TCB、任务栈、任务、就绪表详解。 一、裸机和RTOS中函数存储位置详解 左图为裸机开发时 RAM 的使用情况&#xff0c;右图是使用了 FreeRTOS 后 RAM 的使用情况&#xff08;图片来自野火&#xff09;。 无论是裸机开发还是Fr…