C语言数据结构——详细讲解《队列》

C语言数据结构——详细讲解《队列》

  • 前言
  • 一、队列的概念
  • 二、队列的操作
    • (一)定义队列结构
    • (二)初始化队列
    • (三)入队列操作
    • (四)出队列操作
    • (五)获取队头元素
    • (六)检查队列是否为空
    • (七)销毁队列
  • (三)本文所有代码
    • 1.Queue.h文件
    • 2.Queue.c文件


前言

  • 在上一篇博客中,我们详细探讨了栈这种数据结构,今天,让我们深入了解另一种与栈类似重要的数据结构 —— 队列

一、队列的概念

  • 队列只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表。队列遵循先进先出的原则
  • 入队列:进行插入操作的一端称为队尾
  • 出队列:进行删除操作的一端称为队头

在这里插入图片描述

  • 大家思考一个问题,队列的底层结构是数组还是链表
队列的底层结构既可以是数组,也可以是链表
  • 基于数组实现的队列
  • 优点

实现简单,逻辑清晰;可直接通过索引随机访问元素,时间复杂度为 O (1)。

  • 缺点

需预先确定队列大小。若队列元素超数组大小,扩容操作复杂且耗时

  • 基于链表实现的队列
  • 优点

可动态调整大小,无需预先确定队列长度;队头和队尾的插入、删除操作时间复杂度为 O (1)

  • 缺点

每个节点需额外存储指针,占用空间。
无法直接通过索引访问元素,随机访问效率低

今天我们来详细讲解一下基于链表实现的队列

在这里插入图片描述

二、队列的操作

(一)定义队列结构

  • 首先我们需要定义队列链表节点结构体
//定义队列结点的结构
typedef struct QueueNode
{QDataType data;struct QueueNode* next;
}QueueNode;
  • 队列结点结构中的data成员用于存储队列中的实际数据
  • 接下来,我们定义队列结构体本身
//定义队列的结构
typedef struct Queue
{QueueNode* phead;  //队头QueueNode* ptail;  //队尾
}Queue;
  • 接下来需要初始化队列
// 初始化队列
void initQueue(Queue *pq) {pq->phead = NULL;pq->ptail = NULL;
}

(二)初始化队列

  • 在使用队列之前,我们需要对其进行初始化操作,将队头和队尾指针都设置为 NULL,表示队列为空。
// 初始化队列
void initQueue(Queue *pq) 
{pq->phead = NULL;pq->ptail = NULL;
}

(三)入队列操作

