当前位置:   article > 正文

C语言 队列(循环队列和链队初始化进出队等基本操作)_编写程序,用不同的存储方法,实现队列的基本操作(初始化、入队、出队)。

编写程序,用不同的存储方法,实现队列的基本操作(初始化、入队、出队)。

目录

一、队列的定义

 二、循环队列

1、 循环队列的储存结构

2、初始化

3、输出队列元素

4、入队

5、出队

6、取队头元素

7、求队列长度

8、源代码

三、链式队列

1、队列的链式存储结构表示

2、初始化

3.输出队列元素

4.入队

5.出队

6.取队头元素

7. 源代码

总结


一、队列的定义

队列(Queue)是一种先进先出(FIFO,First-In-First-Out)的线性表。

在具体应用中通常用链表或者数组来实现。队列只允许在后端(称为 rear)进行插入操作,在前端(称为 front)进行删除操作。这和日常生活中的排队时一致的,最早进入队列的元素最早离开。

常见队列有三种:循环队列、链式队列、双端队列。

双端队列又名double ended queue,简称deque,是队列的一种变形,双端队列没有队列和栈这样的限制级,它允许两端进行入队和出队操作,也就是说元素可以从队头出队和入队,也可以从队尾出队和入队

队列基本操作有:

  • 初始化队列:InitQueue(Q)
  • 判断队列是否为空:IsEmpty(Q)
  • 判断队列是否已满:IsFull(Q)
  • 入队操作:EnterQueue(Q,data)
  • 出队操作:DeleteQueue(Q,&data)
  • 取队首元素:GetHead(Q,&data)
  • 清空队列:ClearQueue(&Q)

 二、循环队列

 循环队列其实就是将数组的首尾相连,组成的一个特殊结构。头、尾指针以及队列元素之间的关系不变,只是在循环队列中,头、尾指针“依环状增1"的操作可用“模”运算来实现。通过取模,头指针和尾指针就可以在顺序表空间内以头尾衔接的方式“循环”移动。

数据结构与算法(六)——循环队列的顺序存储结构(超详解,附动图+代码)_站在远方看童年的博客-CSDN博客_循环队列的顺序存储结构

1、 循环队列的储存结构

  1. typedef struct {
  2. int* base;//储存空间的基地址
  3. int front;//头指针
  4. int rear;//尾指针
  5. int maxsize;//队列最大长度
  6. }SqQueue;

2、初始化

动态分配一个大小为size的数组空间,base指向数组空间首地址。

  1. SqQueue* InitQueue(int size) {
  2. SqQueue* Q = malloc(sizeof(SqQueue));//先创建队列结构体指针
  3. Q->base = (int*)malloc(sizeof(int) * size);//为队列分配一个最大容量为size的数组空间
  4. //队列最大长度置为size,头指针尾指针置为0,队列为空
  5. Q->maxsize = size;
  6. Q->front = 0;
  7. Q->rear = 0;
  8. return Q;
  9. }

3、输出队列元素

  1. void print(SqQueue* Q) {
  2. printf("(front) ");
  3. int i;
  4. //跟遍历数组差不多,就是要通过模运算防止越界
  5. for (i = Q->front; i != Q->rear; i = (i + 1) % Q->maxsize) {
  6. printf("%d ", Q->base[i]);
  7. }
  8. printf("(rear)\n");
  9. }

4、入队

入队指在队尾插入一个新元素。

  1. bool EnQueue(SqQueue* Q, int e) {
  2. //插入e作为新队尾元素
  3. if ((Q->rear + 1) % Q->maxsize == Q->front) return false;//尾指针在循环意义上加1后等于头指针说明队满
  4. Q->base[Q->rear] = e;//将元素e插入队尾
  5. Q->rear = (Q->rear + 1) % Q->maxsize;//尾指针加1
  6. return true;
  7. }

示例

初始化一个最大长度为5的队列,用循环将四个元素入队 ,最后输出。

5、出队

出队指将队头元素删除

  1. bool DeQueue(SqQueue* Q, int* e) {
  2. //删除队头元素,用e返回其值
  3. if (Q->front == Q->rear) return false;//队空
  4. *e = Q->base[Q->front];//用e保存队头元素
  5. Q->front = (Q->front + 1) % Q->maxsize;//头指针加1
  6. return true;
  7. }

 示例

接着入队示例,出队三个元素,再入队两个元素,最后输出。

6、取队头元素

  1. bool GetHead(SqQueue* Q, int* e) {
  2. //返回队头元素,不修改头指针
  3. if (Q->front == Q->rear) return false;//队空
  4. *e = Q->base[Q->front];
  5. return true;
  6. }

7、求队列长度

