数据结构 - 队列 [动画+代码注释超详解],萌新轻松上手!!!

news2024/11/21 2:22:57

一. 队列的概念

队列是一种特殊的线性表,用于存储元素,并且按照先进先出(First In First Out)的顺序进行管理,这意味着最先加入队列的元素将会是最先从队列中被移除的元素

队列的原型:只允许在一端进行插入数据的操作,在另一端进行删除数据的操作

队列的原则:队列中的元素遵循先进先出的原则 

队列的两个经典操作:

入队列:队列的插入操作叫做入队列,进行操作的一端称为队尾

出队列:队列的删除操作叫做出队列,进行操作的一端称为队头

二. 队列的结构

现实中的队列

 当我们去银行取款机排队取钱的过程就是队列,我们从队尾进入,依次取钱,取完钱之后从队头离开

三. 队列的实现

队列的实现有两种方式

一. 用数组实现

优点

  • 快速访问:数组允许随机访问,可以快速访问任何一个元素,特别是在入队和出队操作时,可以直接通过索引来访问队头和队尾。
  • 内存连续:数组是连续内存的数据结构,这可能有助于提高缓存效率,因为连续的内存块更有可能一起被加载到CPU缓存中。

缺点

  • 固定大小:数组的大小在初始化时固定,这意味着队列的容量有一个上限。如果队列满了,就需要执行昂贵的数组扩展操作,通常涉及分配一个更大的数组并复制现有元素。
  • 空间浪费:在使用数组实现循环队列时,即使数组中还有空间,队列也可能报告已满,这是因为循环使用的逻辑问题导致的空间利用不充分。

二. 用链表实现

优点

  1. 动态大小:链表提供了动态大小的能力,队列可以根据需要增长和缩小,不存在固定的容量限制。
  2. 内存利用率高:链表只在需要时分配内存,且只为实际存储的元素分配,这减少了内存浪费。

缺点

  1. 内存分配开销:链表的每个新元素都可能需要内存分配(除非使用内存池技术),这可能比连续的内存分配(如数组)更昂贵。
  2. 访问速度慢:链表不支持随机访问,访问任何位置的元素都需要从头开始遍历,这使得某些操作比数组慢。
  3. 额外内存需求:每个链表节点需要额外的内存空间来存储指向下一个节点的指针,这增加了每个元素的内存开销。

总结:不过整体上使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。下面我将用链表的结构来实现队列

1. 初始化队列

1.1 链式结构表示队列

在使用链表实现队列的时候,定义一个节点结构QNode,为队列中的每个元素提供一个容器,使得元素能连接起来

typedef int QDataType;

typedef struct QListNode  //定义一个节点
{
	struct QListNode* pNext; //指针域
	QDataType data; //数据域
}QNode;

1.2 队列的结构

普通链表通常只需要一个头指针来访问链表的起始位置,而队列为了支持高效的入队和出队操作,需要同时维护队头和队尾两个指针,我们通常会定义一个额外的结构体,这个结构体包括了指向队头的指针和指向队尾的指针。

typedef struct Queue
{
    QNode* front; // 队头指针
    QNode* rear;  // 队尾指针
} Queue;         // 队列结构体别名

1.3 队列的初始化 

接下来就是创建一个初始化函数,对队列里的元素进行初始化

void QueueInit(Queue* q)
{
    assert(q);  // 断言队列指针q不为NULL,确保不对NULL指针进行操作,提高程序的安全性。

    q->front = NULL; // 将队列的前端指针设置为NULL,表示队列为空,即队列中没有元素。
    q->rear = NULL;  // 将队列的后端指针也设置为NULL,与队列为空的状态一致,因为没有元素可以指向。
}

2. 销毁队列

从对头开始,进行释放空间,最后让队头队尾指针置为NULL

