C语言数据结构——详细讲解《队列》

十念  论坛元老 | 2024-11-30 18:33:14 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 1035|帖子 1035|积分 3105


媒介



  • 在上一篇博客中,我们详细探讨了栈这种数据结构,今天,让我们深入了解另一种与栈类似重要的数据结构 —— 队列。

一、队列的概念



  • 队列只允许在一端举行插入数据操纵,在另一端举行删除数据操纵的特殊线性表。队列遵照先进先出的原则
  • 入队列:举行插入操纵的一端称为队尾。
  • 出队列:举行删除操纵的一端称为队头。



  • 各人思索一个问题,队列的底层结构是数组还是链表
队列的底层结构既可以是数组,也可以是链表
[/table]

  • 基于数组实现的队列
  • 优点
   实现简单,逻辑清晰;可直接通过索引随机访问元素,时间复杂度为 O (1)。
  

  • 缺点
   需预先确定队列大小。若队列元素超数组大小,扩容操纵复杂且耗时
  

  • 基于链表实现的队列
  • 优点
   可动态调整大小,无需预先确定队列长度;队头和队尾的插入、删除操纵时间复杂度为 O (1)
  

  • 缺点
   每个节点需额外存储指针,占用空间。
无法直接通过索引访问元素,随机访问服从低
  
今天我们来详细讲解一下基于链表实现的队列 [table]

二、队列的操纵

(一)界说队列结构



  • 首先我们需要界说队列链表节点结构体
  1. //定义队列结点的结构
  2. typedef struct QueueNode
  3. {
  4.     QDataType data;
  5.     struct QueueNode* next;
  6. }QueueNode;
复制代码


  • 队列结点结构中的data成员用于存储队列中的实际数据
  • 接下来,我们界说队列结构体本身
  1. //定义队列的结构
  2. typedef struct Queue
  3. {
  4.     QueueNode* phead;  //队头
  5.     QueueNode* ptail;  //队尾
  6. }Queue;
复制代码


  • 接下来需要初始化队列
  1. // 初始化队列
  2. void initQueue(Queue *pq) {
  3.     pq->phead = NULL;
  4.     pq->ptail = NULL;
  5. }
复制代码
(二)初始化队列



  • 在使用队列之前,我们需要对其举行初始化操纵,将队头和队尾指针都设置为 NULL,表现队列为空。
  1. // 初始化队列
  2. void initQueue(Queue *pq) {
  3.     pq->phead = NULL;
  4.     pq->ptail = NULL;
  5. }
复制代码
(三)入队列操纵

  1. // 入队操作
  2. void enqueue(Queue *pq, int x) {
  3.     Node *newNode = (Node *)malloc(sizeof(Node));
  4.     newNode->data = x;
  5.     newNode->next = NULL;
  6.     if (pq->ptail == NULL)
  7.     {
  8.         // 队列为空的情况
  9.         pq->phead = newNode;
  10.         pq->ptail = newNode;
  11.     }
  12.     else
  13.     {
  14.         pq->ptail->next = newNode;
  15.         pq->ptail = newNode;
  16.     }
  17. }
复制代码


  • 先创建一个新节点,给它分配内存空间,
  • 把要入队的元素值赋给新节点的 data,并把 next 设为 NULL。
  • 然后看队列是不是空的,如果空,新节点就既是队头又是队尾;
  • 如果不空,就把新节点接到队尾节点背面,并更新队尾指针指向新节点
(四)出队列操纵

  1. //出队列
  2. int dequeue(Queue* pq)
  3. {
  4.     assert(pq->phead != NULL);
  5.     Node* temp = pq->phead;
  6.     int x = temp->data;
  7.     if (pq->phead == pq->ptail)
  8.     {
  9.         pq->phead = NULL;
  10.         pq->ptail = NULL;
  11.     }
  12.     else
  13.     {
  14.         pq->phead = pq->phead->next;
  15.     }
  16.     free(temp);
  17.     return x;
  18. }
复制代码


  • 从队列的队头取出一个元素并删掉对应的节点。
  • 先检查队列不能是空的,然后把队头节点的数据存起来,
  • 接着看队列是不是只有一个元素,
  • 如果是就把队头和队尾指针都设为 NULL;
  • 如果不止一个元素,就更新队头指针指向下一个节点,
  • 末了释放原来队头节点的内存并返回取出的元素值。
(五)获取队头元素

  1. // 获取队头元素
  2. int front(Queue* pq)
  3. {
  4.     assert(pq->phead != NULL);
  5.     return pq->phead->data;
  6. }
复制代码


  • 能获取队列的队头元素的值,但不把这个元素从队列里取出来。
  • 先得确保队列不是空的,然后直接返回队头节点的 data 值就行
(六)检查队列是否为空

  1. int isEmpty(Queue *pq)
  2. {
  3.     return pq->front == NULL;
  4. }
复制代码


  • 如果是就说明队列为空,返回相应结果,如许在其他操纵前可以先检查下队列状态,避免在空队列上做无效操纵
