在上一章中,使用了数组模拟了队列。但是留下的问题是,把数据取完后,再往里加数据就不行了。

一、假溢出

这是因为数组的末尾已经被占用了,入队会继续在数组后面增加,于是产生数组越界。但是实际上,数组里是有空闲位置的,这种也可以叫“假溢出”。

为了解决“假溢出”的问题,于是乎有了循环队列。

既然数组后面满了,头部有空,那继续加进来的元素从头开始放即可。

接着上图,这时候有a6入队,于是rear的下标指向a6的下一个元素位置,看起来没什么问题。

但是继续有新的元素a7入队的时候,因为front一直没变,这时候rear指针跟front就重合了,也就是说此时front=rear

可是在上一章的代码里,我们是用front=rear来判断是否为空数组的。

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

现在是相等了,条件满足,但是数组是满的。

二、循环队列判断是空是满

这种情况看起来确实比较辣手,那如果不让这种情况出现不就可以了么?

假设,我们让数组始终保留一个元素空间,也就是让rear指向队列中最后一个元素的后一个位置。比如,当a6放入之后,此时就当做队列已经满了,这样的话就不会出现上述的情况了。

为了实现这种思路,front也需要做调整。在上一章中,front初始位置是指在了队头元素的前一个,现在我们让它就指在第一个元素。

队列的最大尺寸还是maxSize,那么,现在判断队列满的条件就可以是这样:

(rear 1)%maxSize = front

验证一下,下面的2种队列满情况:

左图:队列中,maxSize=5,front=0,rear=4,判断(4 1)% 5=0=front,队列已满

右图:队列中,maxSize=5,front=2,rear=1,判断(1 1)% 5=2=front,队列已满

继续验证一下,队列没满的情况:

队列中,maxSize=5,front=2,rear=0,判断(0 1)% 5=1≠front,队列未满

三、循环队列的长度计算

队列的长度,也就是说队列中实际存了多少个元素。

此时需要考虑rear与front之间的三种情况:

  • rear=front
  • rear>front
  • rear<front

第一种自然都清楚,队列为空。

第二种,rear>front,此时队列的长度为:rear-front

第三种,rear<front,比较复杂些。队列长度分为2段:一段是maxSize-front,另一段则是:0 rear(结合右图理解)。故此时队列总长度为两段相加:rear-front maxSize

所以队列长度的通用计算公式为:

(rear-front maxSize)% maxSize

四、代码实现

既然现在队列是满是空的判断条件有了,队列长度也能计算出来了,那么代码就好改造了(基于上一章),变成循环队列。

