news 2026/3/10 15:45:22

【数据结构】C语言实现队列(Queue):链式存储与操作详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【数据结构】C语言实现队列(Queue):链式存储与操作详解

文章目录

  • 前言 🚀
  • 一、队列的概念 💡
    • 1. 什么是队列?
    • 2. 队列有什么用?
  • 二、队列的模拟实现 🛠️
    • 1. 选型:数组 vs 链表?
    • 2. 代码实现
      • 2.1 结构体定义
      • 2.2 初始化
      • 2.3 入队 (Push)
      • 2.4 出队 (Pop)
      • 2.5 获取队头 & 队尾数据
      • 2.6 获取长度 & 判空
      • 2.7 销毁队列
  • 三、代码测试 💻
  • 结语 📝

前言 🚀

哈喽各位小伙伴,欢迎回到我的数据结构系列专栏!👋

这是我们征服数据结构之路的第三站。在前两篇中,我们已经拿下了链表(还没看过的同学强烈建议先补个票,基础打牢才能飞得更高哦~ 链接我放在下面啦)。
https://blog.csdn.net/S_tarfish/article/details/155815933?fromshare=blogdetail&sharetype=blogdetail&sharerId=155815933&sharerefer=PC&sharesource=S_tarfish&sharefrom=from_link
https://blog.csdn.net/S_tarfish/article/details/155418909?fromshare=blogdetail&sharetype=blogdetail&sharerId=155418909&sharerefer=PC&sharesource=S_tarfish&sharefrom=from_link

虽说前两篇的内容可能还略显青涩,但我已经在计划后续的“装修”工程了,敬请期待!😉

好了,闲话少叙,今天我们要解锁一个非常经典且常用的数据结构——队列(Queue)。准备好了吗?让我们开始吧!🚗💨


一、队列的概念 💡

1. 什么是队列?

队列(Queue)是一种特殊的线性表
它的特殊之处在于,它对数据的访问进行了严格的限制:只允许在表的一端进行插入数据,而在另一端进行删除数据

这就好比我们在食堂排队打饭:

  • 入队(Push):新来的人只能站在队尾。
  • 出队(Pop):只有排在队头的人才能先打到饭离开。

这种操作特性被称为FIFO (First In First Out),即先进先出

  • 队尾(Rear/Back):进行插入操作的一端。
  • 队头(Front/Head):进行删除操作的一端。

2. 队列有什么用?

你可能会问:“费劲限制这么多,图啥呢?” 其实,队列在计算机科学和日常生活中的应用简直不要太多:

  1. 保持公平性:这是最直观的作用。比如银行的叫号系统、医院的挂号系统、餐馆的排队小程序,本质上都是队列。先抽号的先服务,确保了公平。
  2. 广度优先遍历(BFS):在图论和树的算法中,队列是实现 BFS 的核心辅助结构。比如 QQ/微信 的“好友推荐”功能(推荐你好友的好友),或者寻找迷宫的最短路径,底层往往都要用到队列。
  3. 缓冲区:比如我们在键盘上打字,如果 CPU 忙不过来,按键信息会被暂时存在一个队列里,保证输入的顺序不会乱。

二、队列的模拟实现 🛠️

1. 选型:数组 vs 链表?

在实现队列之前,我们面临一个选择:是用数组(顺序表)还是链表来实现?

  • 如果用数组:入队在数组尾部很简单,但出队(删除头部元素)需要将后续所有元素向前移动,时间复杂度是O(N),效率较低。
  • 如果用链表
    • 入队:即链表的尾插,如果我们记录了尾节点指针,复杂度是O(1)
    • 出队:即链表的头删,直接释放第一个节点即可,复杂度也是O(1)

结论:为了追求极致的效率,我们选择使用链表来实现队列!且为了操作方便,我们需要维护一个指向队头的指针和一个指向队尾的指针。

2. 代码实现

2.1 结构体定义

为了方便管理,我们定义两个结构体:

  1. Qnode:表示链表中的每一个节点。
  2. Queue:用来维护队列的整体状态(头指针、尾指针、元素个数)。