(七)销毁队列

  1. // 释放队列内存
  2. void freeQueue(Queue* pq)
  3. {
  4.     Node* current = pq->phead;
  5.     Node* next;
  6.     while (current != NULL)
  7.     {
  8.         next = current->next;
  9.         free(current);
  10.         current = next;
  11.     }
  12.     pq->phead = NULL;
  13.     pq->ptail = NULL;
  14. }
复制代码


  • 在队列用完后用来释放它占用的内存资源。
  • 从队头开始,逐个遍历队列里的节点,释放每个节点的内存,
  • 末了把队头和队尾指针都设为 NULL,让队列回到初始的空状态
(三)本文所有代码

1.Queue.h文件

  1. #pragma once#include <stdio.h>#include <stdlib.h>#include <assert.h>// 链表节点结构体typedef struct Node {    int data;    struct Node* next;} Node;// 队列结构体typedef struct Queue {    Node* phead;    Node* ptail;} Queue;// 初始化队列void initQueue(Queue* pq) {    pq->phead = NULL;    pq->ptail = NULL;}//入队列void enqueue(Queue* pq, int x){    Node* newnode = (Node*)malloc(sizeof(Node));    newnode->data = x;    newnode->next = NULL;    if (pq == NULL)    {        pq->phead = newnode;        pq->ptail = newnode;    }    else    {        pq->ptail->next = newnode;        pq->ptail = newnode;    }}
  2. //出队列
  3. int dequeue(Queue* pq)
  4. {
  5.     assert(pq->phead != NULL);
  6.     Node* temp = pq->phead;
  7.     int x = temp->data;
  8.     if (pq->phead == pq->ptail)
  9.     {
  10.         pq->phead = NULL;
  11.         pq->ptail = NULL;
  12.     }
  13.     else
  14.     {
  15.         pq->phead = pq->phead->next;
  16.     }
  17.     free(temp);
  18.     return x;
  19. }
  20. // 获取队头元素
  21. int front(Queue* pq)
  22. {
  23.     assert(pq->phead != NULL);
  24.     return pq->phead->data;
  25. }
  26. // 检查队列是否为空int isEmpty(Queue* pq) {    return (pq->phead != NULL) ? 0 : 1;}// 释放队列内存
  27. void freeQueue(Queue* pq)
  28. {
  29.     Node* current = pq->phead;
  30.     Node* next;
  31.     while (current != NULL)
  32.     {
  33.         next = current->next;
  34.         free(current);
  35.         current = next;
  36.     }
  37.     pq->phead = NULL;
  38.     pq->ptail = NULL;
  39. }
复制代码
2.Queue.c文件

  1. #include "Queue.h"
  2. #include <stdio.h>
  3. int main() {
  4.     Queue myQueue;
  5.     initQueue(&myQueue);
  6.     // 先输入一串数据来初始化队列
  7.     int num;
  8.     printf("请输入一串整数,以空格分隔,用于初始化队列,输入非整数结束输入:\n");
  9.     // 逐个读取输入的数据并将其入队
  10.     while (scanf_s("%d", &num) == 1) {
  11.         enqueue(&myQueue, num);
  12.     }
  13.     // 清除输入缓冲区中的剩余字符(例如换行符等)
  14.     while (getchar() != '\n');
  15.     int choice, value;
  16.     do {
  17.         printf("请选择操作:\n");
  18.         printf("1. 入队\n");
  19.         printf("2. 出队\n");
  20.         printf("3. 获取队头元素\n");
  21.         printf("4. 检查队列是否为空\n");
  22.         printf("5. 退出\n");
  23.         scanf_s("%d", &choice);
  24.         switch (choice) {
  25.         case 1:
  26.             printf("请输入要入队的值:");
  27.             scanf_s("%d", &value);
  28.             enqueue(&myQueue, value);
  29.             break;
  30.         case 2:
  31.             if (!isEmpty(&myQueue)) {
  32.                 printf("出队元素: %d\n", dequeue(&myQueue));
  33.             }
  34.             else {
  35.                 printf("队列为空,无法出队\n");
  36.             }
  37.             break;
  38.         case 3:
  39.             if (!isEmpty(&myQueue)) {
  40.                 printf("当前队头元素: %d\n", front(&myQueue));
  41.             }
  42.             else {
  43.                 printf("队列为空,无队头元素\n");
  44.             }
  45.             break;
  46.         case 4:
  47.             if (isEmpty(&myQueue)) {
  48.                 printf("队列为空\n");
  49.             }
  50.             else {
  51.                 printf("队列不为空\n");
  52.             }
  53.             break;
  54.         case 5:
  55.             printf("退出程序\n");
  56.             break;
  57.         default:
  58.             printf("无效的选择,请重新输入\n");
  59.         }
  60.     } while (choice != 5);
  61.     // 释放队列内存
  62.     freeQueue(&myQueue);
  63.     return 0;
  64. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

十念

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表