Java array implements circular queue (Java algorithm and data structure summary notes) [4/20]

What is a circular queue

A queue is a special linear list, and a circular queue imagines the vector space as a ring connected end to end.

1. The queue is a special linear table. The special thing is that it only allows deletion operations at the front end of the table (front), and insertion operations at the back end (rear) of the table. Like the stack, the queue is a kind of Operations on restricted linear tables.

2. The circular queue imagines the vector space as a ring connected end to end, and calls this vector a circular vector. The queue stored in it is called a circular queue. In a sequential queue, when the tail pointer has reached the upper bound of the array, no more enqueue operations can be performed, but in fact there are still empty positions in the array. This is called "false overflow". The way to solve false overflow is to use Circular queue.

Points to note when implementing a circular queue

  1. When the queue is empty, the head and tail pointers should be equal
  2. When the queue is full, the head pointer should be exactly one position behind the tail pointer.
  3. When joining the queue, the tail pointer is incremented by one.
  4. When leaving the queue, the head pointer increases by one
  5. Modulo the length of the array because it is a circular queue and prevents overflow

Code

/**
 * 循环队列
 */
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 version of circular queue implementation

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);
        }

    }

}

 

Guess you like

Origin blog.csdn.net/amosjob/article/details/117519187