package circle;
import java.util.Scanner;
public class CircleArrayQueue {
    public static void main(String[] args) {
        System.out.println("-----测试循环队列-----");
        // 创建一个队列
        CircleArray circleArray = new CircleArray(4);
        char key = ' '; //接受用户输入
        Scanner scanner = new Scanner(System.in);
        boolean loop = true;
        // 输出一个菜单
        while (loop) {
            System.out.println("s(show): 显示队列");
            System.out.println("e(exit): 退出程序");
            System.out.println("a(add): 添加数据到队列");
            System.out.println("g(get): 从队列取出数据");
            System.out.println("h(head): 显示队首的数据");
            key = scanner.next().charAt(0); // 接收一个字符
            switch (key) {
                case 's':
                    circleArray.showQueue();
                    break;
                case 'a':
                    System.out.println("请要添加的数");
                    int value = scanner.nextInt();
                    circleArray.addQueue(value);
                    break;
                case 'g':
                    try {
                        int res = circleArray.getQueue();
                        System.out.printf("取出的数据是:%d", res);
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'h':
                    try {
                        int headValue = circleArray.showHeadQueue();
                        System.out.printf("队首数据是:%d", headValue);
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'e':
                    scanner.close();
                    loop = false;
                    break;
            }
        }
        System.out.println("退出程序");
    }
}
class CircleArray {
    //表示数组最大容量
    private int maxSize;
    // 队列头,由之前调整为指向队列第一个元素
    private int front;
    // 队列尾,由之前调整为指向队列最后一个元素的后一个位置,为了空出一个元素位置
    private int rear;
    // 用于存放数据的数组
    private int[] arr;
    // 构造器
    public CircleArray(int arrMaxSize) {
        maxSize = arrMaxSize;
        arr = new int[maxSize];
        front = 0;
        rear = 0;
    }
    // 判断队列是否已经存满
    public boolean isFull() {
        return (rear   1) % maxSize == front;
    }
    // 判断队列是否为空
    public boolean isEmpty() {
        return rear == front;
    }
    // 添加数据到队列
    public void addQueue(int num) {
        // 判断队列是否满了
        if (isFull()) {
            System.out.println("队列已满,不可加入数据");
            return;
        }
        arr[rear] = num;
        // 将rear后移,要考虑取模
        rear = (rear   1) % maxSize;
    }
    // 拿出队列数据
    public int getQueue() {
        // 判断队列是否空
        if (isEmpty()) {
            // 抛出异常
            throw new RuntimeException("队列为空,不可取数据");
        }
        int tempValue = arr[front];
        front = (front   1) % maxSize; //也要考虑取模,防止front不停的增加,导致越界
        return tempValue;
    }
    // 显示队列所有数据
    public void showQueue() {
        // 遍历
        if (isEmpty()) {
            System.out.println("队列为空");
            return;
        }
        // 从front开始遍历,遍历多少个实际存的元素即可
        for (int i = front; i < front   CircleQueueSize(); i  ) {
            System.out.printf("arr[%d]=%d\n", i % maxSize, arr[i % maxSize]);
        }
    }
    // 求出当前队列有效数据的个数
    public int CircleQueueSize() {
        return (rear - front   maxSize) % maxSize;
    }
    // 显示队里的队首数据
    public int showHeadQueue() {
        if (isEmpty()) {
            // 抛出异常
            throw new RuntimeException("队列为空,不可取数据");
        }
        return arr[front];
    }
}

重点的改动在于取模。

以上就是java数据结构循环队列的空满判断及长度计算的详细内容,更多关于java循环队列空满判断长度计算的资料请关注Devmax其它相关文章!

java数据结构循环队列的空满判断及长度计算的更多相关文章

  1. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  2. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  3. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  4. Java实现世界上最快的排序算法Timsort的示例代码

    Timsort 是一个混合、稳定的排序算法,简单来说就是归并排序和二分插入排序算法的混合体,号称世界上最好的排序算法。本文将详解Timsort算法是定义与实现,需要的可以参考一下

  5. Java日期工具类的封装详解

    在日常的开发中,我们难免会对日期格式化,对日期进行计算,对日期进行校验,为了避免重复写这些琐碎的逻辑,我这里封装了一个日期工具类,方便以后使用,直接复制代码到项目中即可使用,需要的可以参考一下

  6. Java设计模式之模板方法模式Template Method Pattern详解

    在我们实际开发中,如果一个方法极其复杂时,如果我们将所有的逻辑写在一个方法中,那维护起来就很困难,要替换某些步骤时都要重新写,这样代码的扩展性就很差,当遇到这种情况就要考虑今天的主角——模板方法模式

  7. Java 中 Class Path 和 Package的使用详解

    这篇文章主要介绍了Java 中 Class Path和Package的使用详解,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的朋友可以参考一下

  8. java SpringBoot 分布式事务的解决方案(JTA+Atomic+多数据源)

    这篇文章主要介绍了java SpringBoot 分布式事务的解决方案(JTA+Atomic+多数据源),文章围绕主题展开详细的内容介绍,具有一定的参考价值,感兴趣的小伙伴可以参考一下

  9. Java一维数组和二维数组元素默认初始化值的判断方式

    这篇文章主要介绍了Java一维数组和二维数组元素默认初始化值的判断方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  10. java实现emqx设备上下线监听详解

    这篇文章主要为大家介绍了java实现emqx设备上下线监听详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部