【数据结构和算法】--队列

目录

  • 队列的概念及结构
  • 队列的实现
    • 初始化
    • 入队
    • 出队
    • 其他一些队列函数
  • 小结
  • 队列相关题目

队列的概念及结构

队列是只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 的原则。

  • 入队列:进行插入操作的一端称为队尾
  • 出队列:进行删除操作的一端称为队头

队列结构联想起来也非常简单,如其名,队列就相当于银行办理业务的柜台前一条长长的队伍,排在队伍前面的人(队头)可以先办理,而在队伍最后面的人(队尾)只能最后办理,如果继续有人来办理业务就只能排在队尾,这样的模式就是队列且遵循队头出队列,队尾入队列的原则。结构大致如下:

在这里插入图片描述

队列的实现

队列的实现同样有两种方式–数组队列,链式队列

  1. 数组队列:
    如果用数组实现队列:这样队头就只能指向下标为0的位置,那么队尾就指向队列最后一个元素的后一个的下标,基于此结构,想要出队操作,时间复杂度就会升高为O(N)且十分不方便。因为每当要将下标为0的元素出队,后面的所有元素就要前移并改变队尾指向。大致如下:

在这里插入图片描述

还有一点就是,如果使用数组队列,在前期有大量数据入队列,动态开辟了很大的空间,到后期可能很多数据都出了队列但动态开辟的空间并不能释放,那就造成了严重的空间浪费。

  1. 链式队列:
    如果使用双向链表: 这与栈为什么不用双向链表实现一个道理,虽然可以实现,且入队/出队的时间复杂度都为O(1)但结构较为复杂,实现起来并不是很实用;
    那么我们这时会选择结构更优得单链表,虽说单链表尾插得时间复杂度是O(N),但我们可以定义一个变量(QNode* ptail)来记录单链表的尾节点,这样每次入队时便不用再遍历单链表找尾节点,时间复杂度也降为O(1)。结构如下:

在这里插入图片描述

这样按需开辟空间,出队列就释放节点,进队列新建节点,也大大减少了空间的浪费。我们便可如下定义队列的每个节点:

typedef int QDataType;
//队列节点
typedef struct QueueNode
{QDataType val;struct QueueNode* next;//链接下一个节点的指针
}QNode;

因为我们要记录队列的头(QNode* phead)和尾(QNode* ptail)(下文称这两个指针为头指针和尾指针),且基本每个函数都要用到这两个变量,甚至一些函数还要修改这两个变量对应的值,那就不得不传二级指针了,这也就大大增加了代码的难度!为了解决这个问题,我们可以定义一个结构体,并将这两个变量放到结构体中,每次函数调用时,只需传这个结构体地址即可
为了方便统计队列里面的节点数,我们通常还会定义一个整型变量size,有元素出队列时size--,入队列时size++
此结构体定义方式如下:

typedef struct Queue
{QNode* phead;QNode* ptail;int size;
}Queue;

初始化

初始时队列中无节点,所以pq->size = 0,头指针(pq->phead = NULL)尾指针(pq->ptail = NULL)都指向空。

//初始化
void QueueInit(Queue* pq)
{assert(pq);pq->size = 0;pq->phead = pq->ptail = NULL;
}

入队

入队操作首先要新建一个节点(类型为QNode),然后通过尾指针指向的节点链接此节点pq->ptail->next = newnode),并更新尾指针的指向pq->ptail = newnode),将记录节点数的值加1(pq->size++)。
在链接时还要考虑到队列为空的情况,此情况下直接将头/尾指针指向新建的节点(pq->ptail = pq->phead = newnode)。

//入队列
void QueuePush(Queue* pq, QDataType x)
{assert(pq);//新建节点QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("QueuePush()::malloc");return;}//新建的节点初始化newnode->next = NULL;newnode->val = x;//判断,链接if (pq->ptail == NULL){//1.原队列无节点pq->ptail = pq->phead = newnode;}else{//2.原队列已有节点pq->ptail->next = newnode;pq->ptail = newnode;}pq->size++;
}

出队

出队列操作首先要确保队列有节点才能出队,那么断言一下就可(assert(pq->phead);)。需要注意的是出队是头删,可以先定义变量记录头节点QNode* del = pq->phead;),然后再将头指针指向下一个节点phead = phead->next;),最后将原头节点释放free(del);),并将记录节点数的值减1pq->size--)。
当队列只有一个节点时,删除后队尾和队头指针都应该指向空,但上述操作并不能达到此效果,所以要单独判断一下,将尾指针指向空。

//出队列
void QueuePop(Queue* pq)
{assert(pq);//队列不为空assert(pq->phead);QNode* del = pq->phead;//记录头节点pq->phead = pq->phead->next;//头指针重定向free(del);//释放原头节点del = NULL;//队列是否被删空判断if (pq->phead == NULL)pq->ptail = NULL;pq->size--;
}

