数据结构:图文详解 队列 | 循环队列 的各种操作(出队,入队,获取队列元素,判断队列状态)

本文主要是介绍数据结构:图文详解 队列 | 循环队列 的各种操作(出队,入队,获取队列元素,判断队列状态),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


目录

队列的概念

队列的数据结构

队列的实现

入队

出队

获取队头元素

获取队列长度

循环队列的概念

循环队列的数据结构

循环队列的实现

判断队列是否为空

判断队列是否已满

入队

出队

得到队头元素

得到队尾元素


队列的概念

队列(Queue)是一种数据结构,是一种先进先出(First-In-First-Out,FIFO)的线性数据结构。它只允许在列表的一端进行插入操作(入队),在另一端进行删除操作(出队),即队头进行删除操作,队尾进行插入操作。队列常用的操作有入队(Enqueue)、出队(Dequeue)、获取队头元素(Front/Peek)、获取队列长度(Size/Length)等。

图示如下:

队列的特点是按照元素加入的先后顺序进行操作,先加入队列的元素会先被取出,后加入的元素会后被取出。这种特性常常被用于模拟实际生活中的排队场景,例如银行柜台排队、CPU任务调度等。


队列的数据结构

队列可以用数组或链表来实现。数组实现的队列需要预先分配一定的空间,但是在操作中效率较高;链表实现的队列没有固定的空间限制,但是在操作中可能需要更多的时间和空间。

这里笔者以链表进行演示:

public class MyQueue {static class ListNode {int val;//存放数据ListNode pre;//前驱指针ListNode next;//后驱指针public ListNode(int val) {this.val = val;}}private ListNode head;//记录头节点private ListNode last;//记录尾部节点
}

队列的实现

入队

因为我们使用的是链表来模拟实现,所以对于入队的操作就相当于使用尾插法(头插法),入队图示:

当队列为空的时候需要进行特殊处理,不然会造成空指针异常,队列为空的时候让我们的头指针和尾指针都指向这个节点就可以,如果队列不为空就正常的使用尾插法,尾插法图示:

    //入队public void enqueue(int val) {ListNode newNode = new ListNode(val);if (head == null) {head = newNode;last = newNode;}else {newNode.pre = last;last.next = newNode;last = newNode;}}

出队

队列是个单向的数据结构,对于入队我们使用了尾插法,那么出队就需要使用删除头节点的方法,出队的图示如下:

出队实际上是对于队头节点的删除,所以当队内没有节点的时候我们就不能进行这样的操作,我们直接抛出一个异常,在可以抛出的情况下,我们定义一个 val变量 来存放我们要删除的值,以便返回。当队列只有一个元素的时候要进行特殊处理,不然后面的程序会报空指针异常,这种情况下,我们需要先拿到头节点的值,然后将头节点置空,最后返回这个值;其余情况我们就正常进行删除操作,先拿到头节点的值然后让头节点后移,再让改变现在头节点的前驱指针,让我们要删除的数据无法被访问,最后返回这个值

    //出队public int dequeue() {if (head == null) {throw new ExceptionOfEmpty("队列为空,无法操作");}int val = -1;//当队列只有一个元素的时候要进行特殊处理,不然后面的程序会报空指针异常if (head.next == null) {val = head.val;head = null;last = null;return val;}//对于其他正常位置元素的处理val = head.val;head = head.next;head.pre = null;return val;}

获取队头元素

获取队头元素则十分的简单,使用个临时变量拿到头节点的值然后返回就可以了

    //拿出队列的首个元素进行查看public int peek() {if (head == null) {throw new ExceptionOfEmpty("队列为空,无法操作");}int val = head.val;return val;}

获取队列长度

获取队列的长度也非常的简单,使用一个新的节点挨个变量,然后累加计数器最后返回就可以

