目录
队列的概念
队列(Queue)是一种基础的数据结构,它遵循先进先出(First In First Out, FIFO)的原则。这意味着最早进入队列的元素也将是最先离开队列的元素。队列常被比喻为现实生活中的排队场景,比如在超市收银台前排队结账,先到的人先结账。
队列有两个主要的操作:
- 入队(Enqueue):将一个元素添加到队列的末尾。这相当于一个人加入到队伍的最后面。
- 出队(Dequeue):从队列的前端移除一个元素,并返回该元素。这相当于队伍最前面的人完成相应操作后离开队伍。
画图理解队列
这就是队列的一个基本结构,队尾入队,队头出队。在生活中也有这样的结构,请个看例图(希望可以给你带来印象):
生活中队列的例子非常普遍,以下是一些典型的实例:
超市结账:顾客在超市收银台前排队等待付款,先到的顾客先完成结账离开,后来的顾客依次跟进。
银行服务窗口:客户在银行的服务窗口前排队办理业务,遵循先来先服务的原则。
公共交通:在公交站、火车站或地铁站的候车队伍,乘客按照到达的先后顺序上车。
餐厅排队:在餐厅,特别是快餐店,顾客排队等待点餐和取餐,先排队的顾客先完成点餐流程。
打印机任务队列:在办公室,多个人提交打印任务时,打印机会按照任务提交的顺序依次执行打印。
医院挂号:病人在医院挂号处排队等待挂号,通常也是按照到达顺序进行服务。
网上购票系统:虽然看不见实体队伍,但在高峰时段购买热门活动或交通工具票务时,请求会被按接收顺序处理。
ATM机取款:人们在ATM机前排队取现金,每个人完成交易后下一个人才能使用。
代码图理解
代码展示(注意这个队列是单链表的结构实现)
Queue.h(队列结构)
cpp
#pragma once
/*--头文件--*/
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int DataType;
//创建队列结构
typedef struct QueueNode
{
struct QueueNode* Next;
DataType val;
}QueueNode;
//创建一个结构体来确定头/尾,可以避免使用二级指针,也可以用哨兵来避免使用二级指针
typedef struct Queue {
QueueNode* head;//头
QueueNode* tail;//尾
int size;//计数
}Queue;
/*--函数实现--*/
//初始化
void Q_Init(Queue* p);
//入队
void Q_Push(Queue* p, DataType x);
//出队
void Q_Pop(Queue* p);
//节点数
int Q_Size(Queue* p);
//获取头部
DataType Q_Front(Queue* p);
//获取尾部
DataType Q_Back(Queue* p);
//判断是否为空
bool Q_Empty(Queue* p);
//销毁
void Q_Destroy(Queue* p);
Queue.c(函数/API实现)
cpp
#define _CRT_SECURE_NO_WARNINGS 1
//函数实现
#include"Queue.h"
//初始化
void Q_Init(Queue* p) {
//断言
assert(p);
//初始化结构体
p->head = NULL;
p->tail = NULL;
p->size = 0;
}
//入队
void Q_Push(Queue* p, DataType x) {
//开辟一个节点
QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
if (newnode == NULL)//判断是否开辟成功
{
assert("malloc");
return;
}
//进行插入操作
newnode->Next = NULL;
newnode->val = x;
if (p->tail == NULL)
{
p->head = p->tail = newnode;
}
else
{
p->tail->Next = newnode;
p->tail = newnode;//更新tail的指向
}
p->size++;//push一下节点个数++
}
//出队
void Q_Pop(Queue* p) {
assert(p);
assert(p->size);//节点不能为空
//进行出队
if (p->head->Next == NULL)//一个节点
{
free(p->head);
p->head = p->tail = NULL;
}
else//多个节点
{
QueueNode* tmp = p->head->Next;//用临时变量存储head的下一个节点
free(p->head);//释放head的节点
p->head = tmp;//在更新head指向
}
p->size--;//pop一个节点个数--
}
//节点数
int Q_Size(Queue* p) {
assert(p);
assert(p->size);
return p->size;
}
//获取头部
DataType Q_Front(Queue* p) {
assert(p);
assert(p->size);
//直接返回head的元素
return p->head->val;
}
//获取尾部
DataType Q_Back(Queue* p) {
assert(p);
assert(p->size);
//直接返回tail的元素
return p->tail->val;
}
//判断是否为空
bool Q_Empty(Queue* p) {
assert(p);
//return p->size == 0;
return !p->size;
}
//销毁
void Q_Destroy(Queue* p) {
assert(p);
QueueNode* cur = p->head;
while (cur)
{
//存储下一个位置
QueueNode* tmp = cur->Next;
free(cur);
cur = tmp;
}
//指针制空
p->head = p->tail = NULL;
p->size = 0;
}
main.c(测试文件)
cpp
#define _CRT_SECURE_NO_WARNINGS 1
//测试
#include"Queue.h"
#if 0
int main1() {
Queue s1;
Q_Init(&s1);
Q_Push(&s1, 1);
Q_Push(&s1, 2);
Q_Push(&s1, 3);
Q_Push(&s1, 4);
while (!Q_Empty(&s1))
{
printf("%d ", Q_Front(&s1));
Q_Pop(&s1);
}
Q_Destroy(&s1);
}
#endif // 0
int main() {
//测试一个数据
Queue s1;
Q_Init(&s1);
Q_Push(&s1, 1);
Q_Push(&s1, 2);
Q_Push(&s1, 3);
while (!Q_Empty(&s1))
{
printf("%d ", Q_Front(&s1));
Q_Pop(&s1);
}
Q_Destroy(&s1);
}