当前位置:   article > 正文

数据结构:队列的详解_数据结构队列详细讲解

数据结构队列详细讲解

1.概念:

队列是一种先进先出的数据结构,FIFO(first in first out)

逻辑结构:线性结构

2.队列的存储

2.1顺序队列

顺序队列是基于顺序表和两个下标来实现的,一个是队列头front,一个是队列尾rear

入队时,在队列尾入,出队列时,在队列头出。

顺序队列本质就是对顺序表操作的一个约束:只能在一端插入,另一端删除。

一般这种队列我们不直接使用,因为入队时 rear++ 出队列时 front++

每块内存空间只使用了一次,相当于一个一次性的队列了。

2.2循环队列

循环队列只是对顺序队列的一个小优化,目的是让空间能复用起来。

这种结构就可以让空间复用起来了。

入队列时,不要直接执行rear++,而是改成 rear = (rear+1)%N

出队列时,不要直接执行front++,而是改成 front = (front+1)%N

判断队列空 rear == front

判断队列满 (rear+1)%N == front (浪费了一个存储空间用来区分队列满和队列空 方便写代码)

循环队列的操作:

创建队列

清空队列

销毁队列

入队列 push

判断队列满

出队列 pop

判断队列空

打印队列中所有元素----实际不需要

循环队列代码实现:

loop_queue.h

  1. #ifndef __LOOP_QUEUE_H__
  2. #define __LOOP_QUEUE_H__
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #define N 5
  7. //循环队列的结构体
  8. typedef struct _Queue{
  9. int s[N];
  10. int front;
  11. int rear;
  12. }queue_t;
  13. int create_queue(queue_t **my_queue);
  14. int is_full(queue_t *my_queue);
  15. int push_queue(queue_t *my_queue, int data);
  16. int print_queue(queue_t *my_queue);
  17. int is_empty(queue_t *my_queue);
  18. int pop_queue(queue_t *my_queue, int *num);
  19. int clean_queue(queue_t *my_queue);
  20. int destroy_queue(queue_t **my_queue);
  21. #endif

loop_queue.c

  1. #include "loop_queue.h"
  2. //创建队列
  3. int create_queue(queue_t **my_queue){
  4. if(NULL == my_queue){
  5. printf("入参为NULL\n");
  6. return -1;
  7. }
  8. *my_queue = (queue_t *)malloc(sizeof(queue_t));
  9. if(NULL == *my_queue){
  10. printf("内存分配失败\n");
  11. return -1;
  12. }
  13. memset(*my_queue, 0, sizeof(queue_t));
  14. return 0;
  15. }
  16. //判断队列满
  17. int is_full(queue_t *my_queue){
  18. if(NULL == my_queue){
  19. printf("入参为NULL\n");
  20. return -1;
  21. }
  22. return (my_queue->rear+1) % N == my_queue->front ? 1 : 0;
  23. }
  24. //数据入队列
  25. int push_queue(queue_t *my_queue, int data){
  26. if(NULL == my_queue){
  27. printf("入参为NULL\n");
  28. return -1;
  29. }
  30. if(is_full(my_queue)){
  31. printf("队列满 入队列失败\n");
  32. return -1;
  33. }
  34. my_queue->s[my_queue->rear] = data;
  35. my_queue->rear = (my_queue->rear+1)%N;
  36. return 0;
  37. }
  38. //遍历打印队列中所有元素
  39. int print_queue(queue_t *my_queue){
  40. if(NULL == my_queue){
  41. printf("入参为NULL\n");
  42. return -1;
  43. }
  44. int i = 0;
  45. #if 1
  46. for(i = my_queue->front; i != my_queue->rear; i = (i+1)%N){
  47. printf("%d ", my_queue->s[i]);
  48. }
  49. #else
  50. for(i = my_queue->front; (i%N) != my_queue->rear; i++){
  51. printf("%d ", my_queue->s[i%N]);
  52. }
  53. #endif
  54. printf("\n");
  55. return 0;
  56. }
  57. //判断队列空
  58. int is_empty(queue_t *my_queue){
  59. if(NULL == my_queue){
  60. printf("入参为NULL\n");
  61. return -1;
  62. }
  63. return my_queue->rear == my_queue->front ? 1 : 0;
  64. }
  65. //数据出队列
  66. int pop_queue(queue_t *my_queue, int *num){
  67. if(NULL == my_queue || NULL == num){
  68. printf("入参为NULL\n");
  69. return -1;
  70. }
  71. if(is_empty(my_queue)){
  72. printf("队列空 出队列失败\n");
  73. return -1;
  74. }
  75. *num = my_queue->s[my_queue->front];
  76. my_queue->front = (my_queue->front+1)%N;
  77. return 0;
  78. }
  79. //清空队列
  80. int clean_queue(queue_t *my_queue){
  81. if(NULL == my_queue){
  82. printf("入参为NULL\n");
  83. return -1;
  84. }
  85. //让rear==front即可
  86. my_queue->rear = my_queue->front = 0;
  87. return 0;
  88. }
  89. //销毁队列
  90. int destroy_queue(queue_t **my_queue){
  91. if(NULL == my_queue || NULL == *my_queue){
  92. printf("入参为NULL\n");
  93. return -1;
  94. }
  95. free(*my_queue);
  96. *my_queue = NULL;
  97. return 0;
  98. }

