当前位置:   article > 正文

数据结构之——队列详解

队列

目录

前言:

一、什么是队列

二、队列的实现

        2.1 队列结构

        2.2 队列初始化

        2.3 队列销毁

        2.4 入队列

        2.5 出队列

        2.6 获取队列头部元素 

        2.7  获取队列尾部元素 

        2.8 获取队列中有效元素个数 

        2.9 检测队列是否为空

三、 代码总览

        Queue.h

        Queue.c

        test.c

四、例题


前言:

        我们前面已经学习了栈,今天我们来学习队列,队列和栈一样,相对来说比较简单,随后,会为大家准备OJ练习题,敬请期待!

一、什么是队列

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

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

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

        这里简单给大家解释一下:

        大家肯定都排过队(别说没有,我不信),大家在排好队先前前进时,是不是先站到队伍里的先走。队列的原理何其类似。因为,你可以猜一猜它为什么叫队列。可用下面图片帮助大家理解。 

         明白了,基础知识,那就一起来实现一下队列吧。

二、队列的实现

        2.1 队列结构

                和栈一样,我们队列的结构该如何设计呢?

                队列一共有两种结构,分为:顺序结构链式结构

  • 队列的顺序结构

入队,不需要移动任何元素,时间复杂度为O(1)

出队,所有元素需要往前移动,时间复杂度为O(N)

  • 队列的链式结构

首先我们定义两个指针,队头指针指向第一个节点,队尾指针指向尾节点

入队(尾插),时间复杂度为O(1)

出队(头删),时间复杂度为O(1)

                这里,我们将采取链式结构,如若对顺序结构感兴趣可结合之前的栈进行实现。

                我们要采用链式难道要用二级指针吗?一级已经够麻烦了,使用二级会更晕。所以,为了避免这种轻快,我们可采取结构体,如下代码:

  1. typedef int QDataType;
  2. // 链式结构:表示队列
  3. typedef struct QListNode
  4. {
  5. struct QListNode* next;
  6. QDataType data;
  7. }QNode;
  8. // 队列的结构
  9. typedef struct Queue
  10. {
  11. QNode* phead;
  12. QNode* ptatil;
  13. int size;
  14. }Queue;

                这样即可避免二级指针。

        2.2 队列初始化

  1. // 初始化队列
  2. void QueueInit(Queue* q)
  3. {
  4. assert(q);
  5. q->phead = q->ptatil = NULL;
  6. q->size = 0;
  7. }

                初始化只用将头和尾置为空即可。队列还未建立,所以,先不管。

        2.3 队列销毁

  1. // 销毁队列
  2. void QueueDestroy(Queue* q)
  3. {
  4. assert(q);
  5. QNode* cur = q->phead;
  6. while (cur)
  7. {
  8. QNode* next = cur->next;
  9. free(cur);
  10. cur = next;
  11. }
  12. q->phead = q->ptatil = NULL;
  13. q->size = 0;
  14. }

                销毁时我们要释放的是指针所指向开辟空间,而不是指针本身。所以,使用一个while循来释放。

        2.4 入队列

  1. // 队尾入队列
  2. void QueuePush(Queue* q, QDataType data)
  3. {
  4. assert(q);
  5. QNode* newnode = (QNode*)malloc(sizeof(QNode));
  6. if (newnode == NULL)
  7. {
  8. perror("malloc fail");
  9. return;
  10. }
  11. newnode->next = NULL;
  12. newnode->data = data;
  13. if (q->phead == NULL)//这里使用头节点,尾节点判断均可
  14. {
  15. q->phead = q->ptatil = newnode;
  16. }
  17. else
  18. {
  19. q->ptatil->next = newnode;//记住这里是尾节点,不是头节点!!!
  20. q->ptatil = newnode;
  21. }
  22. q->size++;
  23. }

                入队列时,我们要为其开辟一块空间也就是QNode,这就是队列的元素。要分为两种情况讨论,队列为空和队列不为空。

        2.5 出队列

  1. // 队头出队列
  2. void QueuePop(Queue* q)
  3. {
  4. assert(q);
  5. assert(q->size != 0);
  6. if (q->phead->next == NULL)
  7. {
  8. q->phead = q->ptatil = NULL;
  9. }
  10. else
  11. {
  12. QNode* next = q->phead->next;
  13. free(q->phead);
  14. q->phead = next;
  15. }
  16. q->size--;
  17. }

                要注意:分两种情况进行讨论。

        2.6 获取队列头部元素 

  1. // 获取队列头部元素
  2. QDataType QueueFront(Queue* q)
  3. {
  4. assert(q);
  5. assert(q->phead);
  6. return q->phead->data;
  7. }

                这里,直接用头指针返回值即可。

        2.7  获取队列尾部元素 

  1. // 获取队列队尾元素
  2. QDataType QueueBack(Queue* q)
  3. {
  4. assert(q);
  5. assert(q->ptatil);
  6. return q->ptatil->data;
  7. }

                和上面一样,运用指针获取值即可。

        2.8 获取队列中有效元素个数 

  1. int QueueSize(Queue* q)
  2. {
  3. assert(q);
  4. return q->size;
  5. }

        2.9 检测队列是否为空

  1. // 检测队列是否为空,如果为空返回非零结果,如果非空返回0
  2. bool QueueEmpty(Queue* q)
  3. {
  4. assert(q);
  5. return q->size == 0;
  6. }

