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

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

相关代码gitee自取

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

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

接上期

【数据结构初阶】五、线性表中的栈(C语言 -- 顺序表实现栈)_高高的胖子的博客-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.xdnf.cn/news/149768.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

mysql面试题16:说说分库与分表的设计?常用的分库分表中间件有哪些?分库分表可能遇到的问题有哪些?

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:说说分库与分表的设计? 在MySQL中,分库与分表是常用的数据库水平扩展技术,可以提高数据库的吞吐量和扩展性。下面将具体讲解MySQL中分库与分表…

W25Q128芯片手册精读

文章目录 前言1. 概述2. 特性3. 封装类型和引脚配置3.1 8焊盘WSON 8x6 mm3.2其他封装 4. 引脚描述4.1 片选4.2 串行数据输入输出4.3 写保护4.4 保持脚4.5 时钟 5. 块图6. 功能描述6.1 SPI功能6.1.1 标准SPI6.1.2 双通道SPI6.1.3 四通道SPI6.1.4 保持功能 6.2 写保护6.2.1 写保护…

Python逐日填补Excel中的日期并用0值填充缺失日期的数据

本文介绍基于Python语言&#xff0c;读取一个不同的列表示不同的日期的.csv格式文件&#xff0c;将其中缺失的日期数值加以填补&#xff1b;并用0值对这些缺失日期对应的数据加以填充的方法。 首先&#xff0c;我们明确一下本文的需求。现在有一个.csv格式文件&#xff0c;其第…

C/C++——内存管理

1.为什么存在动态内存分配 灵活性 静态内存分配是在编译时确定的&#xff0c;程序执行过程中无法改变所分配的内存大小&#xff1b;动态内存分配可以根本程序的运行环境来动态分配和释放空间&#xff0c;提供了更大的灵活性 动态数据结构 有些数据结构的大小和结构在编译时…

隐式意图和Activity启动模式:实现文件打开应用【Android、隐式意图】

隐式意图和Activity启动模式&#xff1a;实现文件打开应用 在Android开发中&#xff0c;隐式意图和Activity启动模式是两个重要的概念。它们可以用于实现不同应用之间的协作和交互。在本篇博客中&#xff0c;我们将探讨如何创建一个Android应用&#xff0c;该应用可以从外部应…

IEEE802系列协议知识点总结

IEEE 802 协议包含了以下多种子协议。把这些协议汇集在一起就叫IEEE 802 协议集。 (1)IEEE802.1 IEEE 802.1协议提供高层标准的框架&#xff0c;包括端到端协议、网络互连、网络管理、路由选择、桥接和性能测量。 •IEEE 802.1d:生成树协议(Spanning Tree Protocol&#xff0c…

C++笔记之不同buffer数量下的生产者-消费者机制

C笔记之不同buffer数量下的生产者-消费者机制 文章目录 C笔记之不同buffer数量下的生产者-消费者机制0.在不同的缓冲区数量下&#xff0c;生产者-消费者机制的实现方式和行为的区别1.最简单的生产者-消费者实现&#xff1a;抄自 https://mp.weixin.qq.com/s/G1lHNcbYU1lUlfugXn…

基于虚拟阻抗的下垂控制——孤岛双机并联Simulink仿真

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Oracle Database Express Edition (XE)配置与部署

获取下载安装包 https://www.oracle.com/cn/database/technologies/xe-downloads.htmlhttps://yum.oracle.com/repo/OracleLinux/OL7/latest/x86_64/index.html安装.rpm安装包 cd /usr/local/src wget https://download.oracle.com/otn-pub/otn_software/db-express/oracle-d…

Vue中如何进行分布式搜索与全文搜索(如Elasticsearch)

在Vue中实现分布式搜索与全文搜索&#xff08;使用Elasticsearch&#xff09; 分布式搜索和全文搜索在现代应用程序中变得越来越重要&#xff0c;因为它们可以帮助用户快速查找和检索大量数据。Elasticsearch是一种强大的分布式搜索引擎&#xff0c;它可以用于实现高性能的全文…

Gmail 将停止支持基本 HTML 视图

