【数据结构初阶】六、线性表中的队列(链式结构实现队列)

=========================================================================

相关代码gitee自取

C语言学习日记: 加油努力 (gitee.com)

 =========================================================================

接上期

【数据结构初阶】五、线性表中的栈(顺序表实现栈)_高高的胖子的博客-CSDN博客

 =========================================================================

                     

1 . 队列(Queue)

队列的概念和结构:

队列的概念

  • 队列是一种只允许在一端执行插入数据操作另一端进行删除数据操作特殊线性表
                      
  • 入队列 -- 进行插入操作的一端称为队尾
    出队列 -- 进行删除操作的一端称为队头

                
  • 队列中的数据元素遵守
    先进先出FIFO -- First In First Out)的原则 -- 先进入的元素会先出来
    所以可以应用在公平性排队(抽号机)、BFS(广度优先遍历)
                        

队列的结构

         

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

             

2 . 队列的实现

                

使用 顺序表(数组)链表(链式结构) 都可以实现队列

使用顺序表的话,入队列比较简单,但在出队列时需要删除和挪动数据效率较低

所以下面用链表(链式结构)实现队列  --  单向 + 无头 + 非循环 链表

入队 -- 单链表尾部插入(尾插)         ;      出队 -- 单链表头部删除(头删)

               

(详细解释在图片的注释中,代码分文件放下一标题处)

               

实现具体功能前的准备工作

  • 定义队列(链式结构)中数据域存储的数据类型
                               
  • 定义队列(链式结构)结点类型
    包含 队列指针域 队列数据域
                 
  • 定义队列类型
    包含 头结点指针尾结点指针 和 队列结点(元素)个数
图示

            

            

---------------------------------------------------------------------------------------------

            

QueueInit函数 -- 将队列进行初始化

  • assert断言队列类型指针不为空
                               
  • 队头结点置为空
    队尾结点置为空
    队列结点(元素)个数置为0
图示

            

            

---------------------------------------------------------------------------------------------

            

QueueDestroy函数 -- 将队列销毁

  • assert断言队列类型指针不为空
                               
  • 创建一个在队列进行遍历的指针cur
    使用while循环进行遍历释放队列结点
                 
  • 结点都释放后,把队头队尾指针都置空
                   
  • 再把队列结点(元素)个数置为0
图示

            

            

---------------------------------------------------------------------------------------------

            

QueuePush函数 -- 用链表的尾插操作实现入队

  • assert断言队列类型指针不为空
                               
  • 为队列结点开辟动态空间检查空间开辟情况
                 
  • 结点开辟成功
    尾插值(x)赋给队列结点的数据域并将指针域置为空
                   
  • 空间开辟后进行尾插
    如果队列刚初始化队列为空,将刚开辟的结点newnode地址赋给头尾结点指针
    队列不为空正常进行尾插操作
                
  • 插入数据后队列结点(元素)个数++
图示

            

            

---------------------------------------------------------------------------------------------

            

QueuePop函数 -- 用链表的头删操作实现出队

  • assert断言队列类型指针不为空队列不为空
                               
  • 出队(头删)分两种情况
    队列中只剩一个结点 -- 头删后头指针移动尾指针也要移动
    队列不止一个结点 -- 头删后只需移动队头结点
                 
  • 删除队列结点(元素)个数--
图示

            

            

---------------------------------------------------------------------------------------------

            

QueueFront函数 -- 返回队头结点的数据域数据

  • assert断言队列类型指针不为空队列不为空
                               
  • 队列有数据,则直接返回队头结点数据域数据
图示

            

            

---------------------------------------------------------------------------------------------

            

QueueBack函数 -- 返回队尾结点的数据域数据

  • assert断言队列类型指针不为空队列不为空
                               
  • 队列有数据,则直接返回队尾结点数据域数据
图示

            

            

---------------------------------------------------------------------------------------------

            

QueueEmpty函数 -- 判断队列是否为空

  • assert断言队列类型指针不为空
                               
  • 直接判断队头结点指向的下个结点是否为空直接返回判断结果
图示

            

            

---------------------------------------------------------------------------------------------

            

QueueSize函数 -- 判断队列结点(元素)个数

  • assert断言队列类型指针不为空
                               
  • 直接返回size队列结点(元素)个数
图示

            

            

---------------------------------------------------------------------------------------------

            

