Java数组实现循环队列(Java算法和数据结构总结笔记)[4/20]

什么是循环队列

队列是一种特殊的线性表,循环队列是将向量空间想象为一个首尾相接的圆环。

1、队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。

2、循环队列是将向量空间想象为一个首尾相接的圆环,并称这种向量为循环向量。存储在其中的队列称为循环队列。 在顺序队列中,当队尾指针已经到数组的上界,不能再有入队操作,但其实数组中还有空位置,这就叫做“假溢出”,解决假溢出的途径----采用循环队列。

实现一个循环队列要注意的点

  1. 队空时,头尾指针应该相等
  2. 队满时,头指针应该正好在尾指针后一位
  3. 入队时,尾指针加一
  4. 出队时,头指针加一
  5. 对数组长度取模是因为是循环队列,并防止溢出

代码实现

/**
 * 循环队列
 */
public class CircularQueue {
    // 声明数组
    int[] array;
    // 元素的个数
    int elementSize;
    // 头指针
    int front;
    // 尾指针
    int tail;
    // [0,1,2,3,4,5] 元素加一,用于循环队列,判断数组是否已经满了
    public CircularQueue(int c){
        array = new int[c + 1];
        elementSize = 0;
        front = 0;
        tail = 0;
    }
    // 给队列一个初始的长度
    public CircularQueue(){
        this(5);
    }

    // 获取数组中的元素,把原来加的一再减去
    public int getSizeEle(){
        return array.length - 1;
    }

    // 当头指针的下标索引等于尾指针的下标索引时,队列为空
    public boolean isEmpty(){
        return front == tail;
    }

    // 获取元素的个数
    public int getSize(){
        return elementSize;
    }

    /**
     * 添加元素
     * @param e
     */
    public void pushElement(int e){
        // 考虑数组为空和队列已经满的情况,这里浪费一个元素空位,判断数组是否扩容
        /**
         * 示例:
         * 往数组添加元素:
         *    [1,2,3,4,5,6,7]
         * 取出一个元素来:
         *    [0,2,3,4,5,6,7]  那当前的tail的下标索引就应该是0,没有元素,
         *    而front因为取出了一个元素,那下标指针就指向了1,然后tail+1取模,触发扩容机制
         *    而,实际上现在0的索引位置是没有值的
         */
        if ((tail+1) % array.length == front){
            resize(getSizeEle() * 2);
        }
        // 添加元素
        array[tail] = e;
        // 循环队列,防止下标越界
        tail = (tail + 1) % array.length;
        elementSize ++;
    }

    /**
     * 取出元素
     * @return
     */
    public int popElement(){
        if (isEmpty()){
            throw new RuntimeException("队列为空!");
        }
        // 用于返回
        int value= array[front];
        // 取出值,默认为0
        array[front] = 0;
        // 下标向后移动一位
        front = (front + 1) % array.length;
        elementSize --;
        // 如果开辟的空间大,元素比较少,就进行缩容
        if (elementSize == getSizeEle() / 4 && getSizeEle() / 2 != 0){
            resize(getSizeEle() / 2);
        }
        return value;
    }

    /**
     * 扩容机制
     * @param cap
     */
    private void resize(int cap) {
        int[] newData = new int[cap];
        for (int i = 0; i < elementSize; i++) {
            /**
             * 由于是循环队列,所以新数组和本来数组的下标是不对应的
             * 例如:
             *    array   : [0,0,0,3,4,5,6,7]
             *    newDate : [0+front,1+front,2+front,...]
             */
            newData[i] = array[(i+front) % array.length];
        }
        // 把新数组重新指回
        array = newData;
        front = 0;
        tail = elementSize;
    }


    public static void main(String[] args) {

        CircularQueue queue = new CircularQueue();

        for(int i = 0 ; i < 15 ; i ++){
            // 添加元素,不够扩容
            queue.pushElement(i+1);
            // 每三个元素,出栈一次
            if(i % 3 == 2){
                int i1 = queue.popElement();
                System.out.println(i1);
            }
        }
    }

}

LeetCode版循环队列实现

public class TestCode {

    int[] data;
    int size;
    int front;
    int tail;

    public TestCode(int k){
        data = new int[k + 1];
        size = 0;
        front = 0;
        tail = 0;
    }
    public int Front(){
        if (isEmpty()){
            return -1;
        }
        return data[front];
    }
    public int Rear(){
        if (isEmpty()){
            return -1;
        }
        if (tail == 0 && getSize() != 0){
            return data[getSize()];
        }
        int tailIndex = (tail - 1) % data.length;
        return data[tailIndex];
    }
    public boolean isEmpty(){
        return size == 0;
    }

    public int getSize(){
        return data.length - 1;
    }

    public boolean isFull(){
        if (getSize() == size){
            return true;
        }
        return false;
    }

    public boolean enQueue(int value){
        if (isFull()){
            return false;
        }
        data[tail] = value;
        tail = (tail + 1) % data.length;
        size ++;
        return true;
    }

    public boolean deQueue(){
        if (isEmpty()){
            return false;
        }
        front = (front + 1) % data.length;
        size --;
        return true;
    }


    public static void main(String[] args) {

//        ["TestCode","enQueue","enQueue","enQueue","enQueue","Rear","isFull","deQueue","enQueue","Rear"]
//        [[3],[1],[2],[3],[4],[],[],[],[4],[]]
//        输出
//                [null,true,true,true,false,3,true,true,true,4]
//        预期结果
//                [null,true,true,true,false,3,true,true,true,4]
        
        TestCode obj = new TestCode(3);
        for (int i = 0; i < 1; i++) {
            boolean param_1 = obj.enQueue(1);
            boolean param_2 = obj.enQueue(2);
            boolean param_3 = obj.enQueue(3);
            boolean param_4 = obj.enQueue(4);
            int param_5 = obj.Rear();
            boolean param_6 = obj.isFull();
            boolean param_7 = obj.deQueue();
            boolean param_8 = obj.enQueue(4);
            int param_9 = obj.Rear();
            int param_10 = obj.Front();

            System.out.println(param_1);
            System.out.println(param_2);
            System.out.println(param_3);
            System.out.println(param_4);
            System.out.println(param_5);
            System.out.println(param_6);
            System.out.println(param_7);
            System.out.println(param_8);
            System.out.println(param_9);
            System.out.println(param_10);
        }

    }

}

猜你喜欢

转载自blog.csdn.net/amosjob/article/details/117519187