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

队列简介

队列是一个有序列表,可以用数组或是链表来实现。

遵循先入先出的原则。即先存入队列的数据,先取出,后存入的后取出。

示意图:(使用数组模拟队列示意图)

有两个分别指向头部和尾部的“指针”。

数组模拟队列(无法复用)

1、实现思路

队列本身是有序列表,若使用数组的结构来存储队列的数据,则队列数组的声明如下图,其中maxSize是该队列的最大容量。

因为队列的输出、输入是分别从前后端来处理,因此需要两个变量front及rear分别记录队列前后端的下标,front会随着数据输出而改变,而rear则是随着数据输入而改变,如图所示:

当我们将数据存入队列时称为addQueue,addQueue的处理需要有两个步骤:
①将尾指针往后移。
②若尾指针rear小于队列的最大下标maxSize-1,则将数据存入rear 所指的数组元素中,否则无法存入数据。

rear+1当front== rear[空]
rear==maxSize-1[队列满]

2、代码实现

①数组实现队列类

class ArrQueue {
    private int maxSize; //队列(数组)最大容量
    private int front; //指向队列头部
    private int rear; //指向队列尾部
    private int[] queue;

    //创造队列的构造器
    public ArrQueue(int maxSize){
        this.maxSize = maxSize;
        queue = new int[maxSize];
        front = -1; //其实是队列第一个元素的前一个索引
        rear = -1; //最后一个元素的索引
    }

    //判断是否满
    public boolean isFull(){
        return rear == maxSize - 1;
    }

    //判断是否空
    public boolean isEmpty(){
        return front == rear;
    }

    //添加元素
    public void addQueue(int n){
        if (isFull()){
            System.out.println("队列已经满了,无法添加!");
            return;
        }else {
            rear++;
            queue[rear] = n;
        }

    }

    //取出元素
    public int getQueue(){
        if (isEmpty()){
            throw new RuntimeException("队列为空,无元素可取!");
        }else {
            front++;
            return queue[front];
        }
    }

    //显示队列
    public void showQueue(){
        if (isEmpty()){
            System.out.println("队列为空,没有元素可显示!");
            return;
        }
        for (int i : queue){
            System.out.println(i);
        }
    }

    //显示头数据
    public void headQueue(){
        if (isEmpty()){
            throw new RuntimeException("队列为空,没有头数据!");
        }
        int i = front;
        System.out.println(queue[++i]);
    }

}

②测试类

import java.util.Scanner;

/**
 * @Author: Yeman
 * @Date: 2021-10-11-22:02
 * @Description:
 */