void QueueDestory(Queue* q)
{
    assert(q);            // 断言队列指针不为空

    QNode* cur = q->front;  // 创建一个变量,从队头开始销毁队列节点
    while (cur)
    {
        QNode* next = cur->next;  // 保存当前节点的下一个节点
        free(cur);                 // 释放当前节点的内存
        cur = next;                // 移动到下一个节点
    }

    q->front = NULL;  // 将队列的头指针置为空,表示队列已被销毁
    q->rear = NULL;   // 将队列的尾指针置为空,表示队列已被销毁
}

3. 入队列

申请一个新的节点链接到尾部,然后让尾指针,指向新节点  需要注意的是:若队列中无数据,我们需要让队头和队尾都指向这个新的节点

void QueuePush(Queue* q, QDataType x)
{
    assert(q);  // 断言队列指针不为空

    QNode* newnode = (QNode*)malloc(sizeof(QNode));  // 分配新节点的内存空间
    if (newnode == NULL)
    {
        printf("malloc fail\n");  // 如果内存分配失败,打印错误信息
        exit(-1);                  // 退出程序
    }

    newnode->data = x;   // 将数据存储到新节点中
    newnode->next = NULL;  // 新节点的下一个节点指针为空

    if (q->front == NULL)  // 如果队列为空
    {
        q->front = newnode;  // 将新节点设置为队列的头节点
        q->rear = newnode;   // 将新节点设置为队列的尾节点
    }
    else
    {
        q->rear->next = newnode;  // 将新节点链接到队列尾部
        q->rear = newnode;        // 更新队列的尾节点为新节点
    }
}

4. 出队列

释放队头的节点,并将队头更新到下一个元素。需要注意的是,如果队列中只有一个数据,在释放了队头的节点之后,要让队尾和队头的指针置空

void QueuePop(Queue* q)
{
    assert(q);  // 断言以确保队列指针 'q' 不是 NULL,保证这是一个有效的指针。
    assert(!QueueEmpty(q));  // 断言以确保队列不为空,仅当队列非空时才能进行出队操作。

    // 如果队列中只有一个节点,即队首和队尾是同一个节点
    if (q->front->next == NULL)
    {
        q->front = NULL;  // 将队首指针置为空
        q->rear = NULL;   // 将队尾指针置为空,因为队列要变为空队列
    }
    else
    {
        // 如果队列中不止一个节点,则将队首节点出队
        QNode* head = q->front->next;  // 临时保存新的队首节点
        free(q->front);  // 释放当前的队首节点的内存
        q->front = head;  // 更新队首指针为新的队首节点
    }
}

5. 获取队列的队头元素

返回队头指针指向的数据即可

QDataType QueueFront(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q));//检测队列是否为空

	return q->front->data;//返回队头指针指向的数据
}

6.获取队列的队尾元素

返回队尾指针指向的数据即可

QDataType QueueBack(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q));//检测队列是否为空

	return q->rear->data;//返回队尾指针指向的数据
}

7. 检测队列是否为空

判断队头的指针是否指向空

bool QueueEmpty(Queue* q)
{
	assert(q);
	return q->front == NULL;
}

8. 获取队列中有效元素个数

队列中有效元素个数,即队列中的结点个数。我们只需遍历队列,统计队列中的节点数并返回即可

int QueueSize(Queue* q)
{
    assert(q);  // 断言以确保队列指针 'q' 不是 NULL,保证这是一个有效的指针。

    QNode* cur = q->front;  // 创建一个指针 'cur',用来遍历队列,从队首开始
    int count = 0;  // 初始化计数器 'count',用于统计队列中的元素数量

    // 遍历队列,直到 'cur' 指针为空,即到达队列末尾
    while (cur)
    {
        count++;  // 对每个节点进行计数
        cur = cur->next;  // 将 'cur' 指针移动到下一个节点
    }
    
    return count;  // 返回队列中的元素总数
}

"Yesterday is history, tomorrow is a mystery, but today is a gift. That is why it is called the present."

