当前位置: 首页 > news >正文

C语言 之【队列的简介、队列的实现(初始化、销毁、入队、出队、判空、元素个数、元素的访问)】

目录

1.队列的简介

2.队列的实现

2.1实现须知

2.2 头文件预览

2.2.1 头文件细节

2.3 队列的初始化

2.4 队列的销毁

2.5 入队

2.6出队

2.7 判空

2.8 队列的元素个数

2.9队首元素与队尾元素

2.10 队列的打印


1.队列的简介

队列是一种数据结构,也是一种特殊的线性表

队列只允许一端进行插入数据操作,在另一端进行删除数据操作

 进行插入数据操作的一端叫作队尾, 进行删除数据操作的一端叫作队头

队列遵守先进先出 FIFO(First In First Out)原则

就像生活中顾客按到达顺序排队到超市收银员处结账一样,

新顾客加入队尾,服务从队头开始,排在队头的顾客先结账离开

 插入数据操作,简称入队;删除数据操作,简称出队

2.队列的实现

2.1实现须知

前面说了,队列是是一种线性表,所以既可以用数组实现队列也可以用链表实现队列

注意到:

(1)数组、链表(给定尾指针的情况下),尾插的效率均为O(1)

但链表只需按需申请空间,数组却要进行预分配空间,进行扩容操作还可能造成空间浪费

(2)数组、链表头删同样是 O(1)(数组不移动数据得情况下)

所以队列的实现方式得基于具体场景,根据链表和数组的特性而定

下面使用链表实现的队列

(1)给定一个头指针head和一个尾指针tail就能实现尾插(入队),头删(出队)

所以,无头单向不循环链表就可实现队列

2.2 头文件预览

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>typedef int QueueDataType;
typedef struct QueueNode
{QueueDataType data;struct QueueNode* next;
}QNode;
//队列不仅需要实现单链表的头删,还要知晓元素个数,那么就是多个数据用结构体存储
typedef struct Queue
{QNode* head;QNode* tail;int size;
}Queue;
//初始化
void QueueInit(Queue* pq);
//销毁
void QueueDestroy(Queue* pq);
//入队
void QueuePush(Queue* pq, QueueDataType val);
//出队
void QueuePop(Queue* pq);
//判空
bool QueueEmpty(Queue* pq);
//大小
int QueueSize(Queue* pq);
//队首元素
QueueDataType QueueFront(Queue* pq);
//队尾元素
QueueDataType QueueBack(Queue* pq);

2.2.1 头文件细节

(1)防止头文件内容在同一个编译单元内被多次展开

#pragma once

(2)包含必要的头文件(库函数、开空间、断言、布尔值)

(3)数据类型重命名,(以后只改这一处,就可以改变栈所存储的数据类型)

typedef int QueueDataType;

(4)为了简洁与区分度,将队列的节点命名为QNode,

(5)在实现无头单向不循环链表时,只需要一个头指针head就可以完成一系列操作

但是这样会导致尾插效率低、无法直接获取队尾元素(效率均为O(N),因为需要找尾)

实现队列时,我们再定义一个结构体Queue,存储

变量head, 指向对头

变量tail,指向队尾

变量size,记录队列的元素个数

这样之后,就无需在接口中设置多个参数,让用户传多个参数,

达到用一个队列类型的指针管理队列所有节点的目的,也提高了尾插的效率

2.3 队列的初始化

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

(1)队列指针一定不为空,所以断言队列指针

(1)空队列的状态就是 "空"

2.4 队列的销毁

void QueueDestroy(Queue* pq)
{assert(pq);QNode* cur = pq->head;while (cur){QNode* next = pq->head->next;free(cur);cur = next;}pq->head = pq->tail = NULL;pq->size = 0;
}

(1)队列指针一定不为空,所以断言队列指针

(1)队列中,需要主动释放的空间就是节点所占据的空间

遍历队列,逐个释放,并还原成空队列状态即可

2.5 入队

void QueuePush(Queue* pq, QueueDataType val)
{assert(pq);QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc fail");exit(1);}newnode->data = val;newnode->next = NULL;//尾插注意判空if (pq->head == NULL){assert(pq->tail == NULL);pq->head = pq->tail = newnode;}else{pq->tail->next = newnode;pq->tail = newnode;}++(pq->size);
}

 (1)队列指针一定不为空,所以断言队列指针