public class ArrayQueueTest {
    public static void main(String[] args) {
        //创建一个队列
        ArrQueue arrQueue = new ArrQueue(3);
        //创建一个用户输入
        Scanner scanner = new Scanner(System.in);
        //创建一个功能菜单
        char key = ' ';
        boolean isShow = true;
        while (isShow){
            System.out.println("s:显示队列");
            System.out.println("a:添加数据");
            System.out.println("g:取出数据");
            System.out.println("h:显示头数据");
            System.out.println("e:退出程序");
            key = scanner.next().charAt(0);
            switch (key){
                case 's' :
                    arrQueue.showQueue();
                    break;
                case 'a' :
                    System.out.println("请输入一个数:");
                    int value = scanner.nextInt();
                    arrQueue.addQueue(value);
                    break;
                case 'g' :
                    try {
                        System.out.println(arrQueue.getQueue());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    break;
                case 'h' :
                    try {
                        arrQueue.headQueue();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    break;
                case 'e' :
                    isShow = false;
                    break;
            }
        }
        System.out.println("程序退出...");
    }
}

数组模拟环形队列(可复用)

对前面的数组模拟队列的优化,充分利用数组。将数组看做是一个环形的,即取出之后,有位置可以空出来添加。(通过取模的方式来实现即可)

分析说明:
①尾索引的下一个为头索引时表示队列满,即将队列容量空出一个作为约定。在作判断队列满的时候需要注意(rear+ 1) % maxSize== front [满]
②rear == front [空]

1、思路如下:

①front 变量的含义调整:front 指向队列的第一个元素, 也就是说arr[front]就是队列的第一个元素,front的初始值为0。
②rear 变量的含义调整:rear 指向队列的最后一个元素的后一个位置,因为希望空出一个空间做为约定,rear的初始值=0。
③当队列满时,条件是(rear + 1) % maxSize == front [满]
④对队列为空的条件是rear== front[空]
⑤当我们这样分析,队列中有效的数据的个数(rear + maxSize - front) % maxSize
⑥我们就可以在原来的队列上修改得到一个环形队列

2、代码实现

①数组实现环形队列类

class ArrQueue {
    private int maxSize; //队列(数组)最大容量
    private int front; //指向队列头部,队列第一个元素的索引
    private int rear; //指向队列尾部,队列最后一个元素的后一个索引
    private int[] queue;

    //创造队列的构造器
    public ArrQueue(int maxSize){
        this.maxSize = maxSize;
        queue = new int[maxSize];
    }

    //判断是否满
    public boolean isFull(){
        return (rear + 1) % maxSize == front;
    }

    //判断是否空
    public boolean isEmpty(){
        return front == rear;
    }

    //添加元素
    public void addQueue(int n){
        if (isFull()){
            System.out.println("队列已经满了,无法添加!");
            return;
        }else {
            queue[rear] = n;
            rear = (rear + 1) % maxSize;
        }

    }

    //取出元素
    public int getQueue(){
        if (isEmpty()){
            throw new RuntimeException("队列为空,无元素可取!");
        }else {
            int data = queue[front];
            front = (front + 1) % maxSize;
            return data;
        }
    }

    //显示队列
    public void showQueue(){
        if (isEmpty()){
            System.out.println("队列为空,没有元素可显示!");
            return;
        }
        for (int i = front; i < front + size(); i++) {
            System.out.printf("arr[%d] = %d\n",i % maxSize,queue[i % maxSize]);
        }

    }
    //求当前队列有效数据个数
    public int size(){
        return (rear + maxSize - front) % maxSize;
    }

    //显示头数据
    public void headQueue(){
        if (isEmpty()){
            throw new RuntimeException("队列为空,没有头数据!");
        }
        System.out.println(queue[front]);
    }

}

②测试类

import java.util.Scanner;

/**
 * @Author: Yeman
 * @Date: 2021-10-11-22:02
 * @Description:
 */
public class ArrayQueueTest {
    public static void main(String[] args) {
        //创建一个队列
        ArrQueue arrQueue = new ArrQueue(3); //说明该环形队列的最大有效数据为2
        //创建一个用户输入
        Scanner scanner = new Scanner(System.in);
        //创建一个功能菜单
        char key = ' ';
        boolean isShow = true;
        while (isShow){
            System.out.println("s:显示队列");
            System.out.println("a:添加数据");
            System.out.println("g:取出数据");
            System.out.println("h:显示头数据");
            System.out.println("e:退出程序");
            key = scanner.next().charAt(0);
            switch (key){
                case 's' :
                    arrQueue.showQueue();
                    break;
                case 'a' :
                    System.out.println("请输入一个数:");
                    int value = scanner.nextInt();
                    arrQueue.addQueue(value);
                    break;
                case 'g' :
                    try {
                        System.out.println(arrQueue.getQueue());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    break;
                case 'h' :
                    try {
                        arrQueue.headQueue();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    break;
                case 'e' :
                    isShow = false;
                    break;
            }
        }
        System.out.println("程序退出...");
    }
}

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

(0)

相关推荐

  • java数组实现队列及环形队列实现过程解析

    这篇文章主要介绍了java数组实现队列及环形队列实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 代码内容 ArrayQueue---用数组实现队列 package com.structure; import java.util.Scanner; /** * @auther::9527 * @Description: 数组模拟队列 * @program: jstl2 * @create: 2019-10-05 08:58 */ pub

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

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

  • Java 单向队列及环形队列的实现原理

    目录 队列的特点 图解实现过程: 优化解决--环形队列实现思路 环形队列各步骤及各方法实现讲解 最后: 队列的特点 1.可以使用数组和链表两种方式来实现. 2.遵循先入先出(FIFO)的规则,即先进入的数据先出. 3.属于有序列表. 图解实现过程: ​1.定义一个固定长度的数组,长度为maxSize. ​2.设置两个指针first = -1(指向队列第一个数据的前一位,这样保证在添加第一个数据以后头指针为0,和数组的下标一样,且用于操作出队)和last = -1(指向队尾,用于操作入队). ​3

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

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

  • Java中的数组复制(clone与arraycopy)代码详解

    JAVA数组的复制是引用传递,而并不是其他语言的值传递. 1.clone protectedObjectclone() throwsCloneNotSupportedException创建并返回此对象的一个副本."副本"的准确含义可能依赖于对象的类.这样做的目的是,对于任何对象x,表达式: x.clone()!=x为true,表达式: x.clone().getClass()==x.getClass()也为true,但这些并非必须要满足的要求.一般情况下: x.clone().equa

  • java异常继承何类,运行时异常与一般异常的区别(详解)

    一.基本概念 Throwable是所有异常的根,java.lang.Throwable Error是错误,java.lang.Error Exception是异常,java.lang.Exception Throwable: 有两个重要的子类:Exception(异常)和 Error(错误),二者都是 Java 异常处理的重要子类,各自都包含大量子类. Error(错误):是程序无法处理的错误,表示运行应用程序中较严重问题.大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java

  • Java多线程之线程通信生产者消费者模式及等待唤醒机制代码详解

    前言 前面的例子都是多个线程在做相同的操作,比如4个线程都对共享数据做tickets–操作.大多情况下,程序中需要不同的线程做不同的事,比如一个线程对共享变量做tickets++操作,另一个线程对共享变量做tickets–操作,这就是大名鼎鼎的生产者和消费者模式. 正文 一,生产者-消费者模式也是多线程 生产者和消费者模式也是多线程的范例.所以其编程需要遵循多线程的规矩. 首先,既然是多线程,就必然要使用同步.上回说到,synchronized关键字在修饰函数的时候,使用的是"this"

  • C语言变长数组 struct中char data[0]的用法详解

    今天在看一段代码时出现了用结构体实现变长数组的写法,一开始因为忘记了这种技术,所以老觉得作者的源码有误,最后经过我深思之后,终于想起以前看过的用struct实现变长数组的技术.下面是我在网上找到的一篇讲解很清楚的文章. 在实际的编程中,我们经常需要使用变长数组,但是C语言并不支持变长的数组.此时,我们可以使用结构体的方法实现C语言变长数组. struct MyData { int nLen; char data[0];}; 在结构中,data是一个数组名:但该数组没有元素:该数组的真实地址紧随结

  • Java编程复用类代码详解

    本文研究的主要是Java编程中的复用类,那么到底复用类是什么东西,又有什么用法,下面具体介绍. 看了老罗罗升阳的专访,情不自禁地佩服,很年轻,我之前以为和罗永浩一个级别的年龄,也是见过的不是初高中编程的一位大牛之一,专访之后,发现老罗也是一步一个脚印的人.别说什么难做,做不了,你根本就没去尝试,也没有去坚持. If you can't fly then run,if you can't run then walk, if you can't walk then crawl,but whateve

  • java获取登录者IP和登录时间的两种实现代码详解

    第一种直接用java自带的InetAddress类: import java.net.InetAddress; import java.text.SimpleDateFormat; import java.util.Date; public class test{ public static void main(String[] args) throws Exception{ InetAddress addr = InetAddress.getLocalHost(); String ip=add

  • Java中Spring Boot+Socket实现与html页面的长连接实例详解

    Spring Boot+Socket实现与html页面的长连接,客户端给服务器端发消息,服务器给客户端轮询发送消息,附案例源码 功能介绍 客户端给所有在线用户发送消息客户端给指定在线用户发送消息服务器给客户端发送消息(轮询方式) 注意:socket只是实现一些简单的功能,具体的还需根据自身情况,代码稍微改造下 项目搭建 项目结构图 pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xml

  • Javascript 模拟mvc实现点餐程序案例详解

    MVC模式是一个比较成熟的开发模式.M是指业务模型,V是指用户界面,C则是控制器,使用MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式.其中,View的定义比较清晰,就是用户界面.今天就来模拟使用MVC模式开发一个点餐程序,当然,只是就此案例来说明MVC在前端的实现参考,并没有完整的实现.程序很简单,与传统的MVC三层架构不谋而合. 首先,先介绍一下场景:顾客进到餐馆,拿着菜单点餐,服务员记录并发到后端厨房,厨师接到订单,按照订单的菜品去制作,制作完毕通知服务员取餐,

  • Go语言实现二维数组的2种遍历方式以及案例详解

    二维数组遍历的2种方式: package main import ( "fmt" ) func main() { //定义一个二维数组 var arr = [2][3]int{{1, 4, 3},{7, 5, 6}} //方式1. 用for循环来遍历 for i := 0; i < len(arr); i++ { for j := 0; j < len(arr[i]); j++ { fmt.Printf("%v ",arr[i][j]) } fmt.Pr

随机推荐