数组模拟队列的优化——数组模拟环形队列

举报
周小末天天开心 发表于 2022/11/19 17:54:29 2022/11/19
975 0 0
【摘要】 数组模拟环形队列

数组模拟环形队列

程序优化思路

(1)front 变量的含义进行一个调整:让 front 指向队列的第一个元素,也就是说 arr[front] 为队列的第一个元素,front 的初始值为0。

(2)rear 变量的含义做一个调整:让 rear 指向队列的最后一个元素的后一个位置,因为要空出一个空间来做约定,rear 的初始值为0.

(3)当队列为满时,条件为(rear + 1) % maxSize == front

        例如当 rear = 2 ,front = 0 时,maxSize - 1 = 2,maxSize = 3(因为下标从零开始),所以(2 + 1) % 3 == 0,所以队列已满。

(4)当队列为空时,条件为 rear == front

(5)分析完成后,该队列中有效数据的个数是 (rear + maxSize - front) % maxSize

        例如当 rear = 2,front =0,maxSize = 3时,(2 + 3 - 0) % 3 等于 2 ,说明该队列中有效数据的个数为两个。

(6)修改之前的队列,得到一个新的环形队列

使用数组模拟环形队列—编写一个CircleArrayQueue类

class CircleArrayQueue {
    private int maxSize;//队列的长度,也就是最多能存储多少个数据
    private int front;//队列头
    private int rear;//队列尾
    private int[] arr;//用于存放数据,模拟队列
 
    //创建队列的构造器
    public CircleArrayQueue(int arrMaxSize) {
        maxSize = arrMaxSize;
        arr = new int[maxSize];
        /*
            front 变量的含义进行一个调整:让 front 指向队列的第一个元素,
        也就是说 arr[front] 为队列的第一个元素,front 的初始值为0。
            rear 变量的含义做一个调整:让 rear 指向队列的最后一个元素的后一个位置,
        因为要空出一个空间来做约定,rear 的初始值为0.
         */
        //因为front 和 rear 默认为零,所以不用进行赋值
    }
 
    //判断队列是否满
    public boolean isFull() {
        return (rear + 1) % maxSize == front;
    }
 
    //判断队列是否为空
    public boolean isEmpty() {
        return rear == front;
    }
 
    //添加数据到队列
    public void addQueue(int n) {
        //判断队列是否为满
        if(isFull()) {
            System.out.println("队伍已满,无法加入队列");
            return;
        }
        arr[rear] = n;//添加数据到数组中
        //将 rear 后移一位,这里必须要考虑取模,因为rear很有可能会产生越界
        rear = (rear + 1) % maxSize;
    }
 
    //获取队列的数据,出队列
    public int getQueue() {
        //判断队列是否为空
        if(isEmpty()) {
            //如果为空就抛出异常
            throw new RuntimeException("队列为空,不可以读取数据");
            //return //不需要进行返回,因为抛出异常就已经等于进行了返回
        }
        /*
        这里需要分析出 front 是指向队列的第一个元素
        1.先把 front 对应的值保存到一个临时变量中
        (如果不把值保存到临时变量中,那么 front 就没有往后移的机会了)
        2.将 front 后移,并且考虑取模,因为front也有可能会产生越界
        3.将临时保存的变量返回
         */
        int value = arr[front];
        front = (front + 1) % maxSize;
        return value;
    }
 
    //显示队列
    public void showQueue() {
        //先判断是否为空,为空就停止
        if(isEmpty()) {
            System.out.println("队列为空,无法输出");
            return;
        }
        //若队列不为空则遍历数组输出
        //思考,从front开始遍历,遍历了多少个元素
        for (int i = front; i < front + number(); i++) {
            System.out.print(arr[i % maxSize] + "  ");
            //因为 i 在运行时可能会超过数组的大小,所以要进行模除
        }
    }
 
    //求出当前队列有效数据的个数
    public int number() {
        return (rear + maxSize - front) % maxSize;
    }
 
    //显示队列的头数据,注意不是读取数据
    public int headQueue() {
        //判断是否为空
        if(isEmpty()) {
            throw new RuntimeException("队列为空,无法输出");
        }
        return arr[front];
        //front 不需要 +1 是因为 front 本身就指向队列的第一个元素
    }
}

编写CircleArrayQueueDemo类进行调用方法演示

import java.util.Scanner;
public class CircleArrayQueueDemo {
    public static void main(String[] args) {
        //创建环形队列进行测试
        CircleArrayQueue circleArrayQueue = new CircleArrayQueue(5);
        //因为要空出一个空间来做约定,所以队列长度为5,但最多只能存入4个元素
        Scanner scanner = new Scanner(System.in);
        boolean loop = true;
        while(loop) {
            System.out.println("s(show):显示队列");
            System.out.println("a(add):添加数据到队列");
            System.out.println("g(get):从队列取出数据");
            System.out.println("h(head):查看队列头的数据");
            System.out.println("e(exit):退出程序");
            System.out.println("=====请输入要求=====");
            char key = scanner.next().charAt(0);//接收用户输入的一个字符
            switch(key) {
                case 's'://显示队列
                    circleArrayQueue.showQueue();
                    System.out.println();
                    break;
                case 'a'://添加数据到队列
                    System.out.println("请输入一个整数:");
                    int value = scanner.nextInt();
                    circleArrayQueue.addQueue(value);
                    break;
                case 'g'://取出数据
                    //取出数据时可能会遇到异常,因为有可能没有数据可以取出
                    //所以要使用异常处理机制try catch
                    try {
                        int res = circleArrayQueue.getQueue();
                        //如果getQueue()没有抛出异常,就会取出数据
                        System.out.println("取出的数据是:" + res);
                    } catch (Exception e) {
                        //如果getQueue()抛出异常,就会被catch抓住
                        //所以会在catch中输出异常信息
                        // TODO: handle exception
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'h'://查看队列头的数据
                    try {
                        int res = circleArrayQueue.headQueue();
                        System.out.println("队列头的数据是:" + res);
                    } catch (Exception e) {
                        // TODO: handle exception
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'e'://退出程序
                    scanner.close();//退出前先把scanner关闭,如不关闭可能会有异常
                    loop = false;//如果退出程序那么loop就为false,while循环就不会通过
                    break;
                default:
                    break;
            }
        }
        System.out.println("程序已退出");
    }
}



【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

作者其他文章

评论(0

抱歉,系统识别当前为高风险访问,暂不支持该操作

    全部回复

    上滑加载中

    设置昵称

    在此一键设置昵称,即可参与社区互动!

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。