数据结构:队列

一、队列基础

1.基本定义

队列是一种先进先出(FIFO - First In First Out) 的线性数据结构。元素只能从队尾(rear/tail) 添加,从队头(front/head) 移除。

2.核心特性

  • 操作限制

    • 入队(Enqueue/Push):只能在队尾添加元素
    • 出队(Dequeue/Pop):只能在队头移除元素
  • 类比现实

    • 排队场景:就像现实生活中的排队,先来的人先服务,后来的人排在队尾。

3.常见应用场景

  • 任务调度:操作系统进程调度
  • 消息队列:消息传递系统
  • 广度优先搜索:BFS算法
  • 缓冲区管理:打印任务排队
  • 数据流处理:实时数据处理

4.特殊变种

  • 双端队列(Deque):两端都可插入删除
  • 循环队列:数组实现,充分利用空间
  • 优先队列:元素按优先级出队
  • 阻塞队列:队列空/满时阻塞操作

二、代码实现

  • C++标准库中的队列(queue)是一个容器适配器,提供了很多接口,常见的有入队,出队,判空,获取队头队尾,获取节点个数等。我们来逐一实现。
    下面是原代码及部分注释。

1.Queue.h

c 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>


//定义队列节点
typedef int QDataType;
typedef struct QueueNode
{
	struct QueueNode* pnext;
	QDataType x;
}QNode;

//定义队列
typedef struct Queue
{
	struct QueueNode* head;//队头
	struct QueueNode* ptail;//队尾
	int size;
}Queue;


//初始化队列
void QueueInit(Queue* ps);
//销毁队列
void QueueDestory(Queue* ps);

//入队列
void QueuePush(Queue* ps, QDataType x);
//出队列
void QueuePop(Queue* ps);

//获取队头数据
QDataType QueueFront(Queue* ps);
//获取队尾数据
QDataType QueueBack(Queue* ps);

//获取队列中有效元素个数
int QueueSize(Queue* ps);
//队列判空
bool QueueEmpty(Queue* ps);
//队列的打印
void QueuePrint(const Queue* ps);
  • 我们选择使用列表来实现队列,其中首先创建了一个节点结构体,但与队列不同的是:我们还创建了一个队列结构体,这样做的原因是:
    • 入队时只能在尾部入队,保存尾节点方便操作
    • 保存size可以直接进行获取元素个数,判空等操作
    • 根据队列的特点,我们发现定义一个队列结构体我们会方便很多。

2.Qnene.c

c 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include"Queue.h"

//初始化队列
void QueueInit(Queue* ps)
{
	assert(ps);
	ps->ptail = ps->head = NULL;
	ps->size = 0;
}
//销毁队列
void QueueDestory(Queue* ps)
{
	assert(ps);
	while (ps->size)
	{
		QNode* pFree = ps->head;
		ps->head = ps->head->pnext;
		free(pFree);
		ps->size--;
	}
	ps->head = NULL;
	ps->ptail = NULL;
}
//入队列
void QueuePush(Queue* ps, QDataType x)
{
	assert(ps);
	QNode* pcur = (QNode*)malloc(sizeof(QNode));
	pcur->x = x;
	//空队列情况
	if (ps->size == 0)
	{
		ps->head = ps->ptail = pcur;
		pcur->pnext = NULL;
		ps->size++;
		return;
	}
	ps->ptail->pnext = pcur;
	ps->ptail= pcur;
	pcur->pnext = NULL;
	ps->size++;
}

//出队列
void QueuePop(Queue* ps)
{
	assert(ps);
	assert(ps->size);
	//如果队列只有一个节点
	if (ps->size == 1)
	{
		free(ps->head);
		ps->ptail = ps->head = NULL;
		ps->size--;
		return;
	}
	QNode* pFree = ps->head;
	ps->head = ps->head->pnext;
	free(pFree);
	ps->size--;
}
//获取队头数据
QDataType QueueFront(Queue* ps)
{
	assert(ps);	
	assert(ps->head);
	return ps->head->x;
}
//获取队尾数据
QDataType QueueBack(Queue* ps)
{
	assert(ps);
	assert(ps->ptail);
	return ps->ptail->x;
}
//获取队列中有效元素个数
int QueueSize(Queue* ps)
{
	assert(ps);
	return ps->size;
}
//队列判空
bool QueueEmpty(Queue* ps)
{
	assert(ps);
	return ps->size==0;
}