    //获取队列长度public int size() {int count = 0;ListNode cur = head;while (head != null) {cur = cur.next;count++;}return count;}

循环队列的概念

循环队列是一种特殊的队列数据结构,它允许队列的头尾相接,形成一个环。循环队列解决了普通队列的一些缺点,如空间浪费和在元素出队后无法再次入队的问题。

循环队列通常使用数组来实现,其内部有两个指针frontrear,分别指向队列的第一个元素和最后一个元素的下一个位置。初始化时,frontrear都指向数组的第一个位置。

当往循环队列中插入元素时,将元素放入rear指向的位置,并将rear指针向后移动一位。如果rear指针到达数组的尾部,则将其指向数组的起始位置。当从循环队列中删除元素时,将front指针向后移动一位,表示该元素已出队列。如果front指针到达数组的尾部,则将其指向数组的起始位置。

图示如下:

使用循环队列可以实现高效的元素入队和出队操作,因为循环队列的空间利用率较高。当队列满时,rear指针和front指针会指向同一个位置,此时队列被认为是满的。而在普通队列中,即使队列中还有空闲位置,当rear指针到达数组的尾部时,无法再向队列中插入元素。

循环队列通过循环利用数组空间,解决了普通队列的空间浪费和无法再次入队的问题,提高了队列的空间利用率和性能。


循环队列的数据结构

对于循环队列,我们可以使用数组来模拟实现,分别有俩个指针指向整个数组的首部和尾部

public class MyCircularQueue {public int[] elem;//存放数据public int front;//指向队头public int rear;//指向队尾MyCircularQueue(int k) {elem = new int[k];}
}

循环队列的实现

对于循环队列的实现,其实难点就在于判断队列的状态,分得清队列已满和队列为空的情况就可以,其余的操作实际上都是非常简单的数组的添加和删除元素

另外很重要的一点就是,循环队列需要体现出循环的概念,所以不管是队头指针还是队尾指针,我们在操作的时候都需要除以这个数组的模

判断队列是否为空

队列为空是怎么样的状态?为空,也就是说队列内什么都没有,队列的开始就是队列的结束,也就是队头指针和队尾指针指向同一个地方,如图所示:

    //判空 front和rear相遇public boolean isEmpty() {return front == rear;}

判断队列是否已满

队列已满是怎么样的状态?队列已满就是说队列每一个位置都有元素存放,这个情况下,如果队尾指针再往后走一步,就相当于回到了第二轮的起点,如图所示:

那么也就是说,当队尾指针再往后走一步的值除以整个队列的大小,就等于头指针的大小 

    //判空 front和rear相遇public boolean isFull() {return (rear + 1) % elem.length == front;}

入队

入队的时候,我们先要判断队列是否已满,满了就返回false表示入队失败;没有满的话就进行入队,也就是从数组的最后位置放个元素,然后再更改队尾指针指向,图示如下:

出队

出队的实现实际上就是对数组的第一个元素进行删除操作,如图所示:

    //出队public boolean deQueue() {if (isEmpty()) {return false;}front = (front + 1) % elem.length;return true;}

得到队头元素

这样的操作其实就是出队操作的简化,拿到值返回即可,这里就不再赘述

    //得到队头元素public int Front() {if (isEmpty()) {return -1;}return elem[front];}

得到队尾元素

这里有一点需要注意,当我们的队列只有一个元素的时候,是需要进行特殊处理的,不然就会出现数组越界的异常,毕竟数组不存在下标为-1的元素

    //得到队尾元素public int Rear() {if (isEmpty()) {return -1;}int index = (rear == 0) ? elem.length - 1 : rear - 1;return index;}



