【队列】数据也得排队

news2024/11/25 22:27:38

目录

引言

队列的概念

队列的实现

单向链表队列

结构

初始化

入队

出队

取队头

取队尾

求个数

判空

内存释放

总结


引言

队列,这个看似普通的数据结构,其实隐藏着无尽的趣味和巧思。就像单向链表这把神奇的魔法钥匙,它能打开队列的奇妙大门。别担心,这不是一场枯燥的科普,而是一场充满冒险和乐趣的队列解密之旅。跟着我,我们一起揭开队列的神秘面纱,探寻它背后的精彩故事吧!

队列的概念

队列是一种特殊的线性表,它限制了数据的插入操作只能在一端进行,而删除操作则只能在另一端进行。这种先进先出(FIFO,First In First Out)的结构赋予了队列独特的特性。在队列中,进行插入操作的一端被称为队尾,而进行删除操作的一端则被称为队头

队列可以类比为我们在日常生活中经常遇到的排队现象。想象一下你在超市等待结账的队伍,第一个来的人首先被服务,然后是第二个、第三个,以此类推。这就像队列中的先进先出(FIFO)原则,新来的人只能排在队尾,而最先到达的人则首先离开队伍。队列在日常生活中的排队场景中,有效地维持了有序的服务顺序,确保了公平而有序的进行。

队列的实现

队列可以采用数组或链表的结构来实现,其中使用链表结构更为优越。相比数组结构,链表结构的优势在于在队列头部进行出队列操作时,不需要进行元素的搬移(链式结构维护了头指针和尾指针),从而提高了效率。而使用数组结构的话,虽然尾插的效率不错,但是头删的效率就大打折扣了。并且链表结构允许动态地分配和释放内存,更加灵活,适用于处理动态变化的队列大小。因此,使用链表结构实现队列能够更有效地支持队列操作,提升整体性能。

单向链表队列

结构

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>

// 定义队列中数据的类型
typedef int QEDataType;

// 定义队列节点的结构体
typedef struct QueueNode
{
	QEDataType* val;         // 数据指针
	struct QueueNode* next;  // 下一个节点指针
} QueueNode;

// 定义队列的结构体
typedef struct Queue
{
	QueueNode* phead;  // 队头指针
	QueueNode* ptail;  // 队尾指针
	int size;          // 队列大小
} Queue;

因为这里我们采用的是单向链表来实现队列,所以在执行入队操作时,时间复杂度会达到O(N),因为需要遍历一次链表来找尾,再进行尾插,所以我们干脆用一个结构体来维护这个队列的头节点和尾节点。并且结构体里还有一个size,这个用来指明队列当前数据个数。然后每个节点存储一个数据指针和下一个节点的指针。这种设计方便了队列的插入和删除操作,同时提供了对队列的基本信息的访问。 

初始化

void QueueInit(Queue* pq)
{
    assert(pq);  // 确保队列指针不为空

    pq->phead = NULL;  // 初始化队头指针为空
    pq->ptail = NULL;  // 初始化队尾指针为空
    pq->size = 0;      // 初始化队列大小为0
}

初始化队列的操作就好比给队列找了一个“家”,让队列有了一个干净的、什么都没有的地方,以便之后可以安心地往里面添加元素。这个“家”有两个门,一个是队头,一个是队尾。在开始的时候队头和队尾都是空的,还没有元素进来。而整个队列的大小也是零,表示里面一个元素都没有。这样,我们就为队列创造了一个清空的、准备好接纳元素的环境。

入队

void QueuePush(Queue* pq, QEDataType val)
{
    assert(pq);  // 确保队列指针不为空

    // 为新元素创建一个队列节点
    QueueNode* tmp = (QueueNode*)malloc(sizeof(QueueNode));
    if (tmp == NULL)
    {
        perror("malloc fail");
        exit(-1);
    }
	
    tmp->val = val;    // 将新元素的值存入节点
    tmp->next = NULL;  // 新节点的下一个节点暂时为空
    pq->size++;        // 队列大小加一

    if (pq->phead == NULL)  // 如果队列为空,新元素成为队头和队尾
    {
        pq->phead = pq->ptail = tmp;
    }
    else  // 如果队列不为空,将新元素追加到队尾,并更新队尾指针
    {
        pq->ptail->next = tmp;
        pq->ptail = tmp;
    }
}

