队列的概念以及结构
队列:只允许在队头进行删除数据操作,队尾进行插入数据操作,队列具有先进先出的特点。
队列可以用数组实现也可以使用链表实现,下面展示的是通过单链表实现的
很明显,我们可以看到,只有队头和队尾两个结点可以被直接访问
👀接着我们来看看队列的定义
首先是结点,这与单链表的结点结构一致
typedef struct QueueNode
{
QDataType data;
struct QueueNode* next;
}QNode;
接着是队列的结构,对应着上面的图片,这个队列的结构相当于就是蓝色的框架以及两个指向队首结点、队尾结点的指针
typedef struct Queue
{
QueueNode* head;
QueueNode* rear;
}Queue;
主要操作
入队
入队的操作与单链表的尾插一致,并且因为尾指针的存在,入队的时间复杂度为O(1)
⭐️这里要注意若队列中有元素时,新结点是插在队尾结点的后面;而队列为空时,只需要直接将新结点直接赋给队首指针和队尾指针即可
void QueuePush(Queue* q, QDataType data)
{
assert(q);
QNode* newNode = (QNode*)malloc(sizeof(QNode));
if (newNode == NULL)//检查新结点空间是否申请成功
printf("malloc fail.");
newNode->data = data;
newNode->next = NULL;
if (q->rear == NULL)
{
q->head = q->rear = newNode;
}
else
{
q->rear->next = newNode;
q->rear = newNode;
}
}
出队
我们先用一个指针指向当前的队首结点
接着队首指针指向下一个结点
最后将出队的队首结点释放即可
⭐️这时候我们也需要注意,当队列为空的时候是无法进行出队操作的
以及队中仅有一个元素的时候,队首指针是不用进行后移操作的
void QueuePop(Queue* q)
{
assert(q);
assert(q->head && q->rear); //避免队列中无元素的时候进行出队操作
/*
当然这里也可以选择比较柔和的检查方式,例如用if条件语句进行判断
*/
QNode* qf = q->head; //先用一个指针拿到队头结点
if (qf->next == NULL)
{//队中只有一个元素的时候
free(qf);
q->head = q->rear = NULL;
}
else
{//队中有多个元素的时候
q->head = q->head->next;//队首指针后移
free(qf);
}
}
还有一些操作例如获取队首、队尾元素,获取队列有效元素个数等,就放在下面的整体代码啦
整体代码
头文件:
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
typedef int QDataType;
typedef struct QueueNode
{
QDataType data;
struct QueueNode* next;
}QNode;
typedef struct Queue
{
QueueNode* head;
QueueNode* rear;
}Queue;
// 初始化队列
void QueueInit(Queue* q);
// 队尾入队列
void QueuePush(Queue* q, QDataType data);
// 队头出队列
void QueuePop(Queue* q);
// 获取队列头部元素
QDataType QueueFront(Queue* q);
// 获取队列队尾元素
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数
size_t QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
bool QueueEmpty(Queue* q);
// 销毁队列
void QueueDestroy(Queue* q);
函数实现:
#include "queue.h"
// 初始化队列
void QueueInit(Queue* q)
{
assert(q);
q->head = q->rear = NULL;
}
// 队尾入队列
void QueuePush(Queue* q, QDataType data)
{
assert(q);
QNode* newNode = (QNode*)malloc(sizeof(QNode));
if (newNode == NULL)//检查新结点空间是否申请成功
printf("malloc fail.");
newNode->data = data;
newNode->next = NULL;
if (q->rear == NULL)
{
q->head = q->rear = newNode;
}
else
{
q->rear->next = newNode;
q->rear = newNode;
}
}
// 队头出队列
void QueuePop(Queue* q)
{
assert(q);
assert(q->head && q->rear); //避免队列中无元素的时候进行出队操作
QNode* qf = q->head; //先用一个指针拿到队头结点
if (qf->next == NULL)
{//队中只有一个元素的时候
free(qf);
q->head = q->rear = NULL;
}
else
{//队中有多个元素的时候
q->head = q->head->next;//队首指针后移
free(qf);
}
}
// 获取队列头部元素
QDataType QueueFront(Queue* q)
{
assert(q);
assert(q->head);
/*当然这里也可以使用温柔点的检查
if (q->head == NULL)
printf("Queue is empty.");
*/
return q->head->data;
}
// 获取队列队尾元素
QDataType QueueBack(Queue* q)
{
assert(q);
assert(q->rear);
return q->rear->data;
}
// 获取队列中有效元素个数
size_t QueueSize(Queue* q)
{
assert(q);
QNode* cur = q->head;
size_t size = 0;
while (cur)
{
size++;
cur = cur->next;
}
return size;
}
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
bool QueueEmpty(Queue* q)
{
assert(q);
return q->head == NULL;
}
// 销毁队列
void QueueDestroy(Queue* q)
{
assert(q);
QNode* cur = q->head;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
q->head = q->head = NULL;
}
例牌小测试:
😄我是旺仔,和你一起成长