对于非循环队列,尾指针与头指针的差值就是队列长度;但是循环队列差值可能为负数,所以需要将差值加上maxsize再与maxsize求余。

  1. int QueueLength(SqQueue* Q) {
  2. //返回队列元素个数
  3. return (Q->rear - Q->front + Q->maxsize) % Q->maxsize;
  4. }

8、源代码

  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <stdbool.h>
  5. typedef struct {
  6. int* base;//储存空间的基地址
  7. int front;//头指针
  8. int rear;//尾指针
  9. int maxsize;//队列最大长度
  10. }SqQueue;
  11. //初始化
  12. SqQueue* InitQueue(int size) {
  13. SqQueue* Q = malloc(sizeof(SqQueue));//先创建队列结构体指针
  14. Q->base = (int*)malloc(sizeof(int) * size);//为队列分配一个最大容量为size的数组空间
  15. //队列最大长度置为size,头指针尾指针置为0,队列为空
  16. Q->maxsize = size;
  17. Q->front = 0;
  18. Q->rear = 0;
  19. return Q;
  20. }
  21. //输出
  22. void print(SqQueue* Q) {
  23. printf("(front) ");
  24. int i;
  25. //跟遍历数组差不多,就是要通过模运算防止越界
  26. for (i = Q->front; i != Q->rear; i = (i + 1) % Q->maxsize) {
  27. printf("%d ", Q->base[i]);
  28. }
  29. printf("(rear)\n");
  30. }
  31. //入队
  32. bool EnQueue(SqQueue* Q, int e) {
  33. //插入e作为新队尾元素
  34. if ((Q->rear + 1) % Q->maxsize == Q->front) return false;//尾指针在循环意义上加1后等于头指针说明队满
  35. Q->base[Q->rear] = e;//将元素e插入队尾
  36. Q->rear = (Q->rear + 1) % Q->maxsize;//尾指针加1
  37. return true;
  38. }
  39. //出队
  40. bool DeQueue(SqQueue* Q, int* e) {
  41. //删除队头元素,用e返回其值
  42. if (Q->front == Q->rear) return false;//队空
  43. *e = Q->base[Q->front];//用e保存队头元素
  44. Q->front = (Q->front + 1) % Q->maxsize;//头指针加1
  45. return true;
  46. }
  47. //取队头元素
  48. bool GetHead(SqQueue* Q, int* e) {
  49. //返回队头元素,不修改头指针
  50. if (Q->front == Q->rear) return false;//队空
  51. *e = Q->base[Q->front];
  52. return true;
  53. }
  54. //求队列长度
  55. int QueueLength(SqQueue* Q) {
  56. //返回队列元素个数
  57. return (Q->rear - Q->front + Q->maxsize) % Q->maxsize;
  58. }
  59. int main() {
  60. int i, n, e;
  61. SqQueue* Q = InitQueue(5);
  62. for (scanf("%d", &n), i = 0; i < n; i++) {
  63. scanf("%d", &e);
  64. EnQueue(Q, e);
  65. }
  66. print(Q);
  67. DeQueue(Q, &e);
  68. printf("e=%d\n", e);
  69. DeQueue(Q, &e);
  70. printf("e=%d\n", e);
  71. DeQueue(Q, &e);
  72. printf("e=%d\n", e);
  73. for (scanf("%d", &n), i = 0; i < n; i++) {
  74. scanf("%d", &e);
  75. EnQueue(Q, e);
  76. }
  77. print(Q);
  78. }

三、链式队列

链队列是指采用链式存储结构实现的队列。通常链队列用单链表来表示。一个链队列显然需要两个分别指示队头和队尾的指针(分别称为头指针和尾指针)才能唯一确定。这里和线性表的单链表一样,为了操作方便起见,给链队列添加一个头结点,并令头指针始终指向头结点。

当然也有用单向循环链表表示的队列,与单链表不同的是尾节点指向了头结点,所以只需

一个指针指向尾结点就可以实现基本操作。

1、队列的链式存储结构表示

  1. typedef struct {
  2. int data;
  3. struct QNode* next;
  4. }QNode;
  5. typedef struct {
  6. QNode* front;//队头指针
  7. QNode* rear;//队尾指针
  8. }LinkQueue;

2、初始化

链队的初始化操作就是构造一个只有一个头结点的空队。

  1. LinkQueue* InitQueue() {
  2. LinkQueue* Q = malloc(sizeof(LinkQueue));//生成队头队尾指针
  3. Q->front = (QNode*)malloc(sizeof(QNode));//生成新结点作为头结点,队头队尾指针指向该结点
  4. Q->rear = Q->front;
  5. Q->front->next = NULL;//头结点指针域置空
  6. return Q;
  7. }

3.输出队列元素

