使用数组模拟队列

队列的介绍

  • 队列是一个有序列表,可以用数组或是链表来实现。
  • 遵循先入先出的原则。即:先存入队列的数据,要先取出。后存入的要后取出
  • 示意图:(使用数组模拟队列示意图)
    在这里插入图片描述

数组模拟队列思路

  • 队列本身是有序列表,若使用数组的结构来存储队列的数据,则队列数组的声明如下图, 其中 maxSize 是该队 列的最大容量。
  • 因为队列的输出、输入是分别从前后端来处理,因此需要两个变量 front 及 rear 分别记录队列前后端的下标, front会随着数据输出而改变,而 rear 则是随着数据输入而改变,如图所示:
    在这里插入图片描述
  • 当我们将数据存入队列时称为”addQueue”,addQueue 的处理需要有两个步骤:思路分析 :
  •  1) 将尾指针往后移:rear+1 ,当 front == rear 【空】 
    
  •  2) 若尾指针 rear 小于队列的最大下标 maxSize-1,则将数据存入 rear所指的数组元素中,否则无法存入数据。 rear == maxSize - 1[队列满]
    

编码实现(使用数组模拟队列)

package com.zlx.queue;

import java.util.Scanner;

/**
 * @ClassName ArrayQueue
 * @Description TODO
 * @Author zhalongxi
 * @Date 2021/5/9 19:23
 * @Version 1.0
 **/
public class ArrayQueueDemo {
    public static void main(String[] args) {
        ArrayQueue arrayQueue = new ArrayQueue(3);//创建出一个队列
        char key = ' ';//接收用户输入的数据
        Scanner scanner = new Scanner(System.in); //控制台输入数据
        //在while循环中进行队列的操作
        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':
                    try {
                        arrayQueue.showArrQueue(); //打印出队列中的所有的数据
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'a':
                    System.out.println("请输入需要往队列中添加的元素:");
                    int value = scanner.nextInt(); //接收控制台输入的一个整形数据
                    arrayQueue.addQueue(value);
                    break;
                case 'g':
                    try {
                        arrayQueue.getQueue();//从队列中取出一个元素
                    } catch (Exception e) {
                        //处理从队列中取元素时的空队列跑出的异常
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'h':
                    try {
                        arrayQueue.getHeadQueue();//取出队列中的头元素
                    } catch (Exception e) {
                        //处理从队列中取元素时的空队列跑出的异常
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'e':
                    scanner.close();//关闭控制台
                    loop = false;//结束循环
                    break;
            }
        }
        System.out.println("程序退出");
    }
}

class ArrayQueue{

    private int maxSize;//队列的最大的容量
    private int front;//队列头部
    private int rear;//队列尾部
    private int[] arr;//模拟队列的数组

    //1 使用构造器构造出一个队列
    /** @Description //TODO
     *  @Author zhalongxi
     *  @Date 19:24 2021/5/9
     *  @Param maxSize:队列的最大的容量
     *  @return
     **/
    public ArrayQueue(int arrMaxSize){
        maxSize = arrMaxSize;  //队列的最大的容量
        arr = new int[maxSize]; //创建出一个队列
        front = -1;//队列的头指向队列的第一个元素的前一个位置
        rear = -1;//队列的尾部指向队列的第一个元素的前一个位置
    }

    /** @Description 判断队列是否已满
     *  @Author zhalongxi
     *  @Date 19:33 2021/5/9
     *  @Param
     *  @return
     **/
    public boolean isFull(){
        return rear == maxSize - 1;
    }

    /** @Description 判断队列是否为空
     *  @Author zhalongxi
     *  @Date 19:34 2021/5/9
     *  @Param
     *  @return
     **/
    public boolean isEmpty(){
        return rear == front;
    }

    /** @Description 往队列中添加数据
     *  @Author zhalongxi
     *  @Date 19:35 2021/5/9
     *  @Param
     *  @return
     **/
    public void addQueue(int n){
        //判断队列是否已满
        if(isFull()){
            System.out.println("队列已满,请勿添加数据...");
            return ;
        }
        rear ++;
        arr[rear] = n;
    }

    /** @Description 从队列中取出一个元素
     *  @Author zhalongxi
     *  @Date 19:39 2021/5/9
     *  @Param
     *  @return
     **/
    public int getQueue(){
        //判断队列是否为空
        if(isEmpty()){
            //为空则抛出异常
            throw new RuntimeException("队列为空,无法从队列中获取到数据...");
        }
        front ++; //将队列的头部向前移动一位
        System.out.println("从队列中取出的元素:"+arr[front]);
        return arr[front];
    }

    /** @Description 打印出队列中的所有的元素
     *  @Author zhalongxi
     *  @Date 19:44 2021/5/9
     *  @Param
     *  @return
     **/
    public void showArrQueue(){
        if(isEmpty()){
            System.out.println("队列是空的...");
            return;
        }
        for (int i = 0; i < arr.length; i++) {
            System.out.printf("arr[%d]=%d\n",i,arr[i]);
        }
    }