想象一下队列就像是排队等候的人们,每个人都是队列中的一个元素。这个函数的作用就好比是有一个新的人想要加入队伍。我们会为这个人创建一个“队列节点”,这个节点就相当于这个新人的位置,用来存储他的信息。然后,我们检查一下队伍有没有空位如果队伍是空的,这个新人就是队伍的第一位,也是最后一位。如果队伍不是空的,我们就把这个新人加到队尾,然后更新队尾的位置。这样,队伍中就多了一个人,队伍的长度加一。 

出队

void QueuePop(Queue* pq)
{
    assert(pq);                   // 确保队列指针不为空
    assert(pq->size > 0);         // 确保队列不为空

    QueueNode* tmp = pq->phead;   // 临时指针指向队头
    pq->phead = pq->phead->next;  // 更新队头指针
    free(tmp);                    // 释放原队头的内存
    pq->size--;                   // 队列大小减一

    if (pq->phead == NULL)  // 如果队列变为空,更新队尾指针为空
        pq->ptail = NULL;
}

首先,我们会找到队头的位置,也就是队伍前面的人,用一个临时指针(tmp)指向这个位置。然后,我们把队头指针往后移动,表示队伍前面的人离开了。接着,我们释放掉原来队头位置的内存,因为这个人已经不在队伍中了。最后,队伍的长度减一,表示队伍中少了一个人。如果队伍变为空,我们还需要把队尾指针更新为空,因为队伍中没有人了,防止出现野指针问题。 

 取队头

QEDataType QueueFront(Queue* pq)
{
    assert(pq);             // 确保队列指针不为空
    assert(pq->size > 0);   // 确保队列不为空

    return pq->phead->val;  // 返回队头元素的值
}

这里通过我们的头指针很轻松就取到了队头的数据。 

取队尾

QEDataType QueueBack(Queue* pq)
{
    assert(pq);             // 确保队列指针不为空
    assert(pq->size > 0);   // 确保队列不为空

    return pq->ptail->val;  // 返回队尾元素的值
}

同理通过尾指针取队尾数据。 

求个数

int QueueSize(Queue* pq)
{
    assert(pq);       // 确保队列指针不为空

    return pq->size;  // 返回队列的大小
}

直接返回size的值即可。 

判空

bool QueueEmpty(Queue* pq)
{
    assert(pq);                // 确保队列指针不为空

    return pq->ptail == NULL;  // 如果队尾为空,说明队列为空,返回 true,否则返回 false
}

如果队列为空的话,那么尾指针肯定是空,当然头指针也是为空的。 

内存释放

void QueueDestroy(Queue* pq)
{
    assert(pq);  // 确保队列指针不为空

    QueueNode* cur = pq->phead;      // 从队头开始遍历队列节点
    while (cur)
    {
        QueueNode* tmp = cur->next;  // 保存下一个节点的指针
        free(cur);                   // 释放当前节点的内存
        cur = tmp;                   // 移动到下一个节点
    }

    pq->phead = pq->ptail = NULL;    // 将队头和队尾指针置为空
    pq->size = 0;                    // 队列大小清零
}

从队头开始遍历队列中的每个人(节点),释放每个人所占用的位置(内存)。然后,我们把队头和队尾的位置都设置为空,表示队伍不存在了。最后,队伍中的人数也变成了零,因为队伍已经解散了。这样,我们就成功地销毁了队伍,释放了它所占用的一切。 

总结

在这篇博客中,我们一起探索了队列这一数据结构。首先,我们探讨了队列的概念,对它先进先出的特性有了一定程度的了解。接着,我们介绍了队列的实现方式,着重讲解了使用单向链表实现队列的方法。在这一部分,我们探讨了结构设计、初始化、入队、出队、取队头、取队尾、求个数、判空以及内存释放等关键操作,使读者对队列的操作有了基础的了解。希望通过这篇博客,能让读者对队列有更全面的认识,并能够在未来的编程之旅中更加游刃有余地运用队列这一强大的工具。如果你队列的实现对你来说已经不在话下了,可以前往力扣选择队列的题目开冲。

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

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