(2)用户只传入数据,函数体内部需要创建新节点存储数据

(2)入队就是尾插,分两种情况进行尾插

1.队列为空时,head、tail都要指向新节点

2.不为空时,先将新节点链接到链表中,再改变节点的位置

(3)++size

2.6出队

void QueuePop(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));QNode* next = pq->head->next;free(pq->head);pq->head = next;//注意一个节点时的出队if (pq->head == NULL){pq->tail = NULL;}--(pq->size);
}

 (1)队列指针一定不为空,所以断言队列指针

 (1)出队时,队列一定不为空,所以断言队列

(1) 出队就是头删,但是需要注意只有一个节点时的头删

此时需要改变尾指针的指向

(3)--size

2.7 判空

bool QueueEmpty(Queue* pq)
{assert(pq);return pq->size == 0;
}

  (1)队列指针一定不为空,所以断言队列指针

(2)直接判断size即可

2.8 队列的元素个数

int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}

 

  (1)队列指针一定不为空,所以断言队列指针

(2)直接返回size即可

2.9队首元素与队尾元素

//队首元素
QueueDataType QueueFront(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));return pq->head->data;
}
//队尾元素
QueueDataType QueueBack(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));return pq->tail->data;
}

 (1)队列指针一定不为空,所以断言队列指针

 (1)访问元素时,队列一定不为空(队列为空时访问是无效操作),所以断言队列

 (1)直接返回对应节点存储的数据

2.10 队列的打印

队列并不支持遍历访问,只支持访问队头元素和队尾元素,即不提供遍历访问的接口

想要知道所有元素

只能边访问队头元素,边出队

当然,如果需要保留元素,可提前保存一下

	Queue pq;QueueInit(&pq);QueuePush(&pq, 1);QueuePush(&pq, 2);QueuePush(&pq, 3);QueuePush(&pq, 4);QueuePush(&pq, 5);QueuePush(&pq, 6);while (!QueueEmpty(&pq)){printf("%d ", QueueFront(&pq));QueuePop(&pq);}

http://www.xdnf.cn/news/256501.html

相关文章:

  • n8n 安装 n8n-nodes-mcp 社区节点
  • 对解微分方程分离变量法本质的思考
  • nt!NtReplyWaitReceivePortEx函数分析之nt!LpcpMoveMessage拷贝csr_api_msg
  • 【数据结构】单链表的增删查改
  • 微软发布了最新的开源推理模型套件“Phi-4-Reasoning
  • 构建更快,部署更智能:立即优化您的 Docker 设置
  • CPO-BP+NSGA,豪冠猪优化BP神经网络+多目标遗传算法!(Matlab完整源码和数据)
  • 如何掌握 Lustre/Scade 同步数据流语言
  • BERT+CRF模型在命名实体识别(NER)任务中的应用
  • 自主机器人模拟系统
  • Flutter - 概览
  • 数字智慧方案5869丨智慧健康医疗养老大数据整体规划方案(76页PPT)(文末有下载方式)
  • 【HarmonyOS Next】地图使用详解(三)标点定位问题
  • Java 中 Unicode 字符与字符串的转换:深入解析与实践
  • Go-web开发之帖子功能
  • 纯前端Word文档在线预览工具
  • Fedora升级Google Chrome出现GPG check FAILED问题解决办法
  • PyTorch_创建张量
  • 爱胜品ICSP YPS-1133DN Plus黑白激光打印机报“自动进纸盒进纸失败”处理方法之一
  • 解决Flutter项目中Gradle构建Running Gradle task ‘assembleDebug‘卡顿问题的终极指南
  • 【AI面试准备】元宇宙测试:AI+低代码构建虚拟场景压力测试
  • InnoDB索引的原理
  • 模型上下文协议(MCP)
  • 学习记录:DAY22
  • 数字智慧方案5873丨智慧交通设计方案(57页PPT)(文末有下载方式)
  • 动态库与静态库的区别
  • 内置类型成员变量的初始化详解
  • PostgreSQL 的 VACUUM 与 VACUUM FULL 详解
  • 6.DOS
  • 数字世界的“私人车道“:网络切片如何用Python搭建专属通信高速路?