其他一些队列函数

  1. 队列有效数据个数:
    上面也讲过pq->size记录的就是队列的有效数据个数
//数据个数
int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}
  1. 队列是否为空:
    两种判断方法:1.当头指针指向NULL,2.pq->size的值为0
//队列是否为空
bool QueueEmpty(Queue* pq)
{assert(pq);return pq->phead == NULL;//return pq->size == 0;
}
  1. 返回队头数据:
    首先要判断队列不为空,然后返回头指针指向的节点的val即可。
//返回队头数据
QDataType QueueFront(Queue* pq)
{assert(pq);assert(pq->phead);return pq->phead->val;
}
  1. 返回队尾数据:
    同上,首先要判断队列不为空,然后返回尾指针指向的节点的val即可。
//返回队尾数据
QDataType QueueBack(Queue* pq)
{assert(pq);assert(pq->phead);return pq->ptail->val;
}
  1. 释放队列空间:
    遍历队列直到头指针指向空,每遍历一次释放一个节点,最后将头/尾指针指空,pq->size0
//释放
void QueueDetroy(Queue* pq)
{assert(pq);QNode* cur = pq->phead;//遍历,释放while (cur){//记录下一个节点地址QNode* next = cur->next;free(cur);cur = next;}pq->phead = pq->ptail = NULL;pq->size = 0;
}

小结

  • 队列是一种先进先出的结构,与栈相反;
  • 队列是头部删除尾部插入一般使用链表实现,且与栈结构一样不支持随机访问
  • 在实现队列时一般定义两个结构体,一个结构体用来记录每个节点中所需要的值,另一个用来记录队列的队头,队尾和节点数。第二个结构体的使用避免了二级指针,且在函数调用时一般传第二个结构体的地址

