DS线性表之队列的讲解和实现(5)

文章目录

  • 前言
  • 一、队列的概念及结构
  • 二、队列的实现
    • 队列节点和队列
    • 初始化
    • 销毁
    • 判断是否为空
    • 入队列
    • 出队列
    • 获取队头队尾数据
    • 获取队列元素个数
  • 三、实际使用效果
  • 总结


前言

  队列实现源代码
  队列是我们遇到的第二个实用数据结构,栈和队列地位等同


一、队列的概念及结构

  队列是指只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表。队列具有先进先出 FIFO(First In First Out) 这一点跟栈的先进后出是相反的

队列的核心操作有两个:

  • 入队列:即尾插,进行插入操作的一端称为队尾
  • 出队列:即头删,进行删除操作的一端称为对头

在这里插入图片描述

队列可以考虑顺序表和链表来实现,但是因为队列是一种一端插入一端删除的数据结构,所以最好的实现方式是头删尾插效率高的方式

  1. 顺序表实现:尾插和尾删效率较高,但是头插和头删效率低,因此不太适合
  2. 单链表实现:头删尾插效率较高,链表头删,链表尾插
  3. 双向链表实现:头插头删尾插尾删效率都较高,可以实现队列

照这么看,似乎双向链表是最完美的答案

但是实际上,我们是采用第二种单链表来实现队列,你可能会差异,单链表要遍历一遍才能到达尾节点,而双向链表可以在常量操作内访问到尾节点,为什么我们还会采用单链表来实现队列呢?

答案是我们定义一个队列节点结构体的前提下,在定义一个队列的结构体,里面放着两个队列节点指针front、tail,这样双向链表这里就显得过于复杂,且多开辟了一个头节点,浪费了一点空间,也是不太适合的一种体现

二、队列的实现

  好,掌握了以上知识后,我们来立刻实现!

队列节点和队列

就像前文说的,我们定义两个结构体来实现队列
大致有点像下图:
在这里插入图片描述

typedef int QDataType;
typedef struct QueueNode
{struct QueueNode* next;QDataType data;
}QNode;typedef struct Queue
{QNode* head;QNode* tail;// 根据需要甚至还可以定义一个大小变量// int size;
}Queue;

初始化

首先我们肯定要先验空,确保我们确确实实实例化了一个队列结构体q,此时q内部的两个指针,我们需要先置空

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

销毁

动态开辟的内存,需要手动释放,且由于是链表,所以需要一个一个循环释放
因此思路就是通过一个指针变量cur,一直销毁直到指向为空
在这里插入图片描述

void QueueDestroy(Queue* pq)
{assert(pq);QNode* cur = pq->head;while (cur != NULL){QNode* next = cur->next;free(cur);cur = next;}pq->head = pq->tail = NULL; // 头尾节点指针所指向的内容已被回收,因此不置空将成为野指针
}

判断是否为空

我们看初始化函数就知道,当队列为空的时候,头节点指针为空指针(其实尾节点指针也是~),我们可以通过这个来判断

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

入队列

入队就是尾插
在这里插入图片描述
但是我们要分两种情况,一种是队列有数据,另外一种是队列没有数据的时候,这时候头尾节点指针都指向这个新开辟的节点;如果队列已经有数据了,这时候尾节点指针发生变化

void QueuePush(Queue* pq, QDataType val)
{assert(pq);QNode* newNode = (QNode*)malloc(sizeof(QNode));if (newNode == NULL){printf("malloc fail\n");exit(-1);}newNode->data = val;newNode->next = NULL;if (pq->tail == NULL){ // 如果无数据,用pq->head来判断也行pq->head = pq->tail = newNode;}else {pq->tail->next = newNode;pq->tail = newNode; // 此时newNode就是新的尾节点}
}

出队列

出队就是头删
在这里插入图片描述

void QueuePop(Queue* pq)
{assert(pq);assert(pq->head);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;
}

获取队列元素个数

其实你的队列如果有size变量的话,那这里应该蛮简单,只是我这里提供的没有,那么就是经典的遍历套路

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

三、实际使用效果

// 各接口一览
void QueueInit(Queue* pq);
void QueueDestroy(Queue* pq);void QueuePush(Queue* pq, QDataType val);
void QueuePop(Queue* pq);QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);
int QueueSize(Queue* pq);bool isQueueEmpty(Queue* pq);