昨日已成历史,明天充满未知,而今天是一份礼物,这就是为什么它被称为‘现在’。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1628828.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ArcGIS Pro 和 Python — 分析全球主要城市中心的土地覆盖变化

第一步——设置工作环境 1–0. 地理数据库 在下载任何数据之前,我将创建几个地理数据库,在其中保存和存储所有数据以及我将创建的后续图层。将为我要分析的五个城市中的每一个创建一个地理数据库,并将其命名为: “Phoenix.gdb” “Singapore.gdb” “Berlin.gdb” “B…

入户厨房设计,220大平层现代风三室装修。福州中宅装饰,福州装修

设计亮点 220㎡的平层住宅需要在氛围、功能和储物空间方面进行质的提升,以满足三口之家的需求。原始结构包括五个卧室和两个客厅,客餐厅整体通透,但厨房稍显局促,主卧功能分区不够清晰。 入户厨房 设计亮点 这个充满现代氛围的入…

SpringBoot---------Hutool

第一步&#xff1a;引入依赖 <dependency><groupId>cn.hutool</groupId><artifactId>hutool-parent</artifactId><version>5.7.17</version></dependency> 第二步&#xff1a;各种用法 ①生成随机数 //生成验证码 String s …

29.Gateway网关的全局过滤器GlobalFilter

全局过滤器的作用也是处理一切进入网关的请求和微服务响应。 与GatewayFilter的作用一样(filters, default-filters) 区别 GatewayFilter通过配置定义&#xff0c;处理逻辑是固定的。 GlobalFilter的逻辑需要自己写代码实现&#xff0c;可以自定义。 exchange表示 请求上下…

EXCEL表格中的数字,为什么每次打开会自动变成日期?

一、典型现象 在工作中&#xff0c;有时会发现公司里的报表&#xff0c;经过多人多次的重复的使用和修改后&#xff0c;会出现这种情况&#xff1a; 1.在表格里按照需要输入数字&#xff0c;保存工作簿。 2.然而&#xff0c;再次打开工作簿&#xff0c;里面的数字变成日期&a…

【嵌入式AI开发】轻量级卷积神经网络MobileNetV2详解

前言:MobileNetV2网络先升维后降维,在降维时使用线性激活函数,带残差的Inverted bottleck模块,防止ReLU信息丢失。在图像分类、目标检测、语义分割等任务上实现了网络轻量化、速度和准确度的权衡。 回顾MobileNetV1的理论和MobileNetV2项目实战可查阅如下链接: 【嵌入式AI…

【前端开发基础知识快速入门】

前端开发基础知识&快速入门 一、VSCode 使用1.1 安装常用插件1.2 创建项目1.3 创建网页1.4 运行效果二、ES62.1 简介2.2 什么是 ECMAScript2.3 ES6 新特性2.3.1 let 声明变量2.3.2 const 声明常量(只读变量)2.3.3 解构表达式2.3.4 字符串扩展2.3.5 函数优化2.3.6 对象优化…

ADM2483BRWZ 封装SOIC-16-300mil 隔离器芯片

ADM 2483 BRWZ 是一款由Analog Devices&#xff08;模拟器件公司&#xff09;生产的隔离式RS-485差分总线收发器。以下是ADM 2483 BRWZ的一些主要功能和参数介绍&#xff1a; 主要功能&#xff1a; 隔离通信: 提供电气隔离&#xff0c;以保护敏感的电子设备免受噪声干扰和高压…

nvm基本使用

nvm基本使用 文章目录 nvm基本使用1.基本介绍2.下载地址3.常用指令 1.基本介绍 NVM是一个用于管理 Node.js 版本的工具。它允许您在同一台计算机上同时安装和管理多个 Node.js 版本&#xff0c;针对于不同的项目可能需要不同版本的 Node.js 运行环境。 NVM 主要功能&#xff…

鸿蒙OpenHarmony【小型系统 编译】(基于Hi3516开发板)

