队列的概念
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)入队列。
进行插入操作的一端称为队尾出队列,进行删除操作的一端称为队头。

由于队列需要进行队列头部删除数据,队列尾部插入数据,所以使用链表较为合适【数组虽然队尾插入数据方便,但是队头删除数据非常麻烦】
队列的实现
队列的结构体
队列的核心操作是队列的尾部出队列,队列的头部入队列。而普通的单向链表传递头结点时,只能方便队头删除结点,而对位插入结点需要保存链表的最后一个结点。
// 单链表结构——》表示队列
typedef int QDataType;
typedef struct QueueNode
{
struct QueueuNode* next;
QDataType data;
}QNode;
// 队列的结构——》一个指向头,一个指向尾部
typedef struct Queue
{
QNode* head;
QNode* tail;
}Queue;
- 队列有两个指针,一个指针指向链表头结点,一个指针指向链表最后一个结点;
- 每一个队列指针都保存着一个链表结点

队列初始化
// 队列初始化
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = pq->tail = NULL;
pq->size = 0;
}
初始化队列时,不需要开辟内存空间
队列销毁
// 队列销毁
void QueueDestroy(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
pq->head = pq->tail = NULL;
pq->size = 0;
}
队尾插入数据
// 队尾插入数据
void QueuePush(Queue* pq, QDataType x)
{
assert(pq);
QNode* newNode = (Queue*)malloc(sizeof(Queue));
if (newNode == NULL)
{
perror("newNode malloc fail!\n");
return;
}
// 赋值数据
newNode->data = x;
newNode->next = NULL;
// 判断队列是否为空
if (pq->head == NULL)
{
assert(pq->tail == NULL);
pq->head = pq->tail = newNode;
}
else
{
// tail后面链接
pq->tail->next = newNode;
// tail指向新的最后一个结点
pq->tail = newNode;
}
pq->size++;
}
插入数据需要注意队列中没有元素的情况,需要将队列的头指针和尾指针均指向新结点
队头删除数据
// 队头删除数据
void QueuePop(Queue* pq)
{
assert(pq);
// 如果head不为空,说明没有结点
assert(pq->head != NULL);
// 保存第一个结点
QNode* cur = pq->head;
// 链接第二个结点/或者链接NULL
pq->head = cur->next;
// 删除第一个结点
free(cur);
cur->data = 0;
cur->next = NULL;
if (pq->head == NULL)
{
// 说明释放的时候只有一个结点
pq->tail = NULL;
}
pq->size--;
}
这里重点需要考虑只有一个结点的情况,需要另外拿出来判断
队列的元素个数
// 队列的元素个数
size_t QueueSize(Queue* pq)
{
assert(pq);
return pq->size;
}
这里体现队列除了保存双指针,还添加保存了size数据的好处
队列是否为空
// 队列是否为空
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->head == NULL;
}
访问队头元素数据
// 访问队头元素数据
QDataType QueueFront(Queue* pq)
{
// 防止pq没有指向链表
assert(pq);
// 防止队列中没有元素
assert(!QueueEmpty(pq));
return pq->head->data;
}
访问队尾元素数据
// 访问队尾元素数据
QDataType QueueBack(Queue* pq)
{
// 防止pq没有指向链表
assert(pq);
// 防止队列中没有元素
assert(!QueueEmpty(pq));
return pq->tail->data;
}
队列的优点和缺点
优点
- 插入/删除数据操作效率高,时间复杂度为O(1)
- 符合“先进先出”,适用于特殊场景
缺点
- 随机访问中间元素效率低,需要将数据一个一个出队列,时间复杂度O(N)
- 功能单一
队列的代码实现
Queue.h头文件
#ifndef QUEUE_H_
#define QUEUE_H_
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
// 单链表结构——》表示队列
typedef int QDataType;
typedef struct QueueNode
{
struct QueueuNode* next;
QDataType data;
}QNode;
// 队列的结构——》一个指向头,一个指向尾部
typedef struct Queue
{
QNode* head;
QNode* tail;
size_t size;
}Queue;
// 队列初始化
void QueueInit(Queue* pq);
// 队列销毁
void QueueDestroy(Queue* pq);
// 队尾插入数据
void QueuePush(Queue* pq, QDataType x);
// 队头删除数据
void QueuePop(Queue* pq);
// 队列的元素个数
size_t QueueSize(Queue* pq);
// 队列是否为空
bool QueueEmpty(Queue* pq);
// 访问队头元素数据
QDataType QueueFront(Queue* pq);
// 访问队尾元素数据
QDataType QueueBack(Queue* pq);
#endif
Queue.c源文件
#include"Queue.h"
// 队列初始化
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = pq->tail = NULL;
pq->size = 0;
}
// 队列销毁
void QueueDestroy(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
pq->head = pq->tail = NULL;
pq->size = 0;
}
// 队尾插入数据
void QueuePush(Queue* pq, QDataType x)
{
assert(pq);
QNode* newNode = (Queue*)malloc(sizeof(Queue));
if (newNode == NULL)
{
perror("newNode malloc fail!\n");
return;
}
// 赋值数据
newNode->data = x;
newNode->next = NULL;
// 判断队列是否为空
if (pq->head == NULL)
{
assert(pq->tail == NULL);
pq->head = pq->tail = newNode;
}
else
{
// tail后面链接
pq->tail->next = newNode;
// tail指向新的最后一个结点
pq->tail = newNode;
}
pq->size++;
}
// 队头删除数据
void QueuePop(Queue* pq)
{
assert(pq);
// 如果head不为空,说明没有结点
assert(pq->head != NULL);
// 保存第一个结点
QNode* cur = pq->head;
// 链接第二个结点/或者链接NULL
pq->head = cur->next;
// 删除第一个结点
free(cur);
cur->data = 0;
cur->next = NULL;
if (pq->head == NULL)
{
// 说明释放的时候只有一个结点
pq->tail = NULL;
}
pq->size--;
}
// 队列的元素个数
size_t QueueSize(Queue* pq)
{
assert(pq);
return pq->size;
}
// 队列是否为空
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->head == NULL;
}
// 访问队头元素数据
QDataType QueueFront(Queue* pq)
{
// 防止pq没有指向链表
assert(pq);
// 防止队列中没有元素
assert(!QueueEmpty(pq));
return pq->head->data;
}
// 访问队尾元素数据
QDataType QueueBack(Queue* pq)
{
// 防止pq没有指向链表
assert(pq);
// 防止队列中没有元素
assert(!QueueEmpty(pq));
return pq->tail->data;
}

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