//队列的打印
void QueuePrint(const Queue* ps)
{
	assert(ps);

	QNode* current = ps->head;
	printf("Head -> ");
	while (current != NULL)
	{
		printf("%d", current->x);
		if (current->pnext != NULL)
		{
			printf(" -> ");
		}
		current = current->pnext;
	}
	printf(" -> Tail\n");
}
  • 队列的写法与单链表基本相同,不过要注意其中对队列结构体的使用。唯一看的就是判空操作,我们返回ps->size == 0,而这是一个真假值,我们最好用bool类型。如果ps->size ==0,说明队列为空,判空操作返回真值。

3.测试代码

最后,我们对写完的代码进行测试

c 复制代码
#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include"Queue.h"
int main() {
    Queue q;

    printf("========== 测试1:初始化队列 ==========\n");
    QueueInit(&q);
    printf("初始化完成。\n");
    QueuePrint(&q);
    printf("\n");

    printf("========== 测试2:入队操作 ==========\n");
    QueuePush(&q, 10);
    QueuePrint(&q);
    QueuePush(&q, 20);
    QueuePrint(&q);
    QueuePush(&q, 30);
    QueuePrint(&q);
    QueuePush(&q, 40);
    QueuePrint(&q);
    printf("\n");

    printf("========== 测试3:获取队列信息 ==========\n");
    printf("队列大小: %d\n", QueueSize(&q));
    printf("队列是否为空: %s\n", QueueEmpty(&q) ? "是" : "否");
    printf("队头元素: %d\n", QueueFront(&q));
    printf("队尾元素: %d\n", QueueBack(&q));
    printf("当前队列状态: ");
    QueuePrint(&q);
    printf("\n");

    printf("========== 测试4:出队操作 ==========\n");
    printf("出队操作\n");
    QueuePop(&q);
    printf("出队后队列: ");
    QueuePrint(&q);
    printf("新队头元素: %d\n", QueueFront(&q));
    printf("队列大小: %d\n", QueueSize(&q));
    printf("\n");

    printf("再出队一次\n");
    QueuePop(&q);
    printf("出队后队列: ");
    QueuePrint(&q);
    printf("队列大小: %d\n", QueueSize(&q));
    printf("\n");

    printf("========== 测试5:边界情况测试 ==========\n");
    printf("继续出队直到队列为空...\n");

    printf("第三次出队\n");
    QueuePop(&q);
    printf("队列状态: ");
    QueuePrint(&q);

    printf("第四次出队\n");
    QueuePop(&q);
    printf("队列状态: ");
    QueuePrint(&q);

    printf("队列是否为空: %s\n", QueueEmpty(&q) ? "是" : "否");
    printf("队列大小: %d\n", QueueSize(&q));
    printf("\n");

    printf("========== 测试6:再次入队测试 ==========\n");
    printf("重新入队5个元素\n");

    for (int i = 1; i <= 5; i++) {
        printf("入队元素: %d\n", i * 100);
        QueuePush(&q, i * 100);
        QueuePrint(&q);
    }

    printf("\n========== 测试7:最终队列信息 ==========\n");
    printf("队列大小: %d\n", QueueSize(&q));
    printf("队头元素: %d\n", QueueFront(&q));
    printf("队尾元素: %d\n", QueueBack(&q));
    printf("最终队列状态: ");
    QueuePrint(&q);
    printf("\n");

    printf("========== 测试8:销毁队列 ==========\n");
    QueueDestory(&q);
    printf("队列销毁完成。\n");


    printf("所有测试完成!\n");

    return 0;
}
  • 最后显示测试通过,代表我们代码没有错误。

三、队列与栈的对比

队列(Queue) 栈(Stack)
顺序 先进先出(FIFO) 后进先出(LIFO)
插入 队尾(Rear) 栈顶(Top)
删除 队头(Front) 栈顶(Top)
类比 排队 盘子堆叠

四、结语

以上是队列的简介、实现及与栈的对比,如有错误,欢迎指正~

相关推荐
客梦39 分钟前
数据结构-哈希表
java·数据结构·笔记
失忆已成习惯.1 小时前
西农数据结构第四次实习题目参考
数据结构·算法·图论
kyle~1 小时前
排序---堆排序(Heap Sort)
数据结构·c++·算法
hweiyu001 小时前
数据结构:字典
数据结构
程序员东岸1 小时前
《数据结构——排序(下)》分治与超越:快排、归并与计数排序的终极对决
数据结构·c++·经验分享·笔记·学习·算法·排序算法
想唱rap2 小时前
C++之红黑树
开发语言·数据结构·c++·算法
Ayanami_Reii2 小时前
进阶数据结构应用-区间最大公约数
开发语言·数据结构·算法·线段树·差分·树状数组·fenwick tree
大千AI助手2 小时前
多维空间的高效导航者:KD树算法深度解析
数据结构·人工智能·算法·机器学习·大千ai助手·kd tree·kd树
kk”2 小时前
C++ AVL树
开发语言·数据结构·c++