队列相关题目

  1. 下面关于栈和队列的说法中错误的是( A B
    A.队列和栈通常都使用链表实现
    B.队列和栈都只能从两端插入、删除数据
    C.队列和栈都不支持随机访问和随机插入
    D.队列是“先入先出”,栈是“先入后出”

这题主要考察对队列和栈的性质的区分,思路如下:

  • A错误:是尾部插入和删除,一般使用顺序表实现,队列是头部删除尾部插入,一般使用链表实现

  • B错误:是后进先出,尾部插入和删除队列是先进先出,尾部插入头部删除

  • C正确:栈只能访问栈顶元素,不支持随机访问,队列也不支持

  • D正确:栈和队列的特性

关于队列还有一个知识点就是循环队列,因其结构复杂就单独拿出来讲。

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

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

相关文章

持续集成交付CICD:通过API方式上传Nexus制品

目录 一、实验 1.通过API方式上传Nexus制品 二、问题 1.如何通过API方式上传PNG图片 2.如何通过API方式上传tar.gz 与 ZIP文件 3.如何通过API方式上传Jar file文件 4.如何通过API方式上传制品(maven类型的制品)文件 5.如何下载制品 一、实验 1.通…

各地加速“双碳”落地,数字能源供应商怎么选?

作者 | 曾响铃 文 | 响铃说 随着我国力争2030年前实现“碳达峰”、2060年前实现“碳中和”的“双碳”目标提出,为各地区、各行业的低碳转型和绿色可持续发展制定“倒计时”时间表,一场围绕“数字能源”、“智慧能源”、“新能源”等关键词的创新探索进…

【教程】Ipa Guard为iOS应用提供免费加密混淆方案

概述:使用ios加固工具对ios代码保护,保护ios项目中的核心代码, #ipagurd年终大促百厂联动暖冬特惠,超多软控件立享惊喜优惠>> ​ 简介 iOS加固保护是直接针对ios ipa二进制文件的保护技术,可以对iOS APP中的可…

Leetcode—113.路径总和II【中等】

2023每日刷题(五十七) Leetcode—113.路径总和II 实现代码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* …

使用 Taro 开发鸿蒙原生应用 —— 当 Taro 遇到纯血鸿蒙 | 京东云技术团队

纯血鸿蒙即将到来 在今年 8 月的「2023年华为开发者大会(HDC.Together)」上,华为正式官宣「鸿蒙Next」,这个更新的版本将移除所有的 AOSP 代码,彻底与 Android 切割,使其成为一个完全自主研发的操作系统&a…

数据挖掘目标(Kaggle Titanic 生存测试)

import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns1.数据导入 In [2]: train_data pd.read_csv(r../老师文件/train.csv) test_data pd.read_csv(r../老师文件/test.csv) labels pd.read_csv(r../老师文件/label.csv)[Su…

SqlServer中,数字-null的问题

一、业务描述 叫货单,已知叫货金额,填写本次付款金额,计算待付款金额 二、问题 在计算待付款金额时,偶尔会出现待付款金额为空的情况,百思不得其解 三、解决 仔细检查,发现了猫腻。 简单的说&#xff…

阿里云SMC迁移RedHat/CentOS 5 内核升级

阿里云SMC迁移RedHat/CentOS 5 内核升级 1. 起因 服务器需要迁移上阿里云,有几台服务器用的是Redhat 5.x,在使用SMC进行迁移时出现以下报错. [2023-12-13 09:50:55] [Error] Check System Info Failed, codeS16_111, msgGet OS Info Failed: [error] grub is too old for C…

33、变种卷积 - 分组卷积

这一节再了解一个卷积的变种,叫作分组卷积,这部分了解即可。 1、 什么是分组卷积 网上有很多关于分组卷积的资料。我整理了下,其实分组卷积是将卷积在channel 维度分组来计算,以达到将一个大卷积分成多个小卷积的目的。 为了清晰,我将卷积操作简化为一次最简单的乘累加运…

冒泡排序(函数)

冒泡排序&#xff0c;将一个列表中的两个元素进行比较&#xff0c;并将最小的元素交换到顶部。两个元素中较小的会冒到顶部&#xff0c;而较大的会沉到底部&#xff0c;该过程将被重复执行&#xff0c;直到所有元素都被排序。 输入格式: 输入在第1行中给出N&#xff08;1<N…

路径总和(递归)

112. 路径总和 - 力扣&#xff08;LeetCode&#xff09; 题目描述 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径&#xff0c;这条路径上所有节点值相加等于目标和 targetSum 。如果存在&#xff0c;返回 true &a…

Llama2-Chinese-7b-Chat安装部署

文章目录 前言一、文件介绍 &#x1f4c1;二、环境配置 ♟三、Llama2-Chinese-7b-Chat下载 ⏬总结 前言 本文主要介绍如何使用Llama2-Chinese-7b-Chat&#xff0c;最后的效果如图所示&#xff1a; 一、文件介绍 &#x1f4c1; ⬇️ 下载地址&#xff1a;https://pan.baidu.…

如何实现nacos的配置的热更新

我们在使用nacos进行修改配置后&#xff0c;需要微服务无需重启即可让配置生效&#xff0c;也就是使配置进行热更新我们可以采用下面的两种方式进行配置的热更新操作 方式一&#xff1a;在Value所注入的变量的类上添加注解RefreshScope RestController RequestMapping("/o…

Linux基本操作指令

哈喽小伙伴们&#xff0c;从这篇文章开始&#xff0c;在学习数据结构的同时&#xff0c;我们开启一个新的篇章——Linux操作系统的学习&#xff0c;这将会是又一个新的开始&#xff0c;希望小伙伴们能够认真细心&#xff0c;不要掉队哦。 目录 一.什么是Linux 二.为什么要学习…

git 相关操作说明

1.先下载git相关软件 下载地址&#xff1a; https://git-scm.com/download/win下载其中一个安装 2.打开gitee网站&#xff0c;注册账号 3.打开个人中心&#xff0c;选择ssh公钥&#xff0c;查看如何生成公钥 4.生成公钥后&#xff0c;添加相应的公钥 具体仓库操作 1.第一…

【Android】完美解决Cannot resolve method ‘subscribe(Observer<T>)‘

问题截图&#xff1a; 解决方法&#xff1a; 如上图&#xff0c;看我标123的三个地方&#xff0c;2标注的地方提示我们我方法实际返回的值是Observer<Res_GetCellCode>,而我想要返回的结果是&#xff1a;3标记的结果&#xff1a;Observer<Res_QueryCTInfo>&#xf…

git拉取代码冲突处理

参考文章&#xff1a;https://www.jianshu.com/p/b74ee1f4135f 问题&#xff1a; 因为git commit前没有git pull同步远程分支的代码&#xff0c;所以push会发生错误 解决办法&#xff1a; 1、可以使用git reset --hard HEAD^来回退到上一次commit的状态。此命令可以用来回退到…

智能优化算法应用:基于引力搜索算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于引力搜索算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于引力搜索算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.引力搜索算法4.实验参数设定5.算法结果6.…

AI日报:苹果为使用Mac的人工智能开发者推出开源工具

文章目录 总览主要介绍开发理念开发细节MLX功能用途 MLX可以用于商业软件吗&#xff1f; 总览 苹果正在为开发人员提供新的工具&#xff0c;用于在其硬件上训练和运行大型语言模型。 主要介绍 开发理念 苹果公司通过发布一系列新的开源人工智能工具&#xff0c;向开源人工智能…

关于“Python”的核心知识点整理大全17

目录 ​编辑 8.3.4 结合使用函数和 while 循环 greeter.py 8.4 传递列表 greet_users.py 8.4.1 在函数中修改列表 printing_models.py 8.4.2 禁止函数修改列表 要将列表的副本传递给函数&#xff0c;可以像下面这样做&#xff1a; 往期快速传送门&#x1f446;&#x…