数据结构_用数组实现环形队列

思路分析:

一、front就指向队列的第一个元素,也就是说,arr[front]就是队列的第一个元素

 

二、rear就是指向队列的最后一个元素的后一个位置,我们需要空出这个rear指向的空间(牺牲这个空间)

 

三、现在环形队列中,当队列满时,条件为:( rear + 1 ) % maxSize == front 

  原本非环队列满的条件是 rear = maxSize - 1 

  我的解释是:

 

所以实际上这个环形队列实际的存储数据的长度(从0开始到x)为 maxSize - 2 ,也就是 这个空间的大小-1 ,剩下的这个空间被牺牲掉了,用来做判断这个环形队列是不是满的!

当然,上面的图从1开始是不严谨的,应该从0开始,从1开始只是我画的时候方便=-=

 

四、当队列为空的时候,条件仍然是 rear = front 

 

五、队列中有效的数据的个数为( rear + maxSize - front ) % maxSize 

 

 

 这个公式的解释可以这样理解,首先rear加上maxSize也就是从数组的0位置开始到rear位置加上了容量大小,此时减去一个front就相当于数组中将这个占有数据的值往下推,推到从0位置到rear-front,

此时对maxSize取余就是相当于一个大于maxSize的数减去了一个maxSize所得到的余数,就是数组中有效存储的个数。

把这个公式这样写更好理解:

          (  rear - front + maxSize ) % maxSize 

          1、先不考虑这个环存取数据绕过一圈以上了,那么肯定有rear>front,那么rear-front就是存的有效个数

          2、如果这个环存取数据也就rear和front通过一系列位移不知道是rear大还是front大

          3、此时加上maxSize,就一定可以保证rear-front是一个正数,此时对maxSize取余可以得到有效个数了

          

 

 代码部分:

package queue;

import java.util.Scanner;

public class CircleArrayQueueDEMO {
    public static void main(String[] args) {
        System.out.println("测试——————————");
        System.out.println("创建一个环形队列");
        CircleArrayQueue queue = new CircleArrayQueue(3);

        char key = ' '; //接受用户输入的字符
        Scanner sc = 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 = sc.next().charAt(0); //接受输入的字符
            switch (key) {
                case 's':
                    queue.ShowData();
                    break;
                case 'a':
                    System.out.println("输入一个数");
                    int value = sc.nextInt();
                    queue.addQueue(value);
                    break;
                case 'g':
                    try {
                        int res = queue.getQueue();
                        System.out.println("数据是:" + res);
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'h':
                    try {
                        int res = queue.headData();
                        System.out.println("队列头数据是:" + res);
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'e':
                    sc.close();
                    loop = false;
                    break;
                default:
                    break;
            }
        }
        System.out.println("程序退出");

    }
}

class CircleArrayQueue {
    private int maxSize; //数组最大容量
    private int front; //队列的头 arr[front]就是队列的头元素
    private int rear; //指向队列最后一个元素的后一个位置(空间) arr[rear-1]就是队列的尾元素
    private int[] arr; //队列中存放的数据,模拟队列


    //队列的构造器
    public CircleArrayQueue(int arrMaxSize) {
        maxSize = arrMaxSize+1;  //加1是为了留给被牺牲的空间
        arr = new int[maxSize];
    }

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

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

    //添加数据到队列
    public void addQueue(int n) {
        //先判断是否为满
        if (isfull()) {
            System.out.println("队列满了,不能添加数据");
            return;
        }
        arr[rear] = n; //上面判断了队列还没满,
        rear++;// 那么rear指向的位置就是空的,再后移
    }

    //获取队列数据,取数据
    public int getQueue() {
        //判断队列是否为空
        if (isnull()) {
            //通过抛出异常
            throw new RuntimeException("队列空,不能取数据");
        }
        //front是指向队列的第一个元素
        //一、先把front对应的值保留到一个临时变量(如果直接返回的return后面的代码不会执行)
        //二、将front后移 注意:front可能移到 maxSize-1 去了
        //三、将临时保存的变量返回

        int value = arr[front];      //任何数取余 它的余数不会超过除数
        front = (front + 1) % maxSize; //取模是为了防止front越界,让到了maxSize-1就下去指向0
        return value;
    }

    //显示队列所有的数据
    public void ShowData() {
        if (isnull()) {
            System.out.println("队列为空");
        }
        //从front开始遍历,遍历队列中有效的数据个数,从front -> rear,但rear可能小于front,因此要考虑取模

        //队列中有效长度为queueLength
        int queueLength = (rear + maxSize - front) % maxSize;
        if (front < rear) { //front在rear下面
            for (int i = 0; i < queueLength; i++) {
                System.out.println("队列第" + (i + 1) + "个元素为:" + arr[front + i]);
            }
        } else { //front在rear上面,(front+i)可能会越界       "任何数取余,它的余数不会超过除数"
            for (int i = 0; i < queueLength; i++) {
                System.out.println("队列第" + (i + 1) + "个元素为:" + arr[(front + i) % maxSize]);
            }
        }

        //不用上面的if的话,可以用下面的偷懒写法:
//        for (int i = front; i < front+size(); i++) {
//            System.out.println("arr["+   (i % maxSize)   +"]="+   (arr[i%maxSize])   );
//        }
    }


    public int size() { //计算循环队列中存储的个数
        return (rear - front + maxSize) % maxSize;
    }

    //显示队列的头数据 不是取出
    public int headData() {
        if (isnull()) {
            throw new RuntimeException("队列是空的");
        }
        return arr[front];
    }

}

  

 

 

 

 

 

  

 

posted @ 2022-10-22 21:24  Lee最好好好吃饭  阅读(362)  评论(0)    收藏  举报