相关文章

解决Git提交错误分支

如果 Git 提交到错误的分支&#xff0c;可以通过以下步骤将其转移到正确的分支上&#xff1a; 1.检查当前所在的分支&#xff0c;可以通过 git branch 命令查看。 git branch2.切换到正确的分支&#xff0c;可以通过 git checkout <正确的分支名> 命令进行切换。 git …

vue3-vite前端快速入门教程 vue-element-admin

Vue3快速入门学习 初始化项目 # 创建项目 npm create vitelatest my-vue-app -- --template vue # 安装依赖 npm i # 运行 npm run dev 模板语法 文本插值​ 最基本的数据绑定形式是文本插值&#xff0c;它使用的是“Mustache”语法 (即双大括号)&#xff1a; <span&g…

三相不平衡电压的正负序分析

1、什么是正负序&#xff1f; ABC 正序 ACB 负序 2、在abc坐标系下 接着利用矢量的旋转消去其它分量。。。 同理&#xff0c;得到其它的所有正负序的分量abc 3、在α/β坐标系下&#xff0c; 依次算出正负序的α/β来表示的abc 有一点需要特别注意&#xff0c;可以看到…

贪心其实很简单

关卡名 认识贪心思想 我会了✔️ 内容 1.复习一维数组&#xff0c;对数组进行多轮插入或者删除时会频繁移动数据&#xff0c;理解双指针是如何避免该问题的 ✔️ 2.理解滑动窗口的原理和适用场景 ✔️ 3.掌握窗口变与不变的两种情况是如何用来解题的 ✔️ 1.难以解释的贪心…

基于SpringBoot+Vue前后端分离的商城管理系统(Java毕业设计)

大家好&#xff0c;我是DeBug&#xff0c;很高兴你能来阅读&#xff01;作为一名热爱编程的程序员&#xff0c;我希望通过这些教学笔记与大家分享我的编程经验和知识。在这里&#xff0c;我将会结合实际项目经验&#xff0c;分享编程技巧、最佳实践以及解决问题的方法。无论你是…

【Linux】进程周边001之进程概念

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》《Linux》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负 目录 前言 1.基本概念 2.描述进程-PCB…

贪心算法及相关题目

贪心算法概念 贪心算法是指&#xff0c;在对问题求解时&#xff0c;总是做出在当前看来是最好的选择。也就是说&#xff0c;不从整体最优上加以考虑&#xff0c;算法得到的是在某种意义上的局部最优解 。 贪心算法性质&#xff08;判断是否可以使用贪心算法&#xff09; 1、贪…

【SpringBoot教程】SpringBoot 创建定时任务(配合数据库动态执行)

作者简介&#xff1a;大家好&#xff0c;我是撸代码的羊驼&#xff0c;前阿里巴巴架构师&#xff0c;现某互联网公司CTO 联系v&#xff1a;sulny_ann&#xff08;17362204968&#xff09;&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗…

DDD系列 - 第6讲 仓库Repository及Mybatis、JPA的取舍(一)

目录 一、领域层定义仓库接口1.1 设计聚合1.2 定义仓库Repository接口二 、基础设施层实现仓库接口2.1 设计数据库2.2 集成Mybatis2.3 引入Convetor2.4 实现仓库三、回顾一、领域层定义仓库接口 书接上回,之前通过一个关于拆解、微服务、面向对象的故事,向大家介绍了如何从微…

mysql中的DQL查询

表格为&#xff1a; DQL 基础查询 语法&#xff1a;select 查询列表 from 表名&#xff1a;&#xff08;查询的结果是一个虚拟表格&#xff09; -- 查询指定的列 SELECT NAME,birthday,phone FROM student -- 查询所有的列 * 所有的列&#xff0c; 查询结果是虚拟的表格&am…

【GlobalMapper精品教程】067:基于无人机航拍照片快速创建正射影像图