#include<stdio.h>#include<stdlib.h>#include<assert.h>#include<stdbool.h>//定义队列元素的数据类型,方便后续修改typedefintQDataType;// 1. 定义队列节点的结构typedefstructQueuenode{QDataType val;structQueuenode*next;}Qnode;// 2. 定义队列本身的结构typedefstructQueue{// 把头和尾的指针封装在一起,队列只能在头尾两端操作// 这样能简化函数参数,不必每次都传递两个指针Qnode*phead;// 指向队头(用于出队)Qnode*ptail;// 指向队尾(用于入队)intsize;// 增加size成员,可以O(1)时间复杂度获取队列长度}Queue;

2.2 初始化

养成好习惯,使用前先初始化。

voidQueueInit(Queue*pq){assert(pq);// 保证传进来的结构体指针有效// 初始状态下,队列为空,头尾指针均置空pq->phead=NULL;pq->ptail=NULL;pq->size=0;}

2.3 入队 (Push)

入队操作实际上就是链表的尾插。这里需要注意处理队列为空的特殊情况。

voidQueuePush(Queue*pq,QDataType x){assert(pq);// 1. 既然是插入,首先要开辟新节点Qnode*newnode=(Qnode*)malloc(sizeof(Qnode));if(newnode==NULL){perror("malloc fail");return;}newnode->val=x;newnode->next=NULL;// 新节点将作为尾节点,next必然指向NULL// 2. 链接节点(分类讨论)// 情况A:如果你是第一个进队的元素if(pq->phead==NULL){// 此时头和尾都是你pq->phead=pq->ptail=newnode;}// 情况B:队列里已经有兄弟了else{// 旧的尾节点指向新节点pq->ptail->next=newnode;// 更新尾指针指向新的节点pq->ptail=newnode;}// 3. 别忘了计数pq->size++;}

2.4 出队 (Pop)

出队操作实际上就是链表的头删

⚠️注意:这里有一个很容易踩的坑!当队列只剩下一个节点时,删掉它后,不仅phead要变空,ptail也要置空,否则ptail就变成野指针了。

voidQueuePop(Queue*pq){assert(pq);assert(pq->size!=0);// 队列为空时不能删除,断言报错// 1. 保存下一个节点的地址,防止丢失Qnode*next=pq->phead->next;// 2. 释放当前的头节点free(pq->phead);// 3. 更新头指针pq->phead=next;// 4. 【关键判断】如果删完后队列空了// 此时 phead 已经变成了 NULL,但 ptail 还指着刚才被 free 掉的空间if(pq->phead==NULL){pq->ptail=NULL;// 必须手动置空,防止 ptail 变成野指针}// 5. 计数减一pq->size--;}

2.5 获取队头 & 队尾数据

// 取队头数据QDataTypeQueueFront(Queue*pq){assert(pq);assert(pq->size!=0);// 队列不能为空returnpq->phead->val;}// 取队尾数据QDataTypeQueueBack(Queue*pq){assert(pq);assert(pq->size!=0);returnpq->ptail->val;}

2.6 获取长度 & 判空

因为我们在结构体中维护了size,这两个操作非常简单高效。

// 获取队列长度intQueueSize(Queue*pq){assert(pq);returnpq->size;}// 判空:size为0即为空boolEmpty(Queue*pq){assert(pq);returnpq->size==0;}

2.7 销毁队列

有始有终,申请的内存记得释放。

voidQueueDestroy(Queue*pq){assert(pq);Qnode*cur=pq->phead;while(cur){// 记录下一个,以便能继续往后走Qnode*next=cur->next;free(cur);cur=next;}// 善后工作pq->phead=pq->ptail=NULL;pq->size=0;}

三、代码测试 💻

逻辑写得再好,跑起来才是硬道理。让我们写个main函数测试一下我们的队列是否符合“先进先出”的特性。

#include<iostream>usingnamespacestd;// 假设上面的函数声明在 queue.h 中,实现在 queue.c 中// 这里为了演示方便直接包含// #include "queue.h"intmain(){Queue q1;QueueInit(&q1);// 1. 模拟入队:1 2 3 4printf("入队顺序: 1 -> 2 -> 3 -> 4\n");QueuePush(&q1,1);QueuePush(&q1,2);QueuePush(&q1,3);QueuePush(&q1,4);printf("开始出队及获取信息:\n");// 2. 只要队列不为空,就打印队头元素并出队while(!Empty(&q1)){// 打印格式:队头元素 队尾元素 当前长度cout<<"Front:"<<QueueFront(&q1)<<" | Back:"<<QueueBack(&q1)<<" | Size:"<<QueueSize(&q1)<<endl;QueuePop(&q1);}QueueDestroy(&q1);return0;}

运行结果如下:

结果分析:
我们可以清晰地看到:

  • 第一行Front是 1,Size是 4。
  • Pop一次后,第二行Front变成了 2,Size变成了 3。
  • 这完美验证了队列FIFO(先进先出)的特性。

结语 📝

到这里,关于队列的基础知识和链式实现就讲完啦!相比于顺序表,队列在特定场景下的作用不可替代。

如果你觉得这篇文章对你有帮助,不妨点个赞👍支持一下,这对我通过持续输出高质量内容非常重要!后续我会更新更复杂的二叉树等内容,关注不迷路哦~

我们下期见!👋

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/3 17:31:46

如何快速去除视频硬字幕?AI神器video-subtitle-remover完整教程

如何快速去除视频硬字幕&#xff1f;AI神器video-subtitle-remover完整教程 【免费下载链接】video-subtitle-remover 基于AI的图片/视频硬字幕去除、文本水印去除&#xff0c;无损分辨率生成去字幕、去水印后的图片/视频文件。无需申请第三方API&#xff0c;本地实现。AI-base…

作者头像 李华
网站建设 2026/3/4 16:38:01

小红书数据采集终极指南:xhs工具2025完全教程

小红书数据采集终极指南&#xff1a;xhs工具2025完全教程 【免费下载链接】xhs 基于小红书 Web 端进行的请求封装。https://reajason.github.io/xhs/ 项目地址: https://gitcode.com/gh_mirrors/xh/xhs 在内容营销和数据分析的时代&#xff0c;小红书平台已成为品牌洞察…

作者头像 李华
网站建设 2026/3/7 14:30:18

六音音源完整修复方案:解决洛雪音乐播放问题

六音音源完整修复方案&#xff1a;解决洛雪音乐播放问题 【免费下载链接】New_lxmusic_source 六音音源修复版 项目地址: https://gitcode.com/gh_mirrors/ne/New_lxmusic_source 当您打开最新版洛雪音乐却无法播放心爱歌曲时&#xff0c;六音音源修复方案正是您需要的技…

作者头像 李华
网站建设 2026/3/5 17:11:19

Python通达信数据分析终极指南:Mootdx完整入门教程

Python通达信数据分析终极指南&#xff1a;Mootdx完整入门教程 【免费下载链接】mootdx 通达信数据读取的一个简便使用封装 项目地址: https://gitcode.com/GitHub_Trending/mo/mootdx 在金融数据分析和量化投资领域&#xff0c;通达信作为国内主流的证券软件&#xff0…

作者头像 李华
网站建设 2026/3/5 12:03:40

TPFanCtrl2终极指南:让你的ThinkPad风扇智能又安静

TPFanCtrl2终极指南&#xff1a;让你的ThinkPad风扇智能又安静 【免费下载链接】TPFanCtrl2 ThinkPad Fan Control 2 (Dual Fan) for Windows 10 and 11 项目地址: https://gitcode.com/gh_mirrors/tp/TPFanCtrl2 还在忍受ThinkPad风扇的噪音干扰吗&#xff1f;TPFanCtr…

作者头像 李华
网站建设 2026/3/3 14:07:24

LobeChat安全性评估:XSS防护与CSRF防御机制检查

LobeChat安全性评估&#xff1a;XSS防护与CSRF防御机制检查 在当今 AI 聊天应用遍地开花的背景下&#xff0c;LobeChat 凭借其现代化架构和强大的可扩展性脱颖而出。作为一款基于 Next.js 构建的开源大语言模型&#xff08;LLM&#xff09;前端框架&#xff0c;它不仅支持 GPT…

作者头像 李华