Java数组队列及环形数组队列超详细讲解

目录
  • 一、队列
    • 1、基本介绍
    • 2、示意图
    • 3、队列的特点
  • 二、数组模拟队列
    • 1、数组队列初始化
    • 2、判断方法
    • 3、增删改查的方法
    • 4、注意
  • 三、数组模拟环形队列
    • 1、初始化
    • 2、判断方法
    • 3、增删改查的方法

一、队列

1、基本介绍

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。

2、示意图

3、队列的特点

先进先出:

在队列中插入一个队列元素称为入队,从队列中删除一个队列元素称为出队。因为队列只允许在一端插入,在另一端删除,所以只有最早进入队列的元素才能最先从队列中删除,故队列又被称为先进先出。

二、数组模拟队列

1、数组队列初始化

根据图示进行初始化:

class ArrayQueue{
    private int maxSize; //表示数组最大容量
    private int front; //队列头
    private int rear; //队列尾
    private int[] arr; //该数组用于存放数据,模拟队列
    //创建队列构造器,进行初始化
    public ArrayQueue(int arrMaxSize){
        maxSize = arrMaxSize;
        arr = new int[maxSize];
        front = -1; //front指向队列头的前一个位置
        rear = -1; //指向队列尾
    }
}

2、判断方法

判断队列是否为空

front 是指向队列的头的前一个位置,rear是指向队列的尾,当front和rear重合时,队列为空。

public boolean isEmpty(){
        return rear == front;
    }

判断队列是否满

因为数组有最大容量,所以直接判断rear(队列尾)是否在数组的最后位置。数组的下标从零开始。

public boolean isFull(){
        return rear == maxSize - 1;
    }

3、增删改查的方法

向队列中添加数据,入队列

▷ 添加数据首先判断数组是否满,如果满,则无法添加数据,数组未满则只需要动 rear(进行尾部移动),rear先加一,然后在数组中存放数据。

    //添加数据到队列
    public void addQueue(int n){
        //判断队列是否满
        if(isFull()){
            System.out.println("队列满,不能再添加");
            return;
        }
        rear++; //让rear后移
        arr[rear] = n;
    }

删除队列中数据,出队列

▷ 因为队列的特点先进先出,所以我们需要动队列的头,当然首先应该判断队列是否为空,为空则不能出队列;然后(front是指向队列头的前一个位置)先将front 加一到达队列的头的位置,再把这个值返回即可。有人可能会问队列的头呢?当front == -1时,数组下标为0 的数据为头,一旦front进行加一后,数组下标为1的数据就为头了,也就是当front进行变化后队列的头就变了。

    //获取队列数据,出队列
    public int getQueue(){
        //判断队列是否为空
        if(isEmpty()){
            //通过抛出异常
            throw new RuntimeException("队列为空,不能获取数据");
        }
        front++; //front后移
        return arr[front];
    }

显示队列中所有数据

▷ 因为是数组模拟的队列,将数组进行遍历输出即可。

    //显示队列的所有数据
    public void showQueue(){
        //判断是否为空
        if(isEmpty()){
            System.out.println("队列为空,没有数据");
            return;
        }
        //遍历
        for(int i = 0; i < arr.length ; i++){
            System.out.printf("arr[%d] = %d\n", i , arr[i] );
        }
    }

4、注意

这样的数组队列是不可逆的,当front在数组的末尾时,这个数组队列就不可用了,因为front 和 rear 不能循环到数组的前面去,所以这样的数组队列是非常局限的。而链表队列,就是队列是由单链表形成的,就没有数组大小的限制,可以无限的入队列和出队列,单链表的操作非常的简单,后续的文章会介绍。那么数组队列是否也可以无限入队列和出队列呢?当然可以,那么怎么可以实现呢?数组队列的局限在哪里?不就是front 和 rear 的指向不能回过头来指向数组的空位置。

只要解决了front 和 rear 能够返回到数组的空位置,是不是就能解决这个局限性的问题呢,因为出队列和入队列都是通过 front 和 rear 操作的。

三、数组模拟环形队列

1、初始化

数组的最大容量实际要少一个,因为我们要预留一个空位置,也就是任何时候数组要多一个空位置,便于我们循环。

