Java 循环队列/环形队列的实现流程

 更新时间:2022年02月14日 15:12:59   作者:Word码鸭  
循环队列又叫环形队列,是一种特殊的队列。循环队列解决了队列出队时需要将所有数据前移一位的问题。本文将带大家详细了解循环队列如何实现,需要的朋友可以参考一下

之前,我们使用链表实现了基础队列,链接放在这里可以去康康哟

Java栈和基础队列的实现详解

之所以没有选择数组来实现,是因为每有一个元素出队,数组中所有剩下的元素都需要向前移动一次,因此没有链表高效。

此时,我们就引出了循环队列的概念。

循环队列,又称环形队列,逻辑上是一个环,物理上依然是线性表。

head-指向队列的第一个元素

tail-指向队列最后一个元素的下一个位置

当tail走到数组末尾时,下一步再次返回数组头部(从0开始)

出队之后的元素就访问不到了,此时逻辑上已经将它删除了,tail向后走到该位置时覆盖它即可。此时就解决了数组队列需要一直搬运元素的问题。

了解循环队列的概念之后,我们就能明白它的几个基础知识:

当head == tail 时,表示队列为空

根据上面 head 和 tail 的定义,队列已满时,tail 指向最后一个元素的下一个位置,也就是head ,此时我们就无法区分环形队列到底是已满还是为空。所以我们在环形队列的数组中浪费一个空间,在区分数组是否已满,如下图,就是一个已满的队列

那么如何移动 tail 指针使他返回数组头部呢?我们运用取模操作:

tail = ( tail + 1 ) % 数组.length; 

根据上式我们就能判断队列是否已满的方法:

( tail + 1 ) % 数组.length == head; 

此时 head 和 tail 引用向后移动时,不能简单的 +1,要 ++ 之后对数组长度取模,这样就可以返回数组头部继续向后移动:

 head = ( head +1 ) % 数组.length;

tail = ( tail +1 ) % 数组.length;

那么如何获取当前队列最后一个元素的索引呢?

图①中最后一个元素的索引就是 tail -1

图②的tail恰好在数组第一个位置,这时最后一个元素下标就是 数组.length -1

综上:数组最后一个元素的索引lastIndex

lastIndex = tail == 0 ? 数组.length -1 : tail -1;

代码实现:

public interface Queue<E> {
    void offer(E val);//入队
    E poll();//出队,返回出队的值
    E peek();//返回队首元素
    boolean isEmpty();//判断是否为空
}
 
 
import java.util.NoSuchElementException;
 
//基于整型的循环队列
public class LoopQueue implements Queue<Integer>{
    private Integer[] data;
    private int head;//队首元素
    private int tail;//队尾元素的下一个位置
    private int size;//当前元素个数
    public LoopQueue(int n){
        //n为希望保存的元素个数
        //在循环队列中要浪费一个元素空间,来判断是否已满,所以 +1
        data = new Integer[n + 1];
        }
 
    @Override
    //添加元素
    public void offer(Integer val) {
        if(isFull()){
            throw new ArrayIndexOutOfBoundsException("queue is full, cannot offer new val");
        }
        data[tail] = val;
        //tail向后移
        tail = (tail + 1) % data.length;
        size++;
    }
 
    @Override
    //出队
    public Integer poll() {
        if (isEmpty()){
            throw new NoSuchElementException("queues empty!cannot poll");
        }
        Integer val = data[head];
        //head向后移动
        head = (head + 1) % data.length;
        size--;
        return val;
    }
 
    @Override
    public Integer peek() {
        if (isEmpty()){
            throw new NoSuchElementException("queues empty!cannot poll");
        }
        return data[head];
    }
 
    @Override
    //判断是否为空
    public boolean isEmpty() {
        return tail == head;
    }
    public String toString(){
        StringBuilder sb = new StringBuilder();
        sb.append("front[");
        //取得最后一个元素的下标
        int lastIndex = tail == 0 ? data.length-1 : tail-1;
        for (int i = head; i != tail; ) {
            sb.append(data[i]);
            if (i != lastIndex){
                sb.append(",");
            }
            i = (i+1) % data.length;
 
        }
        sb.append("]tail");
        return sb.toString();
    }
    //判断队列是否已满
    public boolean isFull(){
        return (tail + 1) % data.length == head;
    }
}
//代码测试
public class LoopQueueTest {
    public static void main(String[] args) {
        Queue<Integer> loopQueue = new LoopQueue(5);
        for (int i = 0; i < 5; i++) {
            loopQueue.offer(i+1);
        }
        System.out.println(loopQueue);
//        loopQueue.offer(1);
        System.out.println(loopQueue.poll());
        System.out.println(loopQueue);
    }
}

运行结果:

到此这篇关于Java 循环队列/环形队列的实现流程的文章就介绍到这了,更多相关Java 循环队列内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java Calendar类的时间操作

    Java Calendar类的时间操作

    这篇文章主要为大家详细介绍了Java Calendar类的时间操作,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-10-10
  • 微信小程序与Java后端接口交互

    微信小程序与Java后端接口交互

    本文主要介绍了微信小程序与Java后端接口交互,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07
  • try-with-resource优雅关闭io流的方法

    try-with-resource优雅关闭io流的方法

    这篇文章主要给大家介绍了关于try-with-resource优雅关闭io流的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • maven快速生成SpringBoot打包文件的方法步骤

    maven快速生成SpringBoot打包文件的方法步骤

    本文主要介绍了使用Maven快速生成SpringBoot项目打包文件的方法,包括如何生成可执行的JAR文件,如何将配置文件、运行脚本、调试脚本、证书文件等拷贝到指定目录,及如何编译出部署包,这种方法能大大方便微服务的部署,提高部署效率
    2024-10-10
  • Java多线程实例

    Java多线程实例

    本文给大家介绍java多线程实例,对java多线程知识感兴趣的朋友参考下吧
    2015-11-11
  • SpringMVC获取请求参数和域对象共享数据的示例代码

    SpringMVC获取请求参数和域对象共享数据的示例代码

    这篇文章主要给大家介绍了SpringMVC获取请求参数和域对象共享数据的示例代码,文中通过代码示例给大家介绍的非常详细,具有一定的参考价值,需要的朋友可以参考下
    2023-12-12
  • 解决java.sql.Timestamp丢失精度的问题

    解决java.sql.Timestamp丢失精度的问题

    这篇文章主要介绍了解决java.sql.Timestamp丢失精度的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • 如何将JSON字符串数组转对象集合

    如何将JSON字符串数组转对象集合

    这篇文章主要介绍了如何将JSON字符串数组转对象集合,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-06-06
  • 一篇文章带你详解Spring的概述

    一篇文章带你详解Spring的概述

    这篇文章主要为大家介绍了Spring的概述,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-01-01
  • SpringBoot Security从入门到实战示例教程

    SpringBoot Security从入门到实战示例教程

    Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架,接下来通过本文给大家介绍SpringBoot Security从入门到实战示例教程,感兴趣的朋友一起看看吧
    2022-05-05

最新评论