    /** @Description 取出队列的头部元素
     *  @Author zhalongxi
     *  @Date 19:45 2021/5/9
     *  @Param
     *  @return
     **/
    public int getHeadQueue(){
        if(isEmpty()){
            throw new RuntimeException("队列为空...");
        }
//        front ++;
        System.out.println("从队列中取出的头元素:"+arr[front]);
        return arr[front + 1];
    }
}

注意:这个队列有一个问题:就是一次性的队列,用完就没了。。所以需要将队列进行如下的改进:将这个数组使用算法,改进成一个环形的队列 取模:%,达到复用的效果。

数组模拟环形队列

对前面的数组模拟队列的优化,充分利用数组. 因此将数组看做是一个环形的。(通过取模的方式来实现即可)

  1. 尾索引的下一个为头索引时表示队列满,即将队列容量空出一个作为约定,这个在做判断队列满的 时候需要注意 (rear + 1) % maxSize == front 满]
  2. rear == front [空]
  3. 分析示意图
    在这里插入图片描述

编码实现

package com.zlx.queue;

import java.util.Scanner;

/**
 * @ClassName CircleArrayQueueDemo
 * @Description TODO
 * @Author zhalongxi
 * @Date 2021/5/9 22:45
 * @Version 1.0
 **/
public class CircleArrayQueueDemo {

    public static void main(String[] args) {
        //注意,此环形队列的有效数据实际上只有3,因为预留了一位用作约定
        CircleArrayQueue circleArrayQueue = new CircleArrayQueue(4);//创建出一个队列
        char key = ' ';//接收用户输入的数据
        Scanner scanner = new Scanner(System.in);//控制台输入数据
        //在while循环中进行队列的操作
        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':
                    try {
                        circleArrayQueue.showQueue(); //打印出队列中的所有的数据
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'a':
                    System.out.println("请输入需要往队列中添加的元素:");
                    int value = scanner.nextInt(); //接收控制台输入的一个整形数据
                    circleArrayQueue.addQueue(value);
                    break;
                case 'g':
                    try {
                        circleArrayQueue.getQueue();//从队列中取出一个元素
                    } catch (Exception e) {
                        //处理从队列中取元素时的空队列跑出的异常
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'h':
                    try {
                        circleArrayQueue.getHeadQueue();//取出队列中的头元素
                    } catch (Exception e) {
                        //处理从队列中取元素时的空队列跑出的异常
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'e':
                    scanner.close();//关闭控制台
                    loop = false;//结束循环
                    break;
                default:
                    System.out.println("请输入上面提示的字母!");
                    break;
            }
        }
        System.out.println("程序退出");
    }
}

class CircleArrayQueue{
    private int maxSize; //队列的容量
    //front 变量的含义做一个调整: front 就指向队列的第一个元素, 也就是说 arr[front] 就是队列的第一个元素
    //front 的初始值 = 0
    private int front;   //指向队列的头指针(队列的第一个元素)
    //rear 变量的含义做一个调整:rear 指向队列的最后一个元素的后一个位置. 因为希望空出一个空间做为约定.
    // rear 的初始值 = 0
    private int rear;    //指向队列的最后一个元素的后一个位置
    private int[] arr;   //用于模拟队列存储数据

    /** @Description 初始化队列
     *  @Author zhalongxi
     *  @Date 22:50 2021/5/9
     *  @Param
     *  @return
     **/
    public CircleArrayQueue(int circleArrayMaxSize){
        maxSize = circleArrayMaxSize;
        arr = new int[maxSize];
        //这两行代码可以不写,因为默认值为0
        front = 0;
        rear = 0;
    }

    /** @Description 判断队列是否已满,因为是环形队列,所以考虑取模
     *  @Author zhalongxi
     *  @Date 22:51 2021/5/9
     *  @Param
     *  @return
     **/
    public boolean isFull(){
        return (rear + 1) % maxSize == front;
    }

    /** @Description 判断队列是否为空
     *  @Author zhalongxi
     *  @Date 22:52 2021/5/9
     *  @Param
     *  @return
     **/
    public boolean isEmpty(){
        return rear == front;
    }

    /** @Description 往数组中添加元素
     *  @Author zhalongxi
     *  @Date 22:55 2021/5/9
     *  @Param int n添加的值
     *  @return
     **/
    public void addQueue(int n){
        if(isFull()){
            System.out.println("队列已满,请勿再添加...");
            return;
        }
        //因为这个rear指正指向队列的后一个元素,所以不需要rear+1
        arr[rear] = n;
        //将rear后移,必须考虑到取模,否则会数组越界异常(因为是环形队列)
        rear = (rear + 1) % maxSize;
    }

    /** @Description 取出队列中的值
     *  @Author zhalongxi
     *  @Date 22:58 2021/5/9
     *  @Param
     *  @return
     **/
    public int getQueue(){
        if(isEmpty()){
            throw new RuntimeException("队列为空,无法取出元素...");
        }
        //1、先将front对应的值保留到一个临时变量中
        int value = arr[front];
        //2、将front后移,考虑取模,否则出现数组越界异常
        front = (front + 1) % maxSize;
        //3、将保存的临时变量进行返回
        return value;
    }

    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,arr[i%maxSize]);
        }
    }

    /** @Description 显示队列的头元素
     *  @Author zhalongxi
     *  @Date 23:03 2021/5/9
     *  @Param
     *  @return
     **/
    public int getHeadQueue(){
        System.out.println("队列的头元素为:"+arr[front]);
        return arr[front];
    }

    /** @Description 计算队列中有效数据的个数
     *  @Author zhalongxi
     *  @Date 23:01 2021/5/9
     *  @Param
     *  @return
     **/
    public int size(){
        return (rear + maxSize -front) % maxSize;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值