在这里插入图片描述


总结

  栈和队列,将会贯穿我们后面的学习,所以,请对它们有深刻的认识

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

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

相关文章

一篇python常见的Pandas的数据功能的使用

当我们学习了如何使用 Pandas 进行数据的导入与导出,这为我们后续的数据处理打下了基础.此次我们将重点讨论数据选择与过滤.通过掌握这一部分的知识,你将能够轻松地从复杂的数据集中提取出所需的信息.接下来,我们将通过一些实例来逐步了解这些操作. 这里插播一条粉丝福利&#…

前端技巧汇总

保持盒子在中间位置&#xff1a; 中间盒子设置位绝对定位 上下左右都设置为0 margin为auto中间 <!doctype html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport"content"widthdevice-width,…

三、AOP

文章目录 1. AOP&#xff08;概念&#xff09;2. AOP&#xff08;底层原理&#xff09;2.1 AOP 底层使用动态代理2.2 AOP&#xff08;JDK动态代理&#xff09; 3. AOP&#xff08;术语&#xff09;3.1 连接点3.2 切入点3.3 通知&#xff08;增强&#xff09;3.4 切面 4. AOP操作…

Element中el-table组件设置max-height右侧出现空白列的解决方法

之前就出现过这个情况&#xff0c;没理过&#xff0c;因为不影响啥除了不美观...但今天看着实在是难受&#xff0c;怎么都不顺眼(可能是我自己烦躁--) 试了很多网上的方法&#xff0c;都不得行&#xff0c;后面发现了这篇文章&#xff0c;解决了! 感谢&#xff01; Element中t…

深度学习:生成对抗网络(Generative Adversarial Network, GAN)

生成对抗网络&#xff08;Generative Adversarial Network, GAN&#xff09; 生成对抗网络&#xff08;GAN&#xff09;是一种深度学习模型&#xff0c;最初由Ian Goodfellow于2014年提出。这种模型框架通过让两个神经网络——生成器&#xff08;Generator&#xff09;和判别器…

SpringBoot人事系统:企业人才资源的智能管家

6系统测试 6.1概念和意义 测试的定义&#xff1a;程序测试是为了发现错误而执行程序的过程。测试(Testing)的任务与目的可以描述为&#xff1a; 目的&#xff1a;发现程序的错误&#xff1b; 任务&#xff1a;通过在计算机上执行程序&#xff0c;暴露程序中潜在的错误。 另一个…

fastadmin 多商户模式下侧边栏跳转路径BUG

记录&#xff1a;仅作自己项目记录&#xff0c;在一个域名下部署多套项目时&#xff0c;若是多商户模式项目会出现跳转路径问题。 修改 \manystore\library\Auth.php 文件的 getSidebar 方法 // 1 改为&#xff1a; $v[url] isset($v[url]) && $v[url] ? $v[url] :…

霍尼C200系统CC-TUIO31通用输入输出模块电厂用

霍尼C200系统CC-TUIO31通用输入输出模块电厂用,CC-TUIO31技术参数,CC-TUIO31说明书,霍尼韦尔官网,霍尼韦尔代理商,Honeywell官网,Honeywell代理商, gnote: , titlecolor: , description: 易于维护&#xff1a;模块化设计&#xff0c;便于安装、维护和更换&#xff0c;减少停机时…

JavaSE

线程 1. 区分程序、进程、线程 程序&#xff1a;为实现某种功能&#xff0c;使用计算机语言编写的一系列指令的集合。 进程&#xff1a;是运行中的程序&#xff08;如运行中的原神&#xff09;进程是操作系统进行资源分配的最小单位。 线程&#xff1a;进程可以进一步细化为线…

斯坦福UE4 C++课学习补充25:AI感知组件

文章目录 一、引入感知组件并绑定委托二、优化角色旋转 一、引入感知组件并绑定委托 PawnSensingComponent是UE中用于感知其他 Pawn&#xff08;或 Actor&#xff09;存在的一个组件&#xff0c;常用于 AI 角色的视觉、听觉等感知功能。它为 AI 提供了基础的感知能力&#xff…

关于WPF(Windows Presentation Foundation)中Grid控件

本文将从Grid控件的基础概念开始&#xff0c;逐步深入探讨其特性、用法、实例代码&#xff0c;以及最佳实践。 1. WPF和布局简介 WPF是一种用于构建Windows桌面应用程序的UI框架&#xff0c;它通过XAML&#xff08;Extensible Application Markup Language&#xff09;使开…

PDF编辑不求人!4款高效工具,内容修改从此变得简单又快捷

咱们现在生活在一个数字时代&#xff0c;PDF文件可不就是工作、学习还有日常生活中经常要用的东西嘛。但遇到那些需要改动的PDF文件&#xff0c;是不是就觉得有点头疼啊&#xff1f; 因为传统的PDF文件真的不好编辑&#xff0c;这确实挺烦人的。不过呢&#xff0c;我今天要给你…

文本语义检索系统的搭建过程,涵盖了召回、排序以及Milvus召回系统、短视频推荐等相关内容

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下本文详细介绍了文本语义检索系统的搭建过程&#xff0c;涵盖了召回、排序以及Milvus召回系统的相关内容。通过使用PyTorch框架&#xff0c;我们提供了样例代码&#xff0c;以帮助读者更好地理解和实践。该系统具有广…

systemd实现seatunnel自动化启停

在 systemd 中,您可以通过配置服务单元文件来设置服务在失败或退出后自动重启。这对于确保关键服务在意外退出时能够自动恢复运行非常有用。下面是实现 systemd 自动重启服务的步骤: 通用操作 1. 创建或编辑服务单元文件 假设服务单元文件位于 /etc/systemd/system/my-ser…

深入解析Vue中的双向数据绑定机制

文章目录 一、双向数据绑定的概念单向绑定与双向绑定的区别双向绑定的实例 二、双向绑定的原理MVVM架构ViewModel的工作原理 三、Vue中的双向绑定实现双向绑定流程实现双向绑定的关键代码 一、双向数据绑定的概念 单向绑定与双向绑定的区别 单向绑定是将模型&#xff08;Mode…

VR全景摄影的拍摄和编辑软件推荐

随着虚拟现实技术的不断进步&#xff0c;VR全景摄影逐渐成为商业、娱乐和教育等多个领域中的重要工具。通过专业的设备与软件&#xff0c;摄影师能够创作出沉浸式的360度全景作品&#xff0c;为观众提供身临其境的视觉体验。在这篇文章中&#xff0c;我们将介绍VR全景摄影的相关…

C# 两个进程/exe通讯方式 两个应用程序通讯方式

C# 两个exe通讯方式 两个应用程序通讯方式 1. 命名管道&#xff08;Named Pipes&#xff09; 1.1. 概述 命名管道是一种用于在同一台机器或网络中不同进程之间进行双向通信的机制。它支持同步和异步通信&#xff0c;适用于需要高效数据传输的场景。 1.2. 特点 双向通信&am…

【vue+printJs】前端打印, 自定义字体大小, 自定义样式, 封装共享样式

效果示例 思维导图 目录 1,基本使用1, 依赖下载2, 页面导入3, 修改字体大小(可行但不推荐) 2, 自定义样式,字体大小1, 修改字体大小(推荐)2, 自定义样式3, 封装共享样式 3, 去除页面页脚内容4, 测试案例demo, 直接cv可用5, print-js的其他参数说明 1,基本使用 1, 依赖下载 …

MyBatis-Plus 之 typeHandler 的使用

一、typeHandler 的使用 1、存储json格式字段 如果字段需要存储为json格式&#xff0c;可以使用JacksonTypeHandler处理器。使用方式非常简单&#xff0c;如下所示&#xff1a; 在domain实体类里面要加上&#xff0c;两个注解 TableName(autoResultMap true) 表示自动…

学习之面试题:偏函数

偏函数&#xff08;Partial Function&#xff09;是 Python 中的一个实用工具&#xff0c;通常用于函数式编程中&#xff0c;可以固定一个函数的部分参数&#xff0c;从而生成一个新的函数。偏函数在 Python 中通常通过 functools.partial 实现。在面试中&#xff0c;考察偏函数…