C语言链表实现队列全解析

C语言队列的链表实现

1. 引言
  • 队列的基本概念:队列是一种先进先出(FIFO)的线性数据结构,常用于任务调度、缓冲区管理等场景。
  • 解释为什么使用链表实现队列:链表提供动态内存管理,避免数组实现的固定大小限制,支持高效插入和删除操作。
  • 文章目标:帮助读者掌握链表实现队列的原理、C语言编码技巧和实际应用。
2. 队列的基本概念
  • 2.1 队列的定义
    • 队列是一种受限的线性表,元素只能从队尾入队,从队头出队。
    • 关键属性:FIFO原则,确保第一个进入的元素最先被移除。
  • 2.2 队列的核心操作
    • 入队(enqueue):添加元素到队尾。
    • 出队(dequeue):移除队头元素。
    • 检查队列状态:如判断队列是否为空(isEmpty)、获取队头元素(peek)等。
    • 时间复杂度分析:理想情况下,入队和出队操作的时间复杂度为O(1)(常数时间)。
3. 链表实现队列的原理

  • 3.1 链表节点及结构的设计

      typedef int QueueDataType;  //数据结构类型
      
      typedef struct QueueList    //队列节点结构体
      {
      	QueueDataType data;
      	struct QueueList* next;
      }QL;
      
      typedef struct QLList       //QL数据清单
      {
      	QL* phead;
      	QL* ptail;
      	int size;
      }QLL;
    • 3.2 入队操作(enqueue)

      • 步骤:动态分配新节点 → 设置新节点数据 → 将新节点链接到队尾 → 更新ptail指针。
      • 特殊情况处理:当队列为空时,front和ptail同时指向新节点。
      • 时间复杂度:O(1),因为只需修改指针。
      ///尾插
      void QueuePush(QLL* databag, QueueDataType x)
      {
      	assert(databag);
      	QL* newspace = (QL*)malloc(sizeof(QL));
      	
      	if (newspace == NULL)
      	{
      		perror("malloc fail!");
      		exit(1);
      	}
      	//如果队列为空
      	if (databag->phead == NULL)
      	{
      		databag->phead = databag->ptail = newspace;
      		databag->phead->data = x;
      		databag->phead->next = NULL;
      	}
      	//队列不为空
      	databag->ptail->next = newspace;
      	databag->ptail = databag->ptail->next;
      	databag->ptail->data = x;
      	databag->ptail->next = NULL;
      	databag->size++;
      }
    • 3.3 出队操作(dequeue)
      • 步骤:检查队列是否为空 → 移除队头节点 → 更新phead指针 → 释放内存。
      • 特殊情况处理:当队列只剩一个元素时,出队后设置ptailNULL
      • 时间复杂度O(1)。
    //头删
    void QueuePop(QLL* databag)
    {
    	assert(databag);
    	assert(databag->size>0);
    	QL* pcur = databag->phead;
    	databag->phead = databag->phead->next;
    	free(pcur);
    	databag->size--;
    	pcur == NULL;
    }
    • 3.4 其他辅助操作

      • 判断队列是否为空:检查size是否为0
      //判空
      bool QueueEmpty(QLL* databag)
      {
      	assert(databag);
      	return databag->size == 0;
      }

      • 获取队头,队尾元素:返回data,但不移除元素。
      //获取队头元素
      QueueDataType QueueFront(QLL* databag)
      {
      	assert(databag);
      	assert(databag->phead);
      	return databag->phead->data;
      }
      
      //获取队尾元素
      QueueDataType QueueBack(QLL* databag)
      {
      	assert(databag);
      	assert(databag->phead);
      	return databag->ptail->data;
      }
      
      • 销毁队列:遍历所有节点,释放内存。
    //销毁
    void QueueDestroy(QLL* databag)
    {
    	QL* cur = databag->phead;
    	while (cur)
    	{
    		QL* next = cur->next; // 先存下一个节点
    		free(cur);            // 释放当前节点
    		cur = next;           // 移动到下一个节点
    	}
    	// 重置队列状态
    	databag->phead = databag->ptail = NULL;
    	databag->size = 0;
    
    }

    获取队列元素个数

    //队列元素个数
    int QueueSize(QLL* databag)
    {
    	assert(databag);
    	return databag->size;
    }
    4. C语言代码实现
    • 4.1 完整代码示例
      • 提供上述完整的C语言代码,包括节点定义、队列结构、初始化、入队、出队等函数。
      • 代码使用标准库函数(如mallocfree),确保可移植性。
      Queue.h
      #pragma once
      #include<stdio.h>
      #include<assert.h>
      #include<stdlib.h>
      #include<stdbool.h>
      
      typedef int QueueDataType;  //数据结构类型
      
      typedef struct QueueList    //队列节点结构体
      {
      	QueueDataType data;
      	struct QueueList* next;
      }QL;
      
      typedef struct QLList       //QL数据清单
      {
      	QL* phead;
      	QL* ptail;
      	int size;
      }QLL;
      
      
      
      void QueueInit(QLL* databag);//队列初始化
      void QueuePush(QLL* databag, QueueDataType x);///尾插
      void QueuePop(QLL* databag);//头删
      int QueueSize(QLL* databag);//队列元素个数
      QueueDataType QueueFront(QLL* databag);//获取队头元素
      QueueDataType QueueBack(QLL* databag);//获取队尾元素
      bool QueueEmpty(QLL* databag);//判空
      void QueueDestroy(QLL* databag);//销毁
      
      
      
      Queue.c
      #define _CRT_SECURE_NO_WARNINGS
      
      #include "Queue.h"
      
      //队列初始化
      void QueueInit(QLL* databag)
      {
      	databag->phead = NULL;
      	databag->size = 0;
      	databag->ptail = NULL;
      }
      
      ///尾插
      void QueuePush(QLL* databag, QueueDataType x)
      {
      	assert(databag);
      	QL* newspace = (QL*)malloc(sizeof(QL));
      	
      	if (newspace == NULL)
      	{
      		perror("malloc fail!");
      		exit(1);
      	}
      	//如果队列为空
      	if (databag->phead == NULL)
      	{
      		databag->phead = databag->ptail = newspace;
      		databag->phead->data = x;
      		databag->phead->next = NULL;
      	}
      	//队列不为空
      	databag->ptail->next = newspace;
      	databag->ptail = databag->ptail->next;
      	databag->ptail->data = x;
      	databag->ptail->next = NULL;
      	databag->size++;
      }
      
      //头删
      void QueuePop(QLL* databag)
      {
      	assert(databag);
      	assert(databag->size>0);
      	QL* pcur = databag->phead;
      	databag->phead = databag->phead->next;
      	free(pcur);
      	databag->size--;
      	pcur == NULL;
      }
      
      //队列元素个数
      int QueueSize(QLL* databag)
      {
      	assert(databag);
      	return databag->size;
      }
      
      //获取队头元素
      QueueDataType QueueFront(QLL* databag)
      {
      	assert(databag);
      	assert(databag->phead);
      	return databag->phead->data;
      }
      
      //获取队尾元素
      QueueDataType QueueBack(QLL* databag)
      {
      	assert(databag);
      	assert(databag->phead);
      	return databag->ptail->data;
      }
      
      //判空
      bool QueueEmpty(QLL* databag)
      {
      	assert(databag);
      	return databag->size == 0;
      }
      
      //销毁
      void QueueDestroy(QLL* databag)
      {
      	QL* cur = databag->phead;
      	while (cur)
      	{
      		QL* next = cur->next; // 先存下一个节点
      		free(cur);            // 释放当前节点
      		cur = next;           // 移动到下一个节点
      	}
      	// 重置队列状态
      	databag->phead = databag->ptail = NULL;
      	databag->size = 0;
      
      }

    5. 性能分析与优缺点
    • 5.1 时间复杂度分析
      • 入队和出队:平均$O(1)$时间,因为链表操作只涉及指针修改。
      • 辅助操作:如isEmpty,时间复杂度为O(1)。
    • 5.2 空间复杂度
      • 空间复杂度为O(n),其中n是队列元素数量,每个节点需额外存储指针。
    • 5.3 优点
      • 动态大小:无需预分配内存,适应元素数量变化。
      • 高效操作:入队和出队接近常数时间。
    • 5.4 缺点
      • 额外内存开销:每个节点需要指针空间,比数组实现多出O(n)开销。
      • 碎片风险:频繁mallocfree可能导致内存碎片。
    • 5.5 应用场景
      • 适合内存充足、元素数量动态变化的系统,如实时任务队列。
    6. 结论
    • 总结链表实现队列的核心优势:灵活性高、操作高效。
    • 强调实践建议:在C语言项目中优先使用链表实现队列,避免数组的大小限制。
    • 扩展学习:推荐读者探索其他实现(如循环队列),并应用在实际项目中。
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值