根据 Google 支持文档的更新内容&#xff0c;Gmail 将从明年 1 月起停止支持基本 HTML 视图。 ▲ Gmai 基本 HTML 视图界面 目前网页版 Gmail 提供两个界面&#xff1a;基本 HTML 视图和标准视图。停止支持基本 HTML 视图后&#xff0c;当前打开经典模式的基本 HTML 视图模式 …

苹果签名的MDM(Mobile Device Management)?是怎么做的?优势是什么?什么场合需要应用到?

苹果签名有多少种类之TF签名(TestFlight签名&#xff09;是什么&#xff1f;优势是什么&#xff1f;什么场合需要应用到&#xff1f; 苹果签名有多少种类之TF签名(TestFlight签名&#xff09;是什么&#xff1f;优势是什么&#xff1f;什么场合需要应用到&#xff1f; MDM&am…

基于Matlab求解高教社杯数学建模竞赛(cumcm2010A题)-储油罐的变位识别与罐容表标定(附上源码+数据+题目)

文章目录 题目解题源码数据下载 题目 通常加油站都有若干个储存燃油的地下储油罐&#xff0c;并且一般都有与之配套的“油位计量管理系统”&#xff0c;采用流量计和油位计来测量进/出油量与罐内油位高度等数据&#xff0c;通过预先标定的罐容表&#xff08;即罐内油位高度与储…

lv7 嵌入式开发-网络编程开发 11 TCP管理与UDP协议

目录 1 TCP管理 1.1 三次握手 1.2 四次挥手 1.3 保活计时器 2 wireshark安装及实验 3.1 icmp协议抓包演示 3.2 tcp协议抓包演示 3 UDP协议 3.1 UDP 的主要特点&#xff1a; 4 练习 1 TCP管理 1.1 三次握手 TCP 建立连接的过程叫做握手。 采用三报文握手&#xff1…

机器学习笔记 - 深入研究spaCy库及其使用技巧

一、简述 spaCy 是一个用于 Python 中高级自然语言处理的开源库。它专为生产用途而设计,这意味着它不仅功能强大,而且快速高效。spaCy 在学术界和工业界广泛用于各种 NLP 任务,例如标记化、词性标注、命名实体识别等。 安装,这里使用阿里的源。 pip install spacy…

2023版 STM32实战6 输出比较(PWM)包含F407/F103方式

输出比较简介和特性 -1-只有通用/高级定时器才能输出PWM -2-占空比就是高电平所占的比例 -3-输出比较就是输出不同占空比的信号 工作方式说明 -1-1- PWM工作模式 -1-2- 有效/无效电平 有效电平可以设置为高或低电平&#xff0c;是自己配置的 周期选择与计算 周期重…

华为云云耀云服务器L实例评测|安装搭建学生成绩管理系统

1.前言概述 华为云耀云服务器L实例是新一代开箱即用、面向中小企业和开发者打造的全新轻量应用云服务器。多种产品规格&#xff0c;满足您对成本、性能及技术创新的诉求。云耀云服务器L实例提供丰富严选的应用镜像&#xff0c;实现应用一键部署&#xff0c;助力客户便捷高效的在…

SRT服务器SLS

目前互联网上的视频直播有两种&#xff0c;一种是基于RTMP协议的直播&#xff0c;这种直播方式上行推流使用RTMP协议&#xff0c;下行播放使用RTMP&#xff0c;HTTPFLV或者HLS&#xff0c;直播延时一般大于3秒&#xff0c;广泛应用秀场、游戏、赛事和事件直播&#xff0c;满足了…

mybatis项目启动报错:reader entry: ���� = v

问题再现 解决方案一 由于指定的VFS没有找&#xff0c;mybatis启用了默认的DefaultVFS&#xff0c;然后由于DefaultVFS的内部逻辑&#xff0c;从而导致了reader entry乱码。 去掉mybatis配置文件中关于别名的配置&#xff0c;然后在mapper.xml文件中使用完整的类名。 待删除的…

JMETER自适应高分辨率的显示器

系列文章目录 历史文章 每天15分钟JMeter入门篇&#xff08;一&#xff09;&#xff1a;Hello JMeter 每天15分钟JMeter入门篇&#xff08;二&#xff09;&#xff1a;使用JMeter实现并发测试 每天15分钟JMeter入门篇&#xff08;三&#xff09;&#xff1a;认识JMeter的逻辑控…