class CircleTest{
    private int maxSize;//最大容量
    private int start;//表示队列的头
    private int end;//表示队列的尾的下一个,要预留一个空位
    private int[] arr;//数组用来存放数据
    public CircleTest(int maxSize){
        this.maxSize = maxSize;
        arr = new int[maxSize];
        //start和end默认初始化为0,所以不需要写
    }
}

2、判断方法

判断队列是否为空

start是指向队列的头,end是指向队列的尾的下一个,当start和end重合时,队列为空。

public boolean isEmpty(){
        return start == end;
    }

判断队列是否满

因为此时的数组队列可以循环,所以判断是否满的方法要用算法,让队列尾位置下标加一对总容量取余即可,然后判断是否等于start,比如:end = 2 ,start = 3

计算 (end + 1)% maxSize = (2 + 1)% 4 = 3 ,计算结果等于start ,所以是满状态,因为前面说了要预留一个位置,所以容量为4,实际存放数据为3个。

public boolean isFull(){
        return (end + 1) % maxSize == start;;
    }

计算数组中的有效数据

计算有效数据我们要用到一种取余的算法,算法式: (end + maxSize - start) % maxSize ,用队列头加上总容量减去队列尾再对总容量取余。比如:end = 0 ,start = 3

时,有效数据为 (1 + 4 - 3)% 4 = 2,所以有效数据为2个。

public int size(){
        return (end + maxSize - start) % maxSize;
    }

3、增删改查的方法

向队列中添加数据,入队列

首先判断队列是否满,然后因为我们早已预留了一个位置(end指向的位置是空的),所以加入的数据位置可以直接加入到队列(arr[end] = n);环形队列是要无限循环下去的,所以在加入数据后,end 的指向不能直接加一,而要用算法计算end的下一个位置,此算法为:(end + 1) % maxSize

比如:start = 2,end = 3 ,此时添加一个数据 end 的位置移动到在哪里?

根据算法(end + 1) % maxSize = (3 + 1) % 4 = 0 ,所以 end 指向数组下标为0 的位置。如此,就形成了循环。

    public void addData(int n){
        //先判断是否满
        if (isFull()){
            System.out.println("数据已满,无法添加");
            return;
        }
        //当前end的位置,加入元素
        arr[end] = n;
        //end指向下一个位置为(end + 1) % maxSize
        end = (end + 1) % maxSize;
    }

删除队列中数据,出队列

首先判断是否为空,然后将要出队列的数据用一个中间变量暂存起来,然后将start 移动,移动到的位置和上面end 的移动方式相同,也是用取余算法:(start + 1) % maxSize 即可。

    public int removeData(){
        //判断是否为空
        if(isEmpty()){
            throw new RuntimeException("数据为空,不能移除");
        }
        //先将数据暂存
        int temp = arr[start];
        //然后将start往后移到(start + 1) % maxSize的位置
        start = (start + 1) % maxSize;
        return temp;
    }

显示队列中所有数据

因为是循环队列,所以位置是无限变化的,所以每次for循环的开始位置为start 所在的位置,要循环的次数取决于数组中的有效数据的个数,及前面我们写的有效个数的算法拿来直接用( start + size() ),取余的方式 :i % maxSize ,可以时时确定数组数据的下标。

    public void showData(){
        //判断是否为空
        if(isEmpty()){
            System.out.println("数据为空,不能显示");
            return;
        }
        for (int i = start; i < start + size() ; i++) {
            System.out.printf("arr[%d] = %d\n", i % maxSize,arr[i % maxSize]);
        }
    }

注意:

循环的关键点在于 start 和 end 指向的下一个位置的确定,队列头和尾的位置可以回过头来,那么就能实现循环,而位置的确定,需要用到取余这个算法,前面的列子可以看出,指向发生变化时都是用的取余算法来确定位置,这个是数组中常见的一种算法,可以记住。

