• 数据结构:7、队列


    一、队列的概念与结构

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

    队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。

    二、队列的实现

    1、队列的初始化与销毁

    这个思路是,先创建一个节点用来存储数据,也就是一个单链表,而这里需要头和尾,也就是尾进头出,如1 2 3 4 5 6 7 这样进去,出去也是1 2  3 4 5 6 7,顺序不会改变,所以这里又定义了一个结构用来存储头和尾以及有效的数据,方便后续操作,初始化这里就是把头和尾指向空,当有数据进来时才指向新的节点,销毁就是把单链表释放销毁,而刚开始使用存储链表的头和尾的结构体,因为是局部变量,只需要把头和尾的指针置空,当函数销毁时,这个结构体也会销毁,代码如下。

    1. typedef int QDataType;
    2. // 链式结构:表示队列
    3. typedef struct QueueNode
    4. {
    5. struct QueueNode* next;
    6. QDataType data;
    7. }QNode;
    8. // 队列的结构
    9. typedef struct Queue
    10. {
    11. QNode* phead;
    12. QNode* ptail;
    13. int size;
    14. }Queue;
    15. // 初始化队列
    16. void QueueInit(Queue* pq)
    17. {
    18. assert(pq);
    19. pq->phead = NULL;
    20. pq->ptail = NULL;
    21. pq->size = 0;
    22. }
    23. // 销毁队列
    24. void QueueDestroy(Queue* pq)
    25. {
    26. assert(pq);
    27. QNode* cur = pq->phead;
    28. while (cur)
    29. {
    30. QNode* next = cur->next;
    31. free(cur);
    32. cur = next;
    33. }
    34. pq->phead = pq->ptail = NULL;
    35. pq->size = 0;
    36. }

    2、队列的入队与出队

    这个队列是尾进头出,也就相当于尾插头删,但是需要考虑到链表中没有数据时的情况,也就是尾插时没有数据,会插入一个数据,第二个就是正常的尾插,而头删就需要考虑没有数据时,就直接释放了,代码如下。

    1. // 队尾入队列
    2. void QueuePush(Queue* pq, QDataType data)
    3. {
    4. assert(pq);
    5. QNode* newnode = (QNode*)malloc(sizeof(QNode));
    6. if (newnode == NULL)
    7. {
    8. perror("malloc fail");
    9. return;
    10. }
    11. newnode->data = data;
    12. newnode->next = NULL;
    13. if (pq->ptail == NULL)
    14. {
    15. assert(pq->phead==NULL);
    16. pq->phead = pq->ptail = newnode;
    17. }
    18. else
    19. {
    20. pq->ptail->next = newnode;
    21. pq->ptail = newnode;
    22. }
    23. pq->size++;
    24. }
    25. // 队头出队列
    26. void QueuePop(Queue* pq)
    27. {
    28. assert(pq);
    29. assert(!QueueEmpty(pq));
    30. if (pq->phead->next == NULL)
    31. {
    32. free(pq->phead);
    33. pq->phead = pq->ptail = NULL;
    34. }
    35. else
    36. {
    37. QNode* next = pq->phead->next;
    38. free(pq->phead);
    39. pq->phead = next;
    40. }
    41. pq->size--;
    42. }

    3、判断与获取首尾元素与队列内有效元素

    这个就是利用之前创建的结构体可以判断下链表里有没有数据,如果有可以直接返回,之前定义的数据个数也就是可以直接看出链表有多少数据,判断也就可以直接判断有多少数据,但是不能在删除时不能忘记把数据个数减减。

    1. // 获取队列头部元素
    2. QDataType QueueFront(Queue* pq)
    3. {
    4. assert(pq);
    5. assert(!QueueEmpty(pq));
    6. return pq->phead->data;
    7. }
    8. // 获取队列队尾元素
    9. QDataType QueueBack(Queue* pq)
    10. {
    11. assert(pq);
    12. assert(!QueueEmpty(pq));
    13. return pq->ptail->data;
    14. }
    15. // 获取队列中有效元素个数
    16. int QueueSize(Queue* pq)
    17. {
    18. assert(pq);
    19. return pq->size;
    20. }
    21. // 检测队列是否为空,如果为空返回非零结果,如果非空返回0
    22. bool QueueEmpty(Queue* pq)
    23. {
    24. assert(pq);
    25. return pq->size==0;
    26. }

    4、测试与测试结果

    这个就是测试各个函数,也就是插入1 2 3 4 5 6 7然后读取下有几个数据,然后把尾部数据打印,利用之前写的判断函数也就可以直接用while函数去进行出队数据并且打印,然后队里数据全部出完后,再去取数据打印和删除,会直接报错,代码和测试结果如图。

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include "QL.h"
    3. void TestQueue()
    4. {
    5. Queue q;
    6. QueueInit(&q);
    7. QueuePush(&q, 1);
    8. QueuePush(&q, 2);
    9. QueuePush(&q, 3);
    10. QueuePush(&q, 4);
    11. QueuePush(&q, 5);
    12. QueuePush(&q, 6);
    13. QueuePush(&q, 7);
    14. printf("size:%d\n", QueueSize(&q));
    15. printf("%d\n", QueueBack(&q));
    16. while (!QueueEmpty(&q))
    17. {
    18. printf("%d ", QueueFront(&q));
    19. QueuePop(&q);
    20. }
    21. printf("%d ", QueueFront(&q));
    22. QueuePop(&q);
    23. QueueDestroy(&q);
    24. }
    25. int main()
    26. {
    27. TestQueue();
    28. return 0;
    29. }

    三、代码

    test.c

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include "QL.h"
    3. void TestQueue()
    4. {
    5. Queue q;
    6. QueueInit(&q);
    7. QueuePush(&q, 1);
    8. QueuePush(&q, 2);
    9. QueuePush(&q, 3);
    10. QueuePush(&q, 4);
    11. QueuePush(&q, 5);
    12. QueuePush(&q, 6);
    13. QueuePush(&q, 7);
    14. printf("size:%d\n", QueueSize(&q));
    15. printf("%d\n", QueueBack(&q));
    16. while (!QueueEmpty(&q))
    17. {
    18. printf("%d ", QueueFront(&q));
    19. QueuePop(&q);
    20. }
    21. printf("%d ", QueueFront(&q));
    22. QueuePop(&q);
    23. QueueDestroy(&q);
    24. }
    25. int main()
    26. {
    27. TestQueue();
    28. return 0;
    29. }

    QL.c

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

    QL.h

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

  • 相关阅读:
    Java练习题第十三期:字符串转整数
    HBuilder开发者必备!Windows上传IPA文件的软件分享
    GreenPlum在线扩容工具GPExpan实战
    【开源教程12】疯壳·开源编队无人机-串口(视觉数据获取)
    C++ ++ 和 -- 运算符重载
    flink学习之广播流与合流操作demo
    ERROR in docs.42140ac.js from UglifyJs webpack打包报错
    单一职责模式
    ThinkPHP3.2.3反序列化链子分析
    Java BigInteger比Long更大的整数自增转字符串存储
  • 原文地址:https://blog.csdn.net/weixin_64257568/article/details/136592787