main.c

  1. #include "loop_queue.h"
  2. int main(int argc, const char *argv[])
  3. {
  4. queue_t *my_queue = NULL;
  5. create_queue(&my_queue);
  6. printf("my_queue = %p\n", my_queue);//非NULL
  7. //测试入队列
  8. push_queue(my_queue, 10);
  9. push_queue(my_queue, 20);
  10. push_queue(my_queue, 30);
  11. push_queue(my_queue, 40);
  12. push_queue(my_queue, 50);//满了 失败
  13. print_queue(my_queue); // 10 20 30 40
  14. //出队列
  15. int num = 0;
  16. pop_queue(my_queue, &num);
  17. printf("num = %d\n", num);//10
  18. pop_queue(my_queue, &num);
  19. printf("num = %d\n", num);//20
  20. print_queue(my_queue); // 30 40
  21. //入队列
  22. push_queue(my_queue, 50);
  23. push_queue(my_queue, 60);
  24. push_queue(my_queue, 70);//满了 失败
  25. print_queue(my_queue); // 30 40 50 60
  26. //清空
  27. clean_queue(my_queue);
  28. if(-1 == pop_queue(my_queue, &num)){
  29. printf("没有出队列成功\n");
  30. }
  31. //销毁
  32. destroy_queue(&my_queue);
  33. printf("my_queue = %p\n", my_queue);//NULL
  34. return 0;
  35. }

3.链式队列

链式队列是基于链表配合两个指针实现的 一个是队列头 front 一个是队列尾 rear

链式队列的本质就是对链表操作的一个约束:只能在一端插入,另一端删除。

一般采用尾插头删的方式

一般采用尾插头删的方式实现队列 操作的时间复杂度都是 O(1)

链式队列的操作:

创建队列

清空队列

销毁队列

入队列 push

出队列 pop

判断队列空

打印队列中所有元素----实际不需要

链式队列的代码实现:

link_queue.h

  1. #ifndef __LINK_QUEUE_H__
  2. #define __LINK_QUEUE_H__
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. //链表节点结构体
  7. typedef struct _Node{
  8. int data;
  9. struct _Node *next;
  10. }node_t;
  11. //循环队列的结构体
  12. typedef struct _Queue{
  13. node_t *rear;
  14. node_t *front;
  15. }queue_t;
  16. int create_queue(queue_t **my_queue);
  17. int push_queue(queue_t *my_queue, int data);
  18. int print_queue(queue_t *my_queue);
  19. int is_empty(queue_t *my_queue);
  20. int pop_queue(queue_t *my_queue, int *num);
  21. int clean_queue(queue_t *my_queue);
  22. int destroy_queue(queue_t **my_queue);
  23. #endif