// 入队操作
void enqueue(Queue *pq, int x) {Node *newNode = (Node *)malloc(sizeof(Node));newNode->data = x;newNode->next = NULL;if (pq->ptail == NULL) {// 队列为空的情况pq->phead = newNode;pq->ptail = newNode;} else {pq->ptail->next = newNode;pq->ptail = newNode;}
}
  • 创建一个新节点,给它分配内存空间,
  • 把要入队的元素值赋给新节点的 data,并把 next 设为 NULL。
  • 然后看队列是不是空的,如果空,新节点就既是队头又是队尾;
  • 如果不空,就把新节点接到队尾节点后面,并更新队尾指针指向新节点

(四)出队列操作


//出队列
int dequeue(Queue* pq)
{assert(pq->phead != NULL);Node* temp = pq->phead;int x = temp->data;if (pq->phead == pq->ptail){pq->phead = NULL;pq->ptail = NULL;}else{pq->phead = pq->phead->next;}free(temp);return x;
}
  • 从队列的队头取出一个元素并删掉对应的节点。
  • 检查队列不能是空的,然后把队头节点的数据存起来,
  • 接着看队列是不是只有一个元素
  • 如果是就把队头和队尾指针都设为 NULL;
  • 如果不止一个元素,就更新队头指针指向下一个节点
  • 最后释放原来队头节点的内存并返回取出的元素值。

(五)获取队头元素


// 获取队头元素
int front(Queue* pq)
{assert(pq->phead != NULL);return pq->phead->data;
}
  • 能获取队列的队头元素的值,但不把这个元素从队列里取出来。
  • 先得确保队列不是空的,然后直接返回队头节点的 data 值就行

(六)检查队列是否为空

int isEmpty(Queue *pq) 
{return pq->front == NULL;
}
  • 如果是就说明队列为空返回相应结果,这样在其他操作前可以先检查下队列状态,避免在空队列上做无效操作

(七)销毁队列

// 释放队列内存
void freeQueue(Queue* pq)
{Node* current = pq->phead;Node* next;while (current != NULL){next = current->next;free(current);current = next;}pq->phead = NULL;pq->ptail = NULL;
}
  • 在队列用完后用来释放它占用的内存资源。
  • 从队头开始,逐个遍历队列里的节点,释放每个节点的内存,
  • 最后把队头和队尾指针都设为 NULL,让队列回到初始的空状态

(三)本文所有代码

1.Queue.h文件

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>// 链表节点结构体
typedef struct Node {int data;struct Node* next;
} Node;// 队列结构体
typedef struct Queue {Node* phead;Node* ptail;
} Queue;// 初始化队列
void initQueue(Queue* pq) {pq->phead = NULL;pq->ptail = NULL;
}//入队列
void enqueue(Queue* pq, int x)
{Node* newnode = (Node*)malloc(sizeof(Node));newnode->data = x;newnode->next = NULL;if (pq == NULL){pq->phead = newnode;pq->ptail = newnode;}else{pq->ptail->next = newnode;pq->ptail = newnode;}
}//出队列
int dequeue(Queue* pq)
{assert(pq->phead != NULL);Node* temp = pq->phead;int x = temp->data;if (pq->phead == pq->ptail){pq->phead = NULL;pq->ptail = NULL;}else{pq->phead = pq->phead->next;}free(temp);return x;
}// 获取队头元素
int front(Queue* pq)
{assert(pq->phead != NULL);return pq->phead->data;
}// 检查队列是否为空
int isEmpty(Queue* pq) 
{return (pq->phead != NULL) ? 0 : 1;
}// 释放队列内存
void freeQueue(Queue* pq)
{Node* current = pq->phead;Node* next;while (current != NULL){next = current->next;free(current);current = next;}pq->phead = NULL;pq->ptail = NULL;
}

2.Queue.c文件

#include "Queue.h"
#include <stdio.h>int main() {Queue myQueue;initQueue(&myQueue);// 先输入一串数据来初始化队列int num;printf("请输入一串整数,以空格分隔,用于初始化队列,输入非整数结束输入:\n");// 逐个读取输入的数据并将其入队while (scanf_s("%d", &num) == 1) {enqueue(&myQueue, num);}// 清除输入缓冲区中的剩余字符(例如换行符等)while (getchar() != '\n');int choice, value;do {printf("请选择操作:\n");printf("1. 入队\n");printf("2. 出队\n");printf("3. 获取队头元素\n");printf("4. 检查队列是否为空\n");printf("5. 退出\n");scanf_s("%d", &choice);switch (choice) {case 1:printf("请输入要入队的值:");scanf_s("%d", &value);enqueue(&myQueue, value);break;case 2:if (!isEmpty(&myQueue)) {printf("出队元素: %d\n", dequeue(&myQueue));}else {printf("队列为空,无法出队\n");}break;case 3:if (!isEmpty(&myQueue)) {printf("当前队头元素: %d\n", front(&myQueue));}else {printf("队列为空,无队头元素\n");}break;case 4:if (isEmpty(&myQueue)) {printf("队列为空\n");}else {printf("队列不为空\n");}break;case 5:printf("退出程序\n");break;default:printf("无效的选择,请重新输入\n");}} while (choice != 5);// 释放队列内存freeQueue(&myQueue);return 0;
}

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

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

相关文章

【游资悟道】-作手新一悟道心法

