java数据结构与算法:单向队列与环形队列详解(图片+代码)

Posted 温文艾尔

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java数据结构与算法:单向队列与环形队列详解(图片+代码)相关的知识,希望对你有一定的参考价值。

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

一、队列介绍

  1. 队列是一个有序列表,可以用数组或是链表来实现
  2. 遵循先入先出的原则。即:先存入队列的数据,要先取出,后存入的要后取出。

二、单向队列数组模拟队列

  1. 队列本身是有序列表,若使用数组的结构来存储队列的数据,则队列数组的声明如下图,其中maxSize是该队列的最大容量
  2. 因为队列的输出,输入是分别从前后端来处理,因此需要两个变量front及rear分别记录队列前后端的下标,front会随着数据输出而改变,而rear则是随着数据输入而改变

1.单向队列模拟图


当我们将数据存入队列时称为“addQueue”,addQueue的处理需要有两个步骤

  1. 将尾指针向后移动:rear+1,当front == rear,则队列为空
  2. 若尾指针rear小于队列的最大下标maxSize-1,则将数据存入rear所指的数组元素中,当rear == maxSize-1时队列为满

注意

  1. front指向的是队列头的前一个位置
  2. rear指向的是队列最后一个数据

单项队列代码模拟

package org.wql.Queue;

/**
 * Description
 * User:
 * Date:
 * Time:
 */
public class QueueTest01 {

    public static void main(String[] args) {
        ArrayQueue arrayQueue = new ArrayQueue(3);
        arrayQueue.addData(1);
        arrayQueue.addData(2);
        arrayQueue.addData(3);
        arrayQueue.showData();
        int data = arrayQueue.getData();
        System.out.println("取出数据1");
        arrayQueue.showData();
        arrayQueue.addData(4);
        System.out.println("增加数据4");
        arrayQueue.showData();
        //展示头部
        int head = arrayQueue.gethead();
        System.out.println("头部数据是:"+head);
    }
}

class ArrayQueue{
    private int maxSize;
    private int rear;
    private int front;
    private int[] arr;

    //初始化队列
    public ArrayQueue(int MaxSize){
        maxSize=MaxSize;
        arr = new int[maxSize];
        rear=-1;
        front=-1;
    }

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

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

    //添加数据到队列
    public void addData(int data){
        //在队列未满的状态下才可添加数据
        if (!isFull()){
            arr[++rear]=data;
        }else {
            System.out.println("队列已满,不能加入数据");
            return;
        }
    }

    //从队列中取数据
    public int getData(){
        //在队列非空的状态下才可取得数据
        if(!isEmpty()){
            return arr[++front];
        }else {
            throw new RuntimeException("队列为空,不能取数据");
        }
    }

    //显示队列中的所有数据
    public void showData(){
        if(!isEmpty()){
            for(int i=front+1;i<rear+1;i++){
                System.out.println(arr[i]);
            }
        }else{
            System.out.println("队列没有数据");
        }
    }

    //显示队列的头数据(只是显示,并不取出)
    public int gethead(){
        if(isEmpty()) {
            throw new RuntimeException("队列为空,没有数据");
        }
        return arr[front+1];
    }
}


此时我们发现单项队列存在的缺陷,一旦队列满,则无法再添加数据,曾经数据占用的位置依然被占用,故需要使用环形队列

三、环形队列数组模拟队列

思路如下

  1. front变量的含义做一个调整:front就指向队列的第一个元素,而不是像单项队列一样指向第一个元素的前一个位置,arr[front]就是队列的第一个元素,front初始值为0
  2. rear变量的含义也做一个调整:rear指向队列的最后一个元素的后一个位置,这样可区分环形队列的队满与队空,rear的初始值为0
  3. 当队列满时,条件是(rear+1)%maxSize=front
  4. 队列为空的条件是rear==front
  5. 队列中有效的数据个数为(rear+maxSize-front)%maxSize

环形数列需要牺牲一个位置作为约定

我们可以通过画图来说明问题

设maxSize为4,当队列满时有此场景

front代表队列第一个元素的位置,front=0,rear代表最后一个元素的后一个位置,rear=3

故此时(rear+1)%maxSize=front,因为我们牺牲了一个位置作为约定,故队列中的数据有效个数为(3+4-0)%4=3

环形队列代码模拟

package org.wql.Queue;

/**
 * Description
 * User:
 * Date:
 * Time:
 */
public class CircleQueueTest02 {
    public static void main(String[] args) {
        CircleArrayQueue circleArrayQueue = new CircleArrayQueue(4);
        System.out.println("添加数据");
        circleArrayQueue.addData(1);
        circleArrayQueue.addData(2);
        circleArrayQueue.addData(3);
        circleArrayQueue.showData();
//        f=0,r=3
        int data = circleArrayQueue.getData();
        System.out.println("取出数据:"+data);
        circleArrayQueue.showData();
        //        f=1,r=3
        circleArrayQueue.addData(4);
        System.out.println("增加数据:4");
        //        f=1,r=0
        circleArrayQueue.showData();
        int head = circleArrayQueue.gethead();
        System.out.println("第一个元素为:"+head);
        int size = circleArrayQueue.getQueueSize();
        System.out.println("环形队列中的有效元素个数:"+size);
    }
}

class CircleArrayQueue{
    private int maxSize;
    private int rear;
    private int front;
    private int[] arr;

    //初始化队列
    public CircleArrayQueue(int MaxSize){
        maxSize=MaxSize;
        arr = new int[maxSize];
    }

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

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

    //添加数据到队列
    public void addData(int data){
        //在队列未满的状态下才可添加数据
        if (!isFull()){
            arr[rear]=data;
            rear=(rear+1)%maxSize;
        }else {
            System.out.println("队列已满,不能加入数据");
            return;
        }
    }

    //从队列中取数据
    public int getData(){
        //在队列非空的状态下才可取得数据
        if(!isEmpty()){
            front=(front+1)%maxSize;
            return arr[front-1];
        }else {
            throw new RuntimeException("队列为空,不能取数据");
        }
    }

    //显示队列中的所有数据
    public void showData(){
        if(!isEmpty()){
            for(int i=front;i<front+getQueueSize();i++){
                System.out.println(arr[i]);
            }
        }else{
            System.out.println("队列没有数据");
        }
    }

    //显示队列的头数据(只是显示,并不取出)
    public int gethead(){
        if(isEmpty()) {
            throw new RuntimeException("队列为空,没有数据");
        }
        return arr[front];
    }

    //显示当前队列中元素的有效个数
    public int getQueueSize(){
        return (rear+maxSize-front)%maxSize;
    }
}

以上是关于java数据结构与算法:单向队列与环形队列详解(图片+代码)的主要内容,如果未能解决你的问题,请参考以下文章

Java全数据结构与部分算法(看到就是赚到)

⭐算法入门⭐《队列 - 单调队列》中等03 —— LeetCode 918. 环形子数组的最大和

数据结构之数组模拟队列(单项队列和环形队列)

数据结构之数组模拟队列(单项队列和环形队列)

Java数据结构 -- 环形队列 & 数组模拟环形队列

使用数组模拟普通队列,环形队列,(Java数据结构之队列)