编译 OpenHarmony支持hb和build.sh两种编译方式。此处介绍hb方式&#xff0c;build.sh脚本编译方式请参考[使用build.sh脚本编译源码]。 使用build.sh脚本编译源码 进入源码根目录&#xff0c;执行如下命令进行版本编译。 ./build.sh --product-name name --ccache 说明&…

探讨成为程序员后的收获和体会,以及对未来的展望。

成为程序员后的收获与体会&#xff1a;探索与成长的旅程 自从我踏入程序员这一行业&#xff0c;我的生活和思维方式都发生了巨大的变化。这不仅仅是因为我掌握了一种新的技能&#xff0c;更因为我开启了一段探索与成长的旅程。 首先&#xff0c;成为程序员让我深刻体会到了技…

U盘格式转换GPT格式转回DOS

当前格式 fdisk /dev/sdb# 在 fdisk 提示符下&#xff0c;输入以下命令删除分区&#xff1a; d # 选择要删除的分区编号&#xff08;如 1、2 等&#xff09; w开始转换 [rootnode-24 ~]# fdisk /dev/sdbWelcome to fdisk (util-linux 2.37.4). Changes will remain in memory o…

服务案例|服务器批量重启

告警产生 4月16日上午7:30分左右&#xff0c;福州某市医院20多台服务器批量重启&#xff0c;通知现场工程师。 故障分析定位 1、通过批量重启告警信息&#xff0c;发现内网esxi53主机硬件告警&#xff0c;初步判断是X86设备esxi53发生故障&#xff0c;导致esxi53上的虚拟服务…

uniapp 之 开发微信小程序入门详细指南

目录 配置运行设置&#xff08;编辑器的设置&#xff09;项目目录文件配置基础配置中的uniapp应用标识&#xff08;AppID&#xff09;配置微信小程序的AppID 总结 配置运行设置&#xff08;编辑器的设置&#xff09; 点击编辑器上方菜单栏 - 运行 - 运行到小程序模拟器 - 运行…

selenium 自动化测试课上实操指南1——百度搜索

1.环境准备 下面的所有资源可以从超星班级资料中下载&#xff0c;机房的同学在收到的文件夹中可以找到文件 非本校同学&#xff0c;免费加入学银在线课程&#xff0c;就可以在资料 根目录 > 02 课件新 > week09 web自动化测试02 里下载本次实操资料 1&#xff09;安…

3分钟入门Java多线程

如何在程序中创建出多条线程&#xff1f; 继承Thread类 public class MyThread extends Thread {Overridepublic void run() {for (int i 0; i < 10; i) {System.out.println("MyThread运行了" i);}} }实现Runnable接口 public class MyRunnable implements …

[Qt的学习日常]--信号和槽

前言 作者&#xff1a;小蜗牛向前冲 名言&#xff1a;我可以接受失败&#xff0c;但我不能接受放弃 如果觉的博主的文章还不错的话&#xff0c;还请点赞&#xff0c;收藏&#xff0c;关注&#x1f440;支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 本期学习&#xff…

【Qt 学习笔记】Qt常用控件 | 输入类控件 | Spin Box的使用及说明

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Qt常用控件 | 输入类控件 | Spin Box的使用及说明 文章编号&#xff1…

MySQL__索引

文章目录 &#x1f60a; 作者&#xff1a;Lion J &#x1f496; 主页&#xff1a; https://blog.csdn.net/weixin_69252724 &#x1f389; 主题&#xff1a; MySQL__索引&#xff09; ⏱️ 创作时间&#xff1a;2024年04月23日 ———————————————— 这里写目…

Arcpy入门笔记(三):数据属性的读取

Arcpy入门笔记&#xff08;三&#xff09;&#xff1a;数据属性的获取 文章目录 Arcpy入门笔记&#xff08;三&#xff09;&#xff1a;数据属性的获取常用的属性Describe对象属性&#xff08;部分&#xff09;数据集属性&#xff08;部分&#xff09;表属性&#xff08;部分&a…