link_queue.c

  1. #include "link_queue.h"
  2. //创建队列
  3. int create_queue(queue_t **my_queue){
  4. if(NULL == my_queue){
  5. printf("入参为NULL\n");
  6. return -1;
  7. }
  8. *my_queue = (queue_t *)malloc(sizeof(queue_t));
  9. if(NULL == *my_queue){
  10. printf("内存分配失败\n");
  11. return -1;
  12. }
  13. memset(*my_queue, 0, sizeof(queue_t));
  14. return 0;
  15. }
  16. //数据入队列
  17. int push_queue(queue_t *my_queue, int data){
  18. if(NULL == my_queue){
  19. printf("入参为NULL\n");
  20. return -1;
  21. }
  22. //创建新节点
  23. node_t *pnew = (node_t *)malloc(sizeof(node_t));
  24. if(NULL == pnew){
  25. printf("内存分配失败\n");
  26. return -1;
  27. }
  28. pnew->data = data;
  29. pnew->next = NULL;
  30. //将新节点插入队列
  31. if(NULL == my_queue->front && NULL == my_queue->rear){//说明是第一个节点
  32. my_queue->rear = pnew;
  33. my_queue->front = pnew;
  34. }else{
  35. my_queue->rear->next = pnew;
  36. my_queue->rear = pnew;
  37. }
  38. return 0;
  39. }
  40. //遍历所有元素
  41. int print_queue(queue_t *my_queue){
  42. if(NULL == my_queue){
  43. printf("入参为NULL\n");
  44. return -1;
  45. }
  46. node_t *ptemp = my_queue->front;
  47. while(NULL != ptemp){
  48. printf("%d ", ptemp->data);
  49. ptemp = ptemp->next;
  50. }
  51. printf("\n");
  52. return 0;
  53. }
  54. //判断队列空
  55. int is_empty(queue_t *my_queue){
  56. if(NULL == my_queue){
  57. printf("入参为NULL\n");
  58. return -1;
  59. }
  60. return NULL == my_queue->front && NULL == my_queue->rear ? 1 : 0;
  61. }
  62. //数据出队列
  63. int pop_queue(queue_t *my_queue, int *num){
  64. if(NULL == my_queue || NULL == num){
  65. printf("入参为NULL\n");
  66. return -1;
  67. }
  68. if(is_empty(my_queue)){
  69. printf("队列空 出队列失败\n");
  70. return -1;
  71. }
  72. *num = my_queue->front->data;
  73. node_t *pdel = my_queue->front;
  74. my_queue->front = pdel->next;
  75. free(pdel);
  76. pdel = NULL;
  77. //如果是最后一个节点 记得把 rear 也置成NULL
  78. if(NULL == my_queue->front){
  79. my_queue->rear = NULL;
  80. }
  81. return 0;
  82. }
  83. //清空队列
  84. int clean_queue(queue_t *my_queue){
  85. if(NULL == my_queue ){
  86. printf("入参为NULL\n");
  87. return -1;
  88. }
  89. node_t *pdel = NULL;
  90. while(NULL != my_queue->front){
  91. pdel = my_queue->front;
  92. my_queue->front = pdel->next;
  93. free(pdel);
  94. }
  95. pdel = NULL;
  96. my_queue->rear = NULL;
  97. return 0;
  98. }
  99. //销毁队列
  100. int destroy_queue(queue_t **my_queue){
  101. if(NULL == my_queue || NULL == *my_queue){
  102. printf("入参为NULL\n");
  103. return -1;
  104. }
  105. //先清空再销毁
  106. clean_queue(*my_queue);
  107. free(*my_queue);
  108. *my_queue = NULL;
  109. return 0;
  110. }

main.c

  1. #include "link_queue.h"
  2. int main(int argc, const char *argv[])
  3. {
  4. queue_t *my_queue = NULL;
  5. create_queue(&my_queue);
  6. printf("my_queue = %p\n", my_queue);//非NULL
  7. //测试入队列
  8. push_queue(my_queue, 10);
  9. push_queue(my_queue, 20);
  10. push_queue(my_queue, 30);
  11. push_queue(my_queue, 40);
  12. print_queue(my_queue); // 10 20 30 40
  13. //出队列
  14. int num = 0;
  15. pop_queue(my_queue, &num);
  16. printf("num = %d\n", num);//10
  17. pop_queue(my_queue, &num);
  18. printf("num = %d\n", num);//20
  19. print_queue(my_queue); // 30 40
  20. //入队列
  21. push_queue(my_queue, 50);
  22. push_queue(my_queue, 60);
  23. print_queue(my_queue); // 30 40 50 60
  24. //清空
  25. clean_queue(my_queue);
  26. if(-1 == pop_queue(my_queue, &num)){
  27. printf("没有出队列成功\n");
  28. }
  29. //销毁
  30. destroy_queue(&my_queue);
  31. printf("my_queue = %p\n", my_queue);//NULL
  32. return 0;
  33. }
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/木道寻08/article/detail/915508
推荐阅读
相关标签
  

闽ICP备14008679号