• 数据结构之——队列详解 ( 1 )


    目录

    前言     

    一.队列

    2.1队列的概念及结构

            1.定义:

            2.理解

    二.队列的实现

    1. 队列的数据结构

    2.队列的初始化函数 

    3.释放空间

    4.入队——插入元素(从队尾处)

            图解:

             函数代码:

    5.检查队列是否为空

    6.出队——删除元素(从队头处)

            图解:

            函数代码:

    7.返回队列的队头元素值

    8.返回队列的队尾元素值 

    9.求队列的长度


    前言     

            栈和队列都是两个特殊类型的线性表,之前讲过了关于栈型线性表的特点和功能实现,博客如下: 数据结构之——栈的操作讲解与功能实现

            感兴趣的伙伴们可以去看看,接下来就需要来了解了解队列了。

    一.队列

    2.1队列的概念及结构

            1.定义:

            只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out)的原则

            入队列:进行插入操作的一端称为队尾。

            出队列:进行删除操作的一端称为队。

            2.理解

            队列名副其实就是排队,就好比在医院看病,排了一字长龙,那么先挂号的病患就有优先看病的权力,后来排上队的人就得慢慢等了,这与栈的特征是完全相反的!

            队列既然也是线性表,那么就具有两种实现方式:顺序存储类型和链式存储类型

            顺序存储就是用数组实现,比如有一个n个元素的队列,数组下标0的一端是队头,入队操作就是通过数组下标一个个顺序追加,不需要移动元素,但是如果删除队头元素,后面的所有元素就要往前移动一次,若删除多个头元素,那么就要移动n次,所对应的时间复杂度就是O(n),性能和效率自然低下;而且在删除元素时,会造成空间的丢失,如下图:

            若使用链表实现,链式存储的头部删除极为简单方便,而且链表中也有单链表形式和双向链表形式,本人认为使用单链表好一些,毕竟队列的实现很简单,双向链表有大材小用,杀鸡焉用牛刀的做法了。

            对比来看,链式队列比顺序队列的好处就在于,链式队列节省空间。

    二.队列的实现

     

    1. 队列的数据结构

    1. typedef int QUEUENode;
    2. //单向链式结构体数据类型
    3. typedef struct QuNode {
    4. QUEUENode data;
    5. struct QuNode* next;
    6. }QN;
    7. //封装链式结构体QN的一个结构体队列
    8. typedef struct Queue {
    9. QN* head;//队列头指针
    10. QN* tail;//队列尾指针
    11. }Queue;

    2.队列的初始化函数 

    1. //初始化
    2. void QueueInit(Queue* pq) {
    3. assert(pq);
    4. pq->head = pq->tail = NULL;
    5. }

    3.释放空间

    1. //释放空间
    2. void QueueDestory(Queue* pq) {
    3. assert(pq);
    4. QN* cur = pq->head;
    5. while (cur) {
    6. QN* del = cur;
    7. cur = cur->next;
    8. free(del);
    9. del = NULL;
    10. }
    11. pq->head = pq->tail = NULL;
    12. }

    4.入队——插入元素(从队尾处)

    图解:

     函数代码:

    1. //入队
    2. void QueuePush(Queue* pq, QUEUENode x) {
    3. assert(pq);
    4. //开辟节点
    5. QN* newnode = (QN*)malloc(sizeof(QN));
    6. //若开辟失败
    7. if (newnode == NULL) {
    8. perror("malloc fail");
    9. exit(-1);
    10. }
    11. //开辟成功:
    12. else {
    13. newnode->data = x;
    14. newnode->next = NULL;
    15. }
    16. //若队列为空
    17. if (pq->tail == NULL) {
    18. pq->head = pq->tail = newnode;
    19. }
    20. //若队列不为空
    21. else {
    22. pq->tail->next = newnode;
    23. pq->tail = newnode;
    24. }
    25. }

    5.检查队列是否为空

    在删除元素时,需要进行检查队列中是否有元素,若有元素,则断言false,通过该语句照常进行删除;若没有元素,则断言true 确认为空,程序报错!

    1. //暴力检查
    2. bool QueueEmpty(Queue* pq) {
    3. assert(pq);
    4. return pq->head == NULL && pq->tail == NULL;
    5. }

    注:C语言中没有bool类型,所以需要用到头文件#include即可使用

    6.出队——删除元素(从队头处)

    图解:

    函数代码:

    1. //出队
    2. void QueuePop(Queue* pq) {
    3. assert(pq);
    4. //判断队列是否为空
    5. assert(!QueueEmpty(pq));
    6. //表明队列不为空,可以正常删除元素
    7. //情况1:
    8. if (pq->head->next == NULL) {
    9. free(pq->head);
    10. pq->head = pq->tail = NULL;
    11. }
    12. //情况2:
    13. else {
    14. QN* del = pq->head;
    15. pq->head = pq->head->next;
    16. free(del);
    17. del = NULL;
    18. }
    19. }

    7.返回队列的队头元素值

    1. //返回队头元素
    2. QUEUENode Queuehead(Queue* pq) {
    3. assert(pq);
    4. assert(!QueueEmpty(pq));
    5. return pq->head->data;
    6. }

    该函数的作用就是方便我们去打印输出队头元素的值

    8.返回队列的队尾元素值 

    1. //返回队尾元素
    2. QUEUENode Queuetail(Queue* pq) {
    3. assert(pq);
    4. assert(!QueueEmpty(pq));
    5. return pq->tail->data;
    6. }

    该函数的作用就是方便我们去打印输出队尾元素的值

    9.求队列的长度

    1. //队列长度
    2. int QueueSize(Queue* pq) {
    3. assert(pq);
    4. int n = 0;
    5. QN* cur = pq->head;
    6. while (cur) {
    7. ++n;
    8. cur = cur->next;
    9. }
    10. return n;
    11. }

    测试: 

     

    记得测试完需要使用QueueDestory释放空间函数,否则会造成内存泄漏!!! 

    注:队列的增删方式只能为:头部删除元素,尾部插入元素

  • 相关阅读:
    正则表达式:Regular Expression
    ZYNQ下linux通过xdevcfg在线更新PL
    计网期末复习指南(六):应用层(DNS、FTP、URL、HTTP、SMTP、POP3)
    怎么把备忘录中的视频导到手机相册里
    vue+element-ui el-select + el-tree下拉树形结构组件(支持筛选过滤)
    计算机毕业设计SSM城市智能公交系统【附源码数据库】
    Spring AOP基础之代理模式.静态代理和动态代理
    矩阵分析与应用
    Linux——进程间信号(超级详解!!)
    14种神笔记方法,只需选择1招,让你的学习和工作效率提高100倍!
  • 原文地址:https://blog.csdn.net/weixin_69283129/article/details/126626426