当前位置: 首页 > article >正文

C语言实现队列数据结构:思路与代码详解

目录

一、引言 

二、整体思路 

三、代码模块分析 

(一)头文件包含与宏定义 

(二)数据类型定义 

(三)队列操作函数 

1. 队列初始化 

2. 队列销毁 

3. 入队操作 

4. 出队操作 

5. 获取队头元素 

6. 获取队尾元素 

7. 获取队列大小 

8. 判断队列是否为空 

(四)主函数测试 

四、总结 


作者主页:共享家9527-CSDN博客

一、引言
 


队列是一种重要的数据结构,遵循先进先出(FIFO)的原则。在C语言中,我们可以通过自定义结构体和一系列操作函数来实现一个队列。本文将详细介绍如何实现一个简单的队列,并对代码的各个部分进行深入分析。
 


二、整体思路
 


队列的实现主要涉及队列节点的定义、队列结构体的定义以及对队列的各种操作,如初始化、入队、出队、获取队头和队尾元素、判断队列是否为空和获取队列大小等。我们将这些操作模块化,每个函数负责一个特定的功能,使得代码结构清晰,易于维护和扩展。
 


三、代码模块分析
 


(一)头文件包含与宏定义
 


c
  
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
 


 
 _CRT_SECURE_NO_WARNINGS 宏定义用于关闭Visual Studio中一些函数的安全警告。后面依次包含了标准输入输出库、标准库、布尔类型库和断言库,为后续代码提供必要的功能支持。
 


(二)数据类型定义
 


c
  
typedef int QDatatype;
typedef struct QueueNode
{
    struct QueueNode* next;
    QDatatype data;
}QNode;

typedef struct Queue
{
    QNode* head;
    QNode* tail;
    int size;
}Queue;
 


 
-  QDatatype  定义为  int  类型,表示队列中存储的数据类型,这里是整型,也可以根据实际需求改为其他类型。
 
-  QueueNode  结构体定义了队列节点,包含一个指向下一个节点的指针  next  和存储数据的  data  成员。
 
-  Queue  结构体表示整个队列,包含指向队头的指针  head 、指向队尾的指针  tail  和记录队列元素个数的  size 。
 


(三)队列操作函数
 


1. 队列初始化
 


c
  
void QueueInit(Queue* pq)
{
    pq->head = pq->tail = NULL;
    pq->size = 0;
}
 


 
 QueueInit  函数用于初始化一个队列,将队头和队尾指针设为  NULL ,队列大小设为  0 。
 


2. 队列销毁
 


c
  
void QueueDestroy(Queue* pq)
{
    assert(pq);
    Queue* cur = pq->head;
    while (cur)
    {
        pq->head = pq->head->next;
        free(cur);
        cur = pq->head;
    }
    pq->head = pq->tail = NULL;
    pq->size = 0;
}
 


 
 QueueDestroy  函数用于释放队列占用的内存空间。通过遍历队列,逐个释放每个节点,最后将队头、队尾指针设为  NULL ,队列大小设为  0 。
 


3. 入队操作
 


c
  
void QueuePush(Queue* pq, QDatatype x)
{
    QNode* newnode = (QNode*)malloc(sizeof(QNode));
    if (newnode == NULL)
    {
        perror("malloc fail");
        return;
    }
    newnode->data = x;
    newnode->next = NULL;

    if (pq->head == NULL)
    {
        pq->head = pq->tail = newnode;
    }
    else
    {
        pq->tail->next = newnode;
        pq->tail = newnode;
    }
    pq->size++;
}
 


 
 QueuePush  函数用于将一个元素入队。首先分配一个新节点的内存空间,若分配失败则打印错误信息并返回。然后将新节点的数据设为传入的元素值, next  指针设为  NULL 。如果队列为空,则新节点既是队头也是队尾;否则将新节点连接到队尾,并更新队尾指针。最后队列大小加  1 。
 


4. 出队操作
 


c
  