作手新一经典语录节选&#xff1a; 乔帮主传完整版&#xff1a;做股票5年&#xff0c;炼成18式&#xff0c;成为A股低吸大神&#xff01;从小白到大神&#xff0c;散户炒股的六个过程&#xff0c;不看不知道自己水平 围着主线做&#xff0c;多研究龙头&#xff0c;研究涨停&am…

2025年入职/转行网络安全,该如何规划?网络安全职业规划

网络安全是一个日益增长的行业&#xff0c;对于打算进入或转行进入该领域的人来说&#xff0c;制定一个清晰且系统的职业规划非常重要。2025年&#xff0c;网络安全领域将继续发展并面临新的挑战&#xff0c;包括不断变化的技术、法规要求以及日益复杂的威胁环境。以下是一个关…

使用pymupdf提取PDF文档中的文字和其颜色

最近我在捣鼓一个PDF文件&#xff0c;想把它里面的文字和文字颜色给提取出来。后来发现有个叫pymupdf的库能搞定这事儿。操作起来挺简单的&#xff0c;pymupdf的示例文档里就有现成的代码可以参考。 how-to-extract-text-with-color 我本地的测试代码如下&#xff1a; impor…

STM32 + CubeMX + 串口 + IAP升级

这篇文章分享一个简单的串口IAP Demo&#xff0c;实现使用串口更新我们自己的App程序。 目录 一、IAP简介二、Stm32CubeMx配置三、Boot代码及配置1、代码2、配置 四、App代码及配置1、代码2、配置 五、效果展示 一、IAP简介 IAP介绍可以在网上找找&#xff0c;相关资料很多&am…

A051-基于Spring Boot的网络海鲜市场系统的设计与实现

&#x1f64a;作者简介&#xff1a;在校研究生&#xff0c;拥有计算机专业的研究生开发团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339; 赠送计算机毕业设计600…

《String类》

目录 一、定义与概述 二、创建字符串对象 2.1 直接赋值 2.2 使用构造函数 三、字符串的不可变性 四、常用方法 4.1 String对象的比较 4.1.1 比较是否引用同一个对象 4.1.2 boolean equals(Object anObject)方法&#xff1a;按照字典序比较 4.1.3 int compareTo(Strin…

探讨播客的生态系统

最近对播客发生了兴趣&#xff0c;从而引起了对播客背后的技术&#xff0c;生态的关注。本文谈谈播客背后的技术生态系统。 播客很简单 播客&#xff08;podcast&#xff09;本质上就是以语音的方式发布信息。它和博客非常类似。如果将CSDN 网站上的文字加一个语音播报。CSDN …

@bytemd/vue掘金markdown插件预览内容有误

vue项目使用bytemd/vue 来预览字符串格式的markdown内容&#xff0c;总会多出如图的一段代码&#xff0c; 请问有没有大佬知道为什么&#xff1f; 很急&#xff0c;求教&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;

windows下编译IEC 61850依赖库

windows下编译IEC 61850依赖库 0、引言1、环境准备2、源码下载3、下载WpdPack4、生成vs解决方案5、在VS上对解决方案进行编译 0、引言 最近刚好在学习IEC 61850的一些标准规范&#xff0c;主要包含了两大块协议&#xff1a;MMS和GOOSE。61850是一个非常强大的协议&#xff0c;…

科技为翼 助残向新 高德地图无障碍导航规划突破1.5亿次

今年12月03日是第33个国际残疾人日。在当下科技发展日新月异的时代&#xff0c;如何让残障人士共享科技红利、平等地参与社会生活&#xff0c;成为当前社会关注的热点。 中国有超过8500万残障人士&#xff0c;其中超过2400万为肢残人群&#xff0c;视力障碍残疾人数超过1700万…

C++类的自动转换和强制类型转换