  本次的分享就到此为止了,希望我的分享能给您带来帮助,也欢迎大家三连支持,你们的点赞就是博主更新最大的动力!如有不同意见,欢迎评论区积极讨论交流,让我们一起学习进步!有相关问题也可以私信博主,评论区和私信都会认真查看的,我们下次再见

这篇关于数据结构:图文详解 队列 | 循环队列 的各种操作(出队,入队,获取队列元素,判断队列状态)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/509217

相关文章

C# 比较两个list 之间元素差异的常用方法

《C#比较两个list之间元素差异的常用方法》:本文主要介绍C#比较两个list之间元素差异,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1. 使用Except方法2. 使用Except的逆操作3. 使用LINQ的Join,GroupJoin

Python函数作用域示例详解

《Python函数作用域示例详解》本文介绍了Python中的LEGB作用域规则,详细解析了变量查找的四个层级,通过具体代码示例,展示了各层级的变量访问规则和特性,对python函数作用域相关知识感兴趣... 目录一、LEGB 规则二、作用域实例2.1 局部作用域(Local)2.2 闭包作用域(Enclos

Python实现对阿里云OSS对象存储的操作详解

《Python实现对阿里云OSS对象存储的操作详解》这篇文章主要为大家详细介绍了Python实现对阿里云OSS对象存储的操作相关知识,包括连接,上传,下载,列举等功能,感兴趣的小伙伴可以了解下... 目录一、直接使用代码二、详细使用1. 环境准备2. 初始化配置3. bucket配置创建4. 文件上传到os

Java内存分配与JVM参数详解(推荐)

《Java内存分配与JVM参数详解(推荐)》本文详解JVM内存结构与参数调整,涵盖堆分代、元空间、GC选择及优化策略,帮助开发者提升性能、避免内存泄漏,本文给大家介绍Java内存分配与JVM参数详解,... 目录引言JVM内存结构JVM参数概述堆内存分配年轻代与老年代调整堆内存大小调整年轻代与老年代比例元空

Python中注释使用方法举例详解

《Python中注释使用方法举例详解》在Python编程语言中注释是必不可少的一部分,它有助于提高代码的可读性和维护性,:本文主要介绍Python中注释使用方法的相关资料,需要的朋友可以参考下... 目录一、前言二、什么是注释?示例:三、单行注释语法:以 China编程# 开头,后面的内容为注释内容示例:示例:四

mysql表操作与查询功能详解

《mysql表操作与查询功能详解》本文系统讲解MySQL表操作与查询,涵盖创建、修改、复制表语法,基本查询结构及WHERE、GROUPBY等子句,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随... 目录01.表的操作1.1表操作概览1.2创建表1.3修改表1.4复制表02.基本查询操作2.1 SE

MySQL中的锁机制详解之全局锁,表级锁,行级锁

《MySQL中的锁机制详解之全局锁,表级锁,行级锁》MySQL锁机制通过全局、表级、行级锁控制并发,保障数据一致性与隔离性,全局锁适用于全库备份,表级锁适合读多写少场景,行级锁(InnoDB)实现高并... 目录一、锁机制基础:从并发问题到锁分类1.1 并发访问的三大问题1.2 锁的核心作用1.3 锁粒度分

MySQL数据库中ENUM的用法是什么详解

《MySQL数据库中ENUM的用法是什么详解》ENUM是一个字符串对象,用于指定一组预定义的值,并可在创建表时使用,下面:本文主要介绍MySQL数据库中ENUM的用法是什么的相关资料,文中通过代码... 目录mysql 中 ENUM 的用法一、ENUM 的定义与语法二、ENUM 的特点三、ENUM 的用法1

MySQL count()聚合函数详解

《MySQLcount()聚合函数详解》MySQL中的COUNT()函数,它是SQL中最常用的聚合函数之一,用于计算表中符合特定条件的行数,本文给大家介绍MySQLcount()聚合函数,感兴趣的朋... 目录核心功能语法形式重要特性与行为如何选择使用哪种形式?总结深入剖析一下 mysql 中的 COUNT

Go语言中nil判断的注意事项(最新推荐)

《Go语言中nil判断的注意事项(最新推荐)》本文给大家介绍Go语言中nil判断的注意事项,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1.接口变量的特殊行为2.nil的合法类型3.nil值的实用行为4.自定义类型与nil5.反射判断nil6.函数返回的