到此这篇关于Java数组队列及环形数组队列超详细讲解的文章就介绍到这了,更多相关Java数组队列内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java数据结构之环形链表和约瑟夫问题详解

    目录 一.环形链表 1.创建结点 2.添加小结点 3.显示循环链表 二.约瑟夫问题 1.问题描述 2.首先确定圈大小及开始位置 3.出圈操作 4.出圈方法完整代码 总结 一.环形链表 1.创建结点 环形链表其实也很好理解,就是将单链表的头和尾连接起来,就形成了环形链表. public class Node { public int data; public Node next; public Node(int data) { this.data = data; } @Override publi

  • Java队列篇之实现数组模拟队列及可复用环形队列详解

    队列简介 队列是一个有序列表,可以用数组或是链表来实现. 遵循先入先出的原则.即先存入队列的数据,先取出,后存入的后取出. 示意图:(使用数组模拟队列示意图) 有两个分别指向头部和尾部的"指针". 数组模拟队列(无法复用) 1.实现思路 队列本身是有序列表,若使用数组的结构来存储队列的数据,则队列数组的声明如下图,其中maxSize是该队列的最大容量. 因为队列的输出.输入是分别从前后端来处理,因此需要两个变量front及rear分别记录队列前后端的下标,front会随着数据输出而改变

  • Java 数据结构与算法系列精讲之环形链表

    目录 概述 链表 环形链表 环形链表实现 Node类 insert方法 remove方法 main 完整代码 概述 从今天开始, 小白我将带大家开启 Java 数据结构 & 算法的新篇章. 链表 链表 (Linked List) 是一种递归的动态数据结构. 链表以线性表的形式, 在每一个节点存放下一个节点的指针. 链表解决了数组需要先知道数据大小的缺点, 增加了节点的指针域, 空间开销较大. 链表包括三类: 单向链表 双向链表 循环链表 环形链表 环形链表 (Circular Linked Li

  • java中用数组实现环形队列的示例代码

    本篇文章主要讲述了使用数组实现环形队列的思路以及具体代码 一.队列是什么 我们先来看下百科的解释: 队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,队列是一种操作受限制的线性表.进行插入操作的端称为队尾,进行删除操作的端称为队头. 总结起来两点: 1.一种线性表 2.添加操作只能在表尾,删除操作在表头(先进先出) 二.实现队列的思路 1.初始化一个空队列 初始化一个大小固定的数组,并将头指针,尾指针都指向下表为0的位置,但其

  • Java数组队列概念与用法实例分析

    本文实例讲述了Java数组队列概念与用法.分享给大家供大家参考,具体如下: 一.队列的概念 (1)队列也是一种线性结构 (2)相比数组,队列对应的操作是数组的子集 (3)只允许在一端插入数据操作,在另一端进行删除数据操作,进行插入操作的一端称为队尾(入队列),进行删除操作的一端称为队头(出队列) (4)队列是一种先进先出的数据结构(FIFO) 此处我们先来学习一下顺序队列 ,顺序队列 就是用数组实现:比如有一个n个元素的队列,数组下标0的一端是队头,入队操作就是通过数组下标一个个顺序追加,不需要

  • Java数组队列及环形数组队列超详细讲解

    目录 一.队列 1.基本介绍 2.示意图 3.队列的特点 二.数组模拟队列 1.数组队列初始化 2.判断方法 3.增删改查的方法 4.注意 三.数组模拟环形队列 1.初始化 2.判断方法 3.增删改查的方法 一.队列 1.基本介绍 队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表.进行插入操作的端称为队尾,进行删除操作的端称为队头. 2.示意图 3.队列的特点 先进先出: 在队列中插入一

  • C语言超详细讲解栈与队列实现实例

    目录 1.思考-1 2.栈基本操作的实现 2.1 初始化栈 2.2 入栈 2.3 出栈 2.4 获取栈顶数据 2.5 获取栈中有效元素个数 2.6 判断栈是否为空 2.7 销毁栈 3.测试 3.1测试 3.2测试结果 4.思考-2 5.队列的基本操作实现 5.1 初始化队列 5.2 队尾入队列 5.3 队头出队列 5.4 队列中有效元素的个数 5.5 判断队列是否为空 5.6 获取队头数据 5.7 获取队尾的数据 5.8 销毁队列 6.测试 6.1测试 6.2 测试结果 1.思考-1 为什么栈用

  • C语言超详细讲解队列的实现及代码

    目录 前言 队列的概念 队列的结构 队列的应用场景 队列的实现 创建队列结构 队列初始化 队列销毁 入队列 出队列 队列判空 获取队列元素个数 获取队列头部元素 获取队列尾部元素 总代码 Queue.h 文件 Queue.c 文件 Test.c 文件 前言 队列的概念 队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头 队列和前文所学的栈

  • C语言超详细讲解轮转数组

    目录 题目描述 实例 解题思路 1. 先整体逆转 2.逆转子数组[0, k - 1] 3.逆转子数组[k, numsSize - 1] 易错点 代码 题目描述 给你一个数组,将数组中的元素向右轮转 k 个位置,其中 k 是非负数.OJ链接 实例 1.实例1 输入: nums = [1,2,3,4,5,6,7], k = 3输出: [5,6,7,1,2,3,4]解释:向右轮转 1 步: [7,1,2,3,4,5,6]向右轮转 2 步: [6,7,1,2,3,4,5]向右轮转 3 步: [5,6,7

  • C语言数组超详细讲解下篇扫雷

    目录 前言 1.扫雷是什么? 2.程序框架 2.1 主函数 2.2 函数menu 2.3 函数game 2.3.1 函数init_board 2.3.2 函数show_board 2.3.3 函数set_mine 2.3.4 函数find_mine 2.3.5 函数get_mine_count 3.头文件.h 4.游戏试玩 总结 前言 本文接着复习前面所学知识,以扫雷游戏为例. 1.扫雷是什么? 百度百科:<扫雷>是一款大众类的益智小游戏,于1992年发行.游戏目标是在最短的时间内根据点击格子

  • C语言数组超详细讲解中篇三子棋

    目录 前言 1.三子棋是什么? 1.1 百度百科 1.2 游戏编程准备工作 2. 程序实现 2.1 搭建程序框架 2.2 模块化编程 2.2.1 源文件test.c 2.2.2 源文件play.c 2.2.3 头文件play.h 2.3 程序实现—拓展play函数 2.3.1 棋盘初始化与打印函数 2.3.2 玩家下棋函数 PlayMover 2.3.3 电脑下棋函数 ComputerMove 2.2.4 判断赢家函数 WhoIsWin 总结 前言 本文主要是对前面所学内容进行复习和练习,学习内

  • C语言数组超详细讲解上

    目录 前言 1.一维数组的创建和初始化 1.1 一维数组的创建 1.2 一维数组的初始化 1.3 一维数组的使用 1.4 一维数组在内存中的存储 2.二维数组的创建和初始化 2.1 二维数组的创建 2.2 二维数组的初始化 2.3 二维数组的使用 2.4 二维数组在内存中的存储 3.数组越界 4.数组作为函数参数 4.1 冒泡排序函数的错误设计 4.2 数组名是什么? 4.3 对数组名的用法进行总结 4.4 冒泡排序函数的正确设计 总结 前言 本文主要介绍数组相关的内容,主要内容包括: 一维数组

  • C++超详细讲解数组操作符的重载

    目录 一.字符串类的兼容性 二.重载数组访问操作符 三.小结 一.字符串类的兼容性 问题:string 类对象还具备 C 方式字符串的灵活性吗?还能直接访问单个字符吗? string 类最大限度的考虑了 C 字符串的兼容性 可以按照使用 C 字符串的方式使用 string 对象 下面看一个用 C 方式使用 string 类的示例: #include <iostream> #include <string> using namespace std; int main() { stri

  • 超详细讲解Java线程池

    目录 池化技术 池化思想介绍 池化技术的应用 如何设计一个线程池 Java线程池解析 ThreadPoolExecutor使用介绍 内置线程池使用 ThreadPoolExecutor解析 整体设计 线程池生命周期 任务管理解析 woker对象 Java线程池实践建议 不建议使用Exectuors 线程池大小设置 线程池监控 带着问题阅读 1.什么是池化,池化能带来什么好处 2.如何设计一个资源池 3.Java的线程池如何使用,Java提供了哪些内置线程池 4.线程池使用有哪些注意事项 池化技术

  • Java 超详细讲解十大排序算法面试无忧

    目录 排序算法的稳定性: 一.选择排序 二.冒泡排序 三.插入排序 四.希尔排序 五.堆排序 六.归并排序 七.快速排序 八.鸽巢排序 九.计数排序 十.基数排序 排序算法的稳定性: 假定在待排序的记录序列中,存在多个具有相同的关键字的记录,如果排序以后,保证这些记录的相对次序保持不变,即在原序列中,a[i]=a[j],且 a[i] 在 a[j] 之前,排序后保证 a[i] 仍在 a[j] 之前,则称这种排序算法是稳定的:否则称为不稳定的. 一.选择排序 每次从待排序的元素中选择最小的元素,依次

随机推荐