void QueuePop(Queue* pq)
{
    assert(pq);
    assert(pq->head != NULL);

    if (pq->head->next == NULL)
    {
        free(pq->head);
        pq->head = pq->tail = NULL;
    }
    else
    {
        QNode* next = pq->head->next;
        free(pq->head);
        pq->head = next;
    }
    pq->size--;
}
 


 
 QueuePop  函数用于将队头元素出队。首先进行断言,确保队列指针有效且队列不为空如果队列只有一个元素,释放队头节点并将队头、队尾指针设为  NULL ;否则保存队头节点的下一个节点,释放队头节点,然后将队头指针指向下一个节点。最后队列大小减  1 。
 


5. 获取队头元素
 


c
  
QDatatype QueueFront(Queue* pq)
{
    assert(pq);
    assert(!QueueEmpty(pq));
    return pq->head->data;
}


 
 
 QueueFront  函数用于获取队头元素的值。先进行断言确保队列有效且不为空,然后返回队头节点的数据。
 


6. 获取队尾元素
 


c
  
QDatatype QueueBack(Queue* pq)
{
    assert(pq);
    assert(!QueueEmpty(pq));
    return pq->tail->data;
}
 


 
 QueueBack  函数用于获取队尾元素的值。同样先进行断言确保队列有效且不为空,然后返回队尾节点的数据。
 


7. 获取队列大小
 


c
  
int QueueSize(Queue* pq)
{
    return pq->size;
}
 
 
 QueueSize  函数直接返回队列结构体中记录的元素个数。
 


8. 判断队列是否为空
 


c
  
bool QueueEmpty(Queue* pq)
{
    assert(pq);
    return pq->head == NULL;
}
 


 
 QueueEmpty  函数通过判断队头指针是否为  NULL  来确定队列是否为空,为空则返回  true ,否则返回  false 。
 


(四)主函数测试
 


c
  
int main()
{
    Queue Q;
    QueueInit(&Q);
    QueuePush(&Q, 1);
    QueuePush(&Q, 2);
    QueuePush(&Q, 3);
    QueuePush(&Q, 4);
    QueuePush(&Q, 5);
    while (!QueueEmpty(&Q))
    {
        printf("%d ", QueueFront(&Q));
        QueuePop(&Q);
    }
    printf("\n");
    QueueDestroy(&Q);
    return 0;
}
 


 
在  main  函数中,我们对实现的队列进行了测试。首先初始化一个队列,然后依次将  1  到  5  这五个元素入队,接着通过循环不断获取队头元素并打印,同时将其出队,直到队列为空。最后销毁队列,释放内存。
 


四、总结
 


通过以上模块化的代码实现,我们完成了一个基本的队列数据结构。每个函数都有明确的功能,使得代码逻辑清晰,易于理解和维护。在实际应用中,可以根据具体需求对队列进行进一步的扩展和优化,如添加更多的操作函数或者改变数据存储类型等。


http://www.kler.cn/a/582627.html

相关文章:

  • ARM Cortex-M 内存映射详解:如何基于寄存器直接读写 寄存器映射方式编码程序 直接操作硬件寄存器来控制 MCU
  • JAVA(6)-运算符
  • [密码抓取] Windows 密码抓取 — 浏览器、数据库等其它密码的抓取
  • 【C++】【数据结构】链表与线性表
  • LeetCode 513. 找树左下角的值 java题解
  • Rabbitmq运维
  • 设计模式Python版 模板方法模式
  • 21 | 全面测试项目功能
  • python数据分析--pandas读取数据--按行和列提取数据
  • 【贪心算法4】
  • 人工智能在医疗领域的应用:技术革新与未来展望
  • 【解决报错】:detected dubious ownership in repository at ‘D:/idea_code/xxx‘问题
  • 【2步解决】phpstudy开机自启(自动启动phpstudy、mysql、nignx或apache、自动打开网址)
  • 【蓝桥杯python研究生组备赛】003 贪心
  • Python----计算机视觉处理(opencv:像素,RGB颜色,图像的存储,opencv安装,代码展示)
  • 动态规划-第2篇
  • JAVA SE 4.Java各版本特性
  • 手机端安装包签名原理
  • C++中数组作为函数参数传递,和使用指针作为函数参数有什么区别?
  • Webpack 打包详细教程