跟遍历链表一样,就是要判断队是否为空。

  1. void print(LinkQueue *Q) {
  2. //前提为队不为空
  3. printf("(front) ");
  4. if (Q->front != Q->rear) {
  5. QNode* p = Q->front->next;
  6. while (p != NULL) {
  7. printf("%d ", p->data);
  8. p = p->next;
  9. }
  10. }
  11. printf("(rear)\n");
  12. }

4.入队

链队入队不需要判断队满,只需为入队元素动态分配一个结点空间。

  1. void EnQueue(LinkQueue* Q, int e) {
  2. QNode* p = malloc(sizeof(QNode));//生成新结点
  3. p->data = e;//新结点数据域置为e,指针域置空
  4. p->next = NULL;
  5. Q->rear->next = p;//新结点插入队尾
  6. Q->rear = p;//修改队尾指针
  7. }

示例

用循环将5个元素入队,最后输出队列。 

运行结果如下

5.出队

需要判断队是否为空,出队后可释放队头元素空间。

  1. bool DeQueue(LinkQueue* Q, int* e) {
  2. //删除队头元素,用e返回其值
  3. if (Q->front == Q->rear) return false;//判断队列是否为空
  4. QNode* p = Q->front->next;//p指向队头元素
  5. *e = p->data;//e保存队头元素
  6. Q->front->next = p->next;//修改头结点指针域
  7. if (Q->rear == p) Q->rear = Q->front;//最后一个元素被删,队尾指针指向头结点
  8. free(p);//释放队头元素空间
  9. return true;
  10. }

 示例

接着入队示例,出队一个元素并输出,最后输出队列

运行结果如下

6.取队头元素

  1. bool GetHead(LinkQueue* Q, int* e) {
  2. //返回队头元素,不修改队头指针
  3. if (Q->front == Q->rear) return false;//判断队列是否为空
  4. QNode* p = Q->front->next;
  5. *e =p->data;//用e返回队头元素值
  6. return true;
  7. }

7. 源代码

  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <stdbool.h>
  5. typedef struct {
  6. int data;
  7. struct QNode* next;
  8. }QNode;
  9. typedef struct {
  10. QNode* front;//队头指针
  11. QNode* rear;//队尾指针
  12. }LinkQueue;
  13. //初始化
  14. LinkQueue* InitQueue() {
  15. LinkQueue* Q = malloc(sizeof(LinkQueue));//生成队头队尾指针
  16. Q->front = (QNode*)malloc(sizeof(QNode));//生成新结点作为头结点,队头队尾指针指向该结点
  17. Q->rear = Q->front;
  18. Q->front->next = NULL;//头结点指针域置空
  19. return Q;
  20. }
  21. //入队
  22. void EnQueue(LinkQueue* Q, int e) {
  23. QNode* p = malloc(sizeof(QNode));//生成新结点
  24. p->data = e;//新结点数据域置为e,指针域置空
  25. p->next = NULL;
  26. Q->rear->next = p;//新结点插入队尾
  27. Q->rear = p;//修改队尾指针
  28. }
  29. //出队
  30. bool DeQueue(LinkQueue* Q, int* e) {
  31. //删除队头元素,用e返回其值
  32. if (Q->front == Q->rear) return false;//判断队列是否为空
  33. QNode* p = Q->front->next;//p指向队头元素
  34. *e = p->data;//e保存队头元素
  35. Q->front->next = p->next;//修改头结点指针域
  36. if (Q->rear == p) Q->rear = Q->front;//最后一个元素被删,队尾指针指向头结点
  37. free(p);//释放队头元素空间
  38. return true;
  39. }
  40. //取队头元素
  41. bool GetHead(LinkQueue* Q, int* e) {
  42. //返回队头元素,不修改队头指针
  43. if (Q->front == Q->rear) return false;//判断队列是否为空
  44. QNode* p = Q->front->next;
  45. *e = p->data;//用e返回队头元素值
  46. return true;
  47. }
  48. //输出
  49. void print(LinkQueue* Q) {
  50. //前提为队不为空
  51. printf("(front) ");
  52. if (Q->front != Q->rear) {
  53. QNode* p = Q->front->next;
  54. while (p != NULL) {
  55. printf("%d ", p->data);
  56. p = p->next;
  57. }
  58. }
  59. printf("(rear)\n");
  60. }
  61. int main() {
  62. LinkQueue* Q = InitQueue();
  63. int i, n, e;
  64. scanf("%d", &n);
  65. for (i = 0; i < n; i++) {
  66. scanf("%d", &e);
  67. EnQueue(Q, e);
  68. }
  69. print(Q);
  70. DeQueue(Q, &e);
  71. printf("%d\n", e);
  72. print(Q);
  73. return 0;
  74. }

总结

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

闽ICP备14008679号