三、 代码总览

        Queue.h

  1. #pragma once
  2. #include<stdio.h>
  3. #include<stdlib.h>
  4. #include<stdbool.h>
  5. #include<assert.h>
  6. typedef int QDataType;
  7. // 链式结构:表示队列
  8. typedef struct QListNode
  9. {
  10. struct QListNode* next;
  11. QDataType data;
  12. }QNode;
  13. // 队列的结构
  14. typedef struct Queue
  15. {
  16. QNode* phead;
  17. QNode* ptatil;
  18. int size;
  19. }Queue;
  20. // 初始化队列
  21. void QueueInit(Queue* q);
  22. // 队尾入队列
  23. void QueuePush(Queue* q, QDataType data);
  24. // 队头出队列
  25. void QueuePop(Queue* q);
  26. // 获取队列头部元素
  27. QDataType QueueFront(Queue* q);
  28. // 获取队列队尾元素
  29. QDataType QueueBack(Queue* q);
  30. // 获取队列中有效元素个数
  31. int QueueSize(Queue* q);
  32. // 检测队列是否为空,如果为空返回非零结果,如果非空返回0
  33. bool QueueEmpty(Queue* q);
  34. // 销毁队列
  35. void QueueDestroy(Queue* q);

        Queue.c

  1. #include"Queue.h"
  2. // 初始化队列
  3. void QueueInit(Queue* q)
  4. {
  5. assert(q);
  6. q->phead = q->ptatil = NULL;
  7. q->size = 0;
  8. }
  9. // 队尾入队列
  10. void QueuePush(Queue* q, QDataType data)
  11. {
  12. assert(q);
  13. QNode* newnode = (QNode*)malloc(sizeof(QNode));
  14. if (newnode == NULL)
  15. {
  16. perror("malloc fail");
  17. return;
  18. }
  19. newnode->next = NULL;
  20. newnode->data = data;
  21. if (q->phead == NULL)
  22. {
  23. q->phead = q->ptatil = newnode;
  24. }
  25. else
  26. {
  27. q->ptatil->next = newnode;//记住这里是尾节点,不是头节点!!!
  28. q->ptatil = newnode;
  29. }
  30. q->size++;
  31. }
  32. // 队头出队列
  33. void QueuePop(Queue* q)
  34. {
  35. assert(q);
  36. assert(q->size != 0);
  37. if (q->phead->next == NULL)
  38. {
  39. q->phead = q->ptatil = NULL;
  40. }
  41. else
  42. {
  43. QNode* next = q->phead->next;
  44. free(q->phead);
  45. q->phead = next;
  46. }
  47. q->size--;
  48. }
  49. // 获取队列头部元素
  50. QDataType QueueFront(Queue* q)
  51. {
  52. assert(q);
  53. assert(q->phead);
  54. return q->phead->data;
  55. }
  56. // 获取队列队尾元素
  57. QDataType QueueBack(Queue* q)
  58. {
  59. assert(q);
  60. assert(q->ptatil);
  61. return q->ptatil->data;
  62. }
  63. // 获取队列中有效元素个数
  64. int QueueSize(Queue* q)
  65. {
  66. assert(q);
  67. return q->size;
  68. }
  69. // 检测队列是否为空,如果为空返回非零结果,如果非空返回0
  70. bool QueueEmpty(Queue* q)
  71. {
  72. assert(q);
  73. return q->size == 0;
  74. }
  75. // 销毁队列
  76. void QueueDestroy(Queue* q)
  77. {
  78. assert(q);
  79. QNode* cur = q->phead;
  80. while (cur)
  81. {
  82. QNode* next = cur->next;
  83. free(cur);
  84. cur = next;
  85. }
  86. q->phead = q->ptatil = NULL;
  87. q->size = 0;
  88. }

        test.c

  1. #include"Queue.h"
  2. int main()
  3. {
  4. Queue q;
  5. QueueInit(&q);
  6. QueuePush(&q, 1);
  7. QueuePush(&q, 2);
  8. QueuePush(&q, 3);
  9. QueuePush(&q, 4);
  10. while (!QueueEmpty(&q))
  11. {
  12. printf("%d ", QueueFront(&q));
  13. QueuePop(& q);
  14. }
  15. printf("\n");
  16. QueueDestroy(&q);
  17. return 0;
  18. }

四、例题

        来一道例题来练一练吧!

        现有队列Q与栈S,初始时Q中的元素依次是 1,2,3,4,5,6(1在队头),S 为空。若仅允许下列3种操作:①出队并输出出队元素;②出队并将出队元素入栈;③出栈并输出出栈元素,则不能得到的输出序列是()。

                       A. 1,2,5,6,4,3                                        B.  2,3,4,5,6,1                                        C. 3,4,5,6,1,2                                         D.  6.5.4.3.2.1

        

        可得:答案为:C。

        如果还有什么问题,可以私信也可在评论区留言!

        栈和队列经典习题:CSDN

完! 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/1018275
推荐阅读
相关标签
  

闽ICP备14008679号