目录 一、类型转换 二、转换函数 一、类型转换 C⽀持内置类型隐式类型转换为类类型对象&#xff0c;需要有相关内置类型为参数的构造函数 简单说就是可以将内置类型转化为自定义类型 示例&#xff1a; class Test { public:Test(int n1 0):num1(n1){}void pr…

什么是sfp,onu,​为什么PON(​俗称“光猫”​)模块使用SC光纤接口

在现代网络设备中&#xff0c;我们经常会看到SFP或SFP接口的身影&#xff0c;这些接口有时被简称为光口&#xff0c;但这个称呼并不严谨。有些厂商则称之为多功能口或多用途口&#xff0c;然而这对于不了解的人来说可能还是一头雾水。SFP&#xff0c;即Small Form-Factor Plugg…

【Linux】线程池设计 + 策略模式

&#x1f308; 个人主页&#xff1a;Zfox_ &#x1f525; 系列专栏&#xff1a;Linux 目录 一&#xff1a;&#x1f525; 线程池 1-1 ⽇志与策略模式1-2 线程池设计1-3 线程安全的单例模式1-3-1 什么是单例模式1-3-2 单例模式的特点1-3-3 饿汉实现⽅式和懒汉实现⽅式1-3-4 饿汉…

flutter项目AndroidiOS自动打包脚本

从业数年余,开发出身,经数载努力位项目经理,因环境欠佳,终失业.失业达七月有余,几经周转,现又从开发,既回原点亦从始.并非与诸位抢食,仅为糊口,望海涵!因从头开始,所经之处皆为新奇,遂处处留痕以备日后之需. 自动打包脚本原文地址:https://zhuanlan.zhihu.com/p/481472311 转…

循环神经网络:从基础到应用的深度解析

&#x1f35b;循环神经网络&#xff08;RNN&#xff09;概述 循环神经网络&#xff08;Recurrent Neural Network, RNN&#xff09;是一种能够处理时序数据或序列数据的深度学习模型。不同于传统的前馈神经网络&#xff0c;RNN具有内存单元&#xff0c;能够捕捉序列中前后信息…

【言语理解】中心理解题目之结构分析

3.1 五种常见对策表达方式 3.1.1 祈使或建议给对策 应该&#xff08;应&#xff09; 需要&#xff08;要&#xff09; eg&#xff1a;……。对此&#xff0c;媒体要做好自我规约。……。 eg&#xff1a;……。然而&#xff0c;两地仅简单承接北京转移的一般产业是远远不够的&a…

嵌入式开发之Bootloader移植(一)

1、Bootloader基本概念 Bootloader是硬件启动的引导程序,是运行操作系统的前提; 在操作系统内核或用户应用程序运行之前运行的一小段代码。对软硬件进行相应的初始化和设定,为最终运行操作系统准备好环境; 在嵌入式系统中,整个系统的启动加载任务通常由Bootloader来完成…

【Leecode】Leecode刷题之路第61天之旋转链表

题目出处 61-旋转链表-题目出处 题目描述 个人解法 思路&#xff1a; todo代码示例&#xff1a;&#xff08;Java&#xff09; todo复杂度分析 todo官方解法 61-旋转链表-官方解法 方法1&#xff1a;闭合为环 思路&#xff1a; 代码示例&#xff1a;&#xff08;Java&…

【H2O2|全栈】Node.js(3)

目录 前言 开篇语 准备工作 get和post登录校验测试 准备 创建应用 数据 端口监听 get方式校验 代码 测试 ​编辑 post方式校验 代码 测试 中间件 概念 流程 结束语 前言 开篇语 本系列博客分享Node.js的相关知识点&#xff0c;本章讲解登录校验原理和中间…

mysql之基本常用的语法

mysql之基本常用的语法 1.增加数据2.删除数据3.更新/修改数据4.查询数据4.1.where子句4.2.order by4.3.limit与offset4.4.分组与having4.5.连接 5.创建表 1.增加数据 insert into 1.指定列插入 语法&#xff1a;insert into table_name(列名1,列名2,....,列名n) values (值1,值…