文章目录 一、加载无人机照片二、创建正射影像三、导出正射影像四、worldImagery比对一、加载无人机照片 打开globalmapper软件,点击打开数据文件。 选择配套实验数据data067.rar中的影像,Ctrl+A全选。 在globalmapper中,可以直接将照片加载为如下样式。 二、创建正射影像 …

深入理解网络中断:原理与应用

&#x1f52d; 嗨&#xff0c;您好 &#x1f44b; 我是 vnjohn&#xff0c;在互联网企业担任 Java 开发&#xff0c;CSDN 优质创作者 &#x1f4d6; 推荐专栏&#xff1a;Spring、MySQL、Nacos、Java&#xff0c;后续其他专栏会持续优化更新迭代 &#x1f332;文章所在专栏&…

[GPT]Andrej Karpathy微软Build大会GPT演讲(下)--该如何使用GPT助手

该如何使用GPT助手--将GPT助手模型应用于问题 现在我要换个方向,让我们看看如何最好地将 GPT 助手模型应用于您的问题。 现在我想在一个具体示例的场景里展示。让我们在这里使用一个具体示例。 假设你正在写一篇文章或一篇博客文章,你打算在最后写这句话。 加州的人口是阿拉…

【参天引擎】华为参天引擎内核架构专栏开始更新了,多主分布式数据库的特点,类oracle RAC国产数据开始出现了

cantian引擎的介绍 ​专栏内容&#xff1a; 参天引擎内核架构 本专栏一起来聊聊参天引擎内核架构&#xff0c;以及如何实现多机的数据库节点的多读多写&#xff0c;与传统主备&#xff0c;MPP的区别&#xff0c;技术难点的分析&#xff0c;数据元数据同步&#xff0c;多主节点的…

记录 | ubuntu上安装fzf

在 ubuntu 上采用命令行安装 fzf 的方式行不通 指的是采用下面的方式行不通&#xff1a; sudo apt install fzf # 行不通 sudo snap install fzf --classic # 行不通正确的安装方式是&#xff1a; ● 到 fzf 的 git 仓库&#xff1a;https://github.com/junegunn/fzf/re…

Landsat7_C2_SR数据集(大气校正地表发射率数据集)

Landsat7_C2_SR数据集是经大气校正后的地表反射率数据&#xff0c;属于Collection2的二级数据产品&#xff0c;空间分辨率为30米&#xff0c;基于Landsat生态系统扰动自适应处理系统&#xff08;LEDAPS&#xff09;&#xff08;版本3.4.0&#xff09;生成。水汽、臭氧、大气高度…

【SpringBoot教程】SpringBoot 实现前后端分离的跨域访问(Nginx)

作者简介&#xff1a;大家好&#xff0c;我是撸代码的羊驼&#xff0c;前阿里巴巴架构师&#xff0c;现某互联网公司CTO 联系v&#xff1a;sulny_ann&#xff08;17362204968&#xff09;&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗…

【Linux】进程见通信之匿名管道pipe

1.匿名管道的特点 以下管道的统称仅代表匿名管道。 管道是一个只能单向通信的通信信道。为了实现进程间通信.管道是面向字节流的。仅限于父子通信或者具有血缘关系的进程进行进程见通信。管道自带同步机制&#xff0c;原子性写入。管道的生命周期是随进程的。 2.匿名管道通信…

neuq-acm预备队训练week 8 P8794 [蓝桥杯 2022 国 A] 环境治理

题目描述 输入格式 输出格式 输出一行包含一个整数表示答案。 输入输出样例 解题思路 最短路二分 AC代码 #include<bits/stdc.h> using namespace std; long long temp,n, Q; long long f[105][105],min_f[105][105],cut[105],dis[105][105];//cut为减少多少&#x…

ubuntu20.04在noetic下编译orbslam2

ubuntu20.04在noetic下编译orbslam2 参考链接1&#xff1a;https://blog.csdn.net/qq_58869016/article/details/128660588 参考链接2&#xff1a;https://blog.csdn.net/dong123456789e/article/details/129693837 在noetic下的安装环境 1.库安装 sudo apt-get update sudo …