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指针 → 释放内存。 - 特殊情况处理:当队列只剩一个元素时,出队后设置
ptail为NULL。 - 时间复杂度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语言代码,包括节点定义、队列结构、初始化、入队、出队等函数。
- 代码使用标准库函数(如
malloc、free),确保可移植性。
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)开销。
- 碎片风险:频繁
malloc和free可能导致内存碎片。
- 5.5 应用场景
- 适合内存充足、元素数量动态变化的系统,如实时任务队列。
6. 结论
- 总结链表实现队列的核心优势:灵活性高、操作高效。
- 强调实践建议:在C语言项目中优先使用链表实现队列,避免数组的大小限制。
- 扩展学习:推荐读者探索其他实现(如循环队列),并应用在实际项目中。
7448

被折叠的 条评论
为什么被折叠?