总体测试:

         

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

             

3 . 对应代码

Queue.h -- 队列头文件

#pragma once//包含之后需要的头文件:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>//以链表(链式结构)实现队列:
//双向+循环 的链表可以解决找尾结点的问题,
//定义一个尾指针也可以解决该问题,
//哨兵位 可以解决二级指针的问题,
//且尾插时可以少一层判断,但还有方法可以解决//定义队列(链式结构)中数据域存储的数据类型:
typedef int QDataType;//定义队列(链式结构)结点类型:
typedef struct QueueNode
{//队列指针域:struct QueueNode* next;//队列数据域:QDataType data;}QNode; //将类型重命名为Qnode//定义队列类型:
typedef struct Queue
{//因为用链表尾插实现入队,//用链表头删实现出队,//那么就需要头结点和尾结点的指针,//所以可以直接将这两个指针封装为一个类型,//队列类型://头结点指针:QNode* head;//尾结点指针:QNode* tail;//记录队列结点(元素)个数:int size; //这样之后在出队和入队操作时,//就不需要用到二级指针,//直接接收这个结构体指针,//通过结构体指针运用结构体里的头尾结点指针,//再用头尾结点指针定义头尾结点//来实现 二级指针、带哨兵位头结点 和 返回值 的作用//所以现在已知的通过指针定义结点的方法就有4种://		1. 结构体包含结点指针//		2. 二级指针调用结点指针//		3. 哨兵位头结点指针域next指向结点地址//		4. 返回值返回改变的结点指针}Que; //重命名为Que//队列初始化函数 -- 将队列进行初始化
//接收队列类型指针(包含链表头尾结点) 
void QueueInit(Que* pq);//队列销毁函数 -- 将队列销毁
//接收队列类型指针(包含链表头尾结点) 
void QueueDestroy(Que* pq);//队列入队函数 -- 用链表的尾插操作实现入队
//接收队列类型指针(包含链表头尾结点) 、尾插值
void QueuePush(Que* pq, QDataType x);//队列出队函数 -- 用链表的头删操作实现出队
//接收队列类型指针(包含链表头尾结点) 
void QueuePop(Que* pq);//队头函数 -- 返回队头结点的数据域数据
//接收队列类型指针(包含链表头尾结点) 
QDataType QueueFront(Que* pq);//队尾函数 -- 返回队尾结点的数据域数据
//接收队列类型指针(包含链表头尾结点) 
QDataType QueueBack(Que* pq);//判空函数 -- 判断队列是否为空
//接收队列类型指针(包含链表头尾结点) 
bool QueueEmpty(Que* pq);//队列大小函数 -- 判断队列结点(元素)个数
//接收队列类型指针(包含链表头尾结点) 
int QueueSize(Que* pq);

            

            

---------------------------------------------------------------------------------------------

                

Queue.c -- 队列函数实现文件

#define _CRT_SECURE_NO_WARNINGS 1//包含队列头文件:
#include "Queue.h"//队列初始化函数 -- 将队列进行初始化
//接收队列类型指针(包含链表头尾结点) 
void QueueInit(Que* pq)
{//assert断言队列类型指针不为空:assert(pq != NULL);//将队头结点置为空:pq->head = NULL;//将队尾结点置为空:pq->tail = NULL;//队列结点(元素)个数置为0:pq->size = 0;
}//队列销毁函数 -- 将队列销毁
//接收队列类型指针(包含链表头尾结点) 
void QueueDestroy(Que* pq)
{//assert断言队列类型指针不为空:assert(pq != NULL);//释放队列跟单链表的释放一样//先创建一个在队列进行遍历的指针:QNode* cur = pq->head; //从队头结点开始//使用while循环进行遍历释放队列结点:while (cur != NULL)	{//先保存下个结点:QNode* next = cur->next;//再释放当前结点:free(cur);//再指向下个结点:cur = next;}//结点都释放后,把队头队尾指针都置空:pq->head = NULL;pq->tail = NULL;//再把队列结点(元素)个数置为0:pq->size = 0;
}//队列入队函数 -- 用链表的尾插操作实现入队
//接收队列类型指针(包含链表头尾结点) 、尾插值
void QueuePush(Que* pq, QDataType x)
{//assert断言队列类型指针不为空:assert(pq != NULL);//入队放入元素需要空间,//所以要先为队列结点开辟动态空间:QNode* newnode = (QNode*)malloc(sizeof(QNode));//检查是否开辟成功:if (newnode == NULL){//开辟失败则打印错误信息:perror("malloc fail");//终止程序:exit(-1);}//队列结点完成后将尾插值(x)//赋给队列结点数据域:newnode->data = x;//指针域指向空:newnode->next = NULL;//空间开辟后进行尾插:if (pq->tail == NULL)//如果队列刚初始化,队列为空,//头结点指针和尾结点指针都为空:{//那么将刚开辟的结点newnode地址//赋给头结点指针和尾结点指针pq->head = newnode;pq->tail = newnode;}else//队列不为空,进行尾插:{//将目前队尾结点指针域next指向尾插结点:pq->tail->next = newnode;//然后再指向尾插结点,成为新队尾结点:pq->tail = newnode;}//插入数据后队列结点(元素)个数++:pq->size++;
}//队列出队函数 -- 用链表的头删操作实现出队
//接收队列类型指针(包含链表头尾结点) 
void QueuePop(Que* pq)
{//assert断言队列类型指针不为空:assert(pq != NULL);//assert断言队列不为空,没数据不能删除:  assert(QueueEmpty != true); //不为空就继续程序//如果队列中只剩一个结点:if (pq->head->next == NULL)//队头指针指向空,说明只剩一个结点,//只剩一个结点说明队头队尾指针都指向这一个结点,//所以这时头删后头指针移动,尾指针也要移动{//先释放("删除")队列目前头结点:free(pq->head);//删除后将队头队尾指针都置为空:pq->head = NULL;pq->tail = NULL;}else//队列不止一个结点,则头删后只需移动队头结点:{//用链表的头删操作实现出队,//先保存第二个结点地址:QNode* next = pq->head->next;//释放("删除")队列目前头结点:free(pq->head);//再将队头结点指针指向原本第二个结点next,//让其成为新的队头结点:pq->head = next;}//“删除”后队列结点(元素)个数--:pq->size--; 
}//队头函数 -- 返回队头结点的数据域数据
//接收队列类型指针(包含链表头尾结点) 
QDataType QueueFront(Que* pq)
{//assert断言队列类型指针不为空:assert(pq != NULL);//assert断言队列不为空,没数据不能查找:  assert(QueueEmpty != true); //不为空就继续程序//队列有数据,则直接返回队头结点数据域数据:return pq->head->data;
}//队尾函数 -- 返回队尾结点的数据域数据
//接收队列类型指针(包含链表头尾结点) 
QDataType QueueBack(Que* pq)
{//assert断言队列类型指针不为空:assert(pq != NULL);//assert断言队列不为空,没数据不能查找:  assert(QueueEmpty != true); //不为空就继续程序//队列有数据,则直接返回队尾结点数据域数据:return pq->tail->data;
}//判空函数 -- 判断队列是否为空
//接收队列类型指针(包含链表头尾结点) 
bool QueueEmpty(Que* pq)
{//assert断言队列类型指针不为空:assert(pq != NULL);//直接判断队头结点指向的下个结点是否为空:return pq->head == NULL; //是则返回true -- 队列为空//是则返回false -- 队列不为空
}//队列大小函数 -- 判断队列结点(元素)个数
//接收队列类型指针(包含链表头尾结点) 
int QueueSize(Que* pq)
{//assert断言队列类型指针不为空:assert(pq != NULL);//直接返回size队列结点(元素)个数:return pq->size;
}

            

            

---------------------------------------------------------------------------------------------

                

Test.c -- 队列测试文件

#define _CRT_SECURE_NO_WARNINGS 1//包含队列头文件:
#include "Queue.h"//队列测试函数:
void TestQueue()
{//创建队列类型:Que q;//对队列类型进行初始化:QueueInit(&q);//进行入队操作:QueuePush(&q, 1);QueuePush(&q, 2);QueuePush(&q, 3);QueuePush(&q, 4);QueuePush(&q, 5);//当前队尾值:printf("当前队尾值:%d\n", QueueBack(&q));//当前队列元素个数:printf("当前队列元素个数:%d\n", QueueSize(&q));//换行:printf("\n");//使用while循环遍历进行出队://(类似抽号机,当前号抽完就到下个号)while (!QueueEmpty(&q))//队列不为空就继续出队:{//打印出队值:printf("当前出队值为:%d\n", QueueFront(&q));//进行出队:QueuePop(&q); //出队后打印下个出队值}//换行:printf("\n");//当前队列元素个数:printf("当前队列元素个数:%d", QueueSize(&q));//销毁队列:QueueDestroy(&q);
}//主函数:
int main()
{//调用队列测试函数:TestQueue();return 0;
}

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

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

相关文章

PSINS工具箱学习(一)下载安装初始化、SINS-GPS组合导航仿真、习惯约定与常用变量符号、数据导入转换、绘图显示

原始 Markdown文档、Visio流程图、XMind思维导图见&#xff1a;https://github.com/LiZhengXiao99/Navigation-Learning 文章目录 一、前言二、相关资源三、下载安装初始化1、下载PSINSyymmdd.rar工具箱文件2、解压文件3、初始化4、启动工具箱导览 四、习惯约定与常用变量符号1…

数据集笔记:2015上海地铁一卡通数据

数据地址&#xff1a;上海地铁数据_免费高速下载|百度网盘-分享无限制 (baidu.com) 数据介绍 上海2015年几天的地铁一卡通出入站信息 卡号、交易日期、交易时间、公交线路/地铁站点中文名称、行业名称(公交、地铁、出租、轮渡、PR停车场)、交易金额、交易性质(非优惠、优惠、…

No139.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

RNN模型与NLP应用(1/9):数据处理基础Data Processing Basics

文章目录 处理分类特征把分类特征转化为数值特征应用one-hot编码indice要从1开始而不能从0开始数据处理为什么使用one-hot向量 处理文本数据Step1&#xff1a;将文本分割成单词Step2&#xff1a;计算单词的频度按频度递减的方式排序 Step3&#xff1a;One-Hot编码 处理分类特征…

UE5 ChaosVehicles载具研究

一、基本组成 载具Actor类名称&#xff1a;WheeledVehiclePawn Actor最原始的结构 官方增加了两个摇臂相机&#xff0c;可以像驾驶游戏那样切换多机位、旋转观察 选择骨骼网格体、动画蓝图类、开启物理模拟 二、SportsCar_Pawn 角阻尼&#xff1a;物体旋转的阻力。数值越大…

前端架构师之02_ES6_高级

1 类和继承 1.1 class类 JavaScript 语言中&#xff0c;生成实例对象的传统方法是通过构造函数。 // ES5 创建对象 // 创建一个类&#xff0c;用户名 密码 function User(name,pass){// 添加属性this.name name;this.pass pass; } // 用 原型 添加方法 User.prototype.sho…

Docker下如何构建包含延迟插件的RabbitMQ镜像

&#x1f468;&#x1f3fb;‍&#x1f4bb; 热爱摄影的程序员 &#x1f468;&#x1f3fb;‍&#x1f3a8; 喜欢编码的设计师 &#x1f9d5;&#x1f3fb; 擅长设计的剪辑师 &#x1f9d1;&#x1f3fb;‍&#x1f3eb; 一位高冷无情的编码爱好者 大家好&#xff0c;我是 DevO…

FIPS 140简介

FIPS 140(Federal Information Processing Standards Publication 140)是美国联邦政府颁布的一系列密码学标准,用于评估和验证安全模块(如加密模块)的安全性。FIPS 140标准制定了一系列安全要求,以确保加密模块能够提供足够的安全性,以保护敏感数据。 与AES的关系是,A…

UE5 虚幻引擎 如何使用构造脚本(Construction Script)? 构造脚本的奥秘!

目录 1 构造脚本&#xff08;Construction Script&#xff09;1.1 介绍1.2 案例1&#xff1a;利用样条组件程序化生成树木1.2 案例2&#xff1a;利用样条组件和样条网格体组件程序化生成道路 1 构造脚本&#xff08;Construction Script&#xff09; 1.1 介绍 问题&#xff1a…

3D孪生场景搭建:模型阵列摆放

阵列摆放概念 阵列摆放是指将物体、设备或元件按照一定的规则和间距排列组合的方式。在工程和科学领域中&#xff0c;阵列式摆放常常用于优化空间利用、提高效率或增强性能。 阵列摆放通常需要考虑间距、角度、方向、对称性等因素&#xff0c;以满足特定的要求和设计目标。不同…

江西广电会展集团总经理李悦一行莅临拓世科技集团调研参观,科技璀璨AIGC掀新潮

在江西这片充满活力的土地上&#xff0c;数字经济如潮水般涌动&#xff0c;会展文化与科技的完美结合&#xff0c;正如新时代的璀璨繁星照亮夜空&#xff0c;更预示着一场AIGC创新的壮丽篇章即将展开。作为拓世科技集团的老朋友&#xff0c;江西广电多位领导多次莅临拓世科技集…

Elasticsearch:与多个 PDF 聊天 | LangChain Python 应用教程(免费 LLMs 和嵌入)

在本博客中&#xff0c;你将学习创建一个 LangChain 应用程序&#xff0c;以使用 ChatGPT API 和 Huggingface 语言模型与多个 PDF 文件聊天。 如上所示&#xff0c;我们在最最左边摄入 PDF 文件&#xff0c;并它们连成一起&#xff0c;并分为不同的 chunks。我们可以通过使用 …

项目集成七牛云存储sdk

以PHP为例 第一步&#xff1a;下载sdk PHP SDK_SDK 下载_对象存储 - 七牛开发者中心 sdk下载成功之后&#xff0c;将sdk放入项目中&#xff0c;目录选择以自己项目实际情况而定。 注意&#xff1a;在examples目录中有各种上传文件的参考示例&#xff0c;这里我们主要参考的是…

如何注册一个 DA 为 10 的高价值老域名

众所周知&#xff0c;由于域名存在唯一性&#xff0c;随着人们注册的越多&#xff0c;好域名也变得越来越少&#xff0c;渐渐成为稀缺的网络资源。这个时候要想拥有好的域名&#xff0c;抢注优质老域名就成了广大米友的路径之一。 优质的高价值域名都有一个特点&#xff0c;那…

MySQL数据库入门到精通1--基础篇(MySQL概述,SQL)

1. MySQL概述 1.1 数据库相关概念 目前主流的关系型数据库管理系统&#xff1a; Oracle&#xff1a;大型的收费数据库&#xff0c;Oracle公司产品&#xff0c;价格昂贵。 MySQL&#xff1a;开源免费的中小型数据库&#xff0c;后来Sun公司收购了MySQL&#xff0c;而Oracle又收…

如何快速学习AdsPower RPA(2)——中级、高级部分

Tool哥继续给大家分享快速学习AdsPower RPA的方法。上一篇在这里&#xff0c;还没看过的小伙伴赶快补课去&#xff1a;如何快速学习AdsPower RPA&#xff08;1&#xff09;——简单、进阶部分 能进入到中级、高级阶段的学习&#xff0c;说明你自学能力超强&#xff01;只要跟着…

创建型设计模式——工厂模式

摘要 本博文主要介绍软件设计模式中工厂模式&#xff0c;其中工厂设计模式的扩展为简单工厂(Simple Factory)、工厂方法(Factory Method)、抽象工厂(Abstract Factory)三种。 一、简单工厂(Simple Factory) 主要分析设计模式 - 简单工厂(Simple Factory)&#xff0c;它把实例…

微信小程序,动态设置三级联动, 省市区街道

1.第一步 传parentId0 查询省份 2.第二步 选择省份,传pathId选择省份的pathId, 不传parentId,会查询出 市/县数据 3.第三步 根据选择县的parentId 查询街道数据,传parentId选择的县id 4.选择结果回显 显示所选择的 path 以/分割 取最后一级<van-dropdown-menu…

Pygame中监控鼠标动作的方法

在Pygame中监控键盘按键的方法_pygame获取键盘输入-CSDN博客中提到&#xff0c;通过在while True循环中获取队列中事件的方法监控键盘动作。监控鼠标动作的方法与监控键盘动作的方法相同。 相关连接1 队列与事件的相关知识&#xff0c;请参考 Pygame中监控键盘按键的方法_pyg…

【Servlet】Servlet API 详解

Servlet API 详解 一. HttpServlet1. 核心方法2. 代码示例: 处理 GET 请求3. 关于乱码问题4. 代码示例: 处理 POST 请求 二. HttpServletRequest1. 核心方法2. 代码示例: 打印请求信息3. 代码示例: 获取 GET 请求中的参数4. 代码示例: 获取 POST 请求中的参数(1)5. 代码示例: 获…