"Fun advanced data structures from entry to" cycle queue array

This article comes from liuyubobobo of "Fun from entry to advanced data structures" video tutorials

A queue is a special linear form, is special in that it only allows deletion at the front end of the table, while the rear end of the insertion operation table. Referred to as the tail end of the end, delete operation will be referred to as head-of-insertion operation.

Suppose we use an array queue, see below

Enqueue operation very quickly, you only need to add elements in the tail. However, a team operating on a time-consuming, the head elements after the deletion and return to the caller, the need to put all the elements in the array to move forward, this step is very time-consuming.

After dequeue a, b, c, d to be moved to the lower position labeled 0,1,2

When there is a way to do a team, the array elements do not move it? There are drops, using a loop arrays

Circular queue has several features:

1, front variable points HOL (all elements), tail variable points to the tail (Elemental).

2, when the team moves back front a subscript ( "back" This statement is not entirely correct, then followed by a precise definition is given; speak later expansion)

3, while it was the added element in the tail, the tail is moved backward a subscript

4, front == tail indicates that the queue is empty, the queue is full, not the front, tail refer to the same elements, but in front of a front position of the tail.

The figure is a case where the queue is full, the length of the array 8, but only store queue element 7, so that an element to be empty, the tail pointing element.

It is to lower, if you must run out of memory arrays, then front == tail; queue is empty and also front == tail, on the code implementation to distinguish between when the queue is empty, the queue is full when it is complicated. Simply "waste" a memory element, front == tail queue is empty, this is only one case.

5, data.length definition array length (length in the array of FIG. 8), the queue is full when the judgment condition is  (+ tail. 1) == Front data.length% , we understand the determination shining FIG good condition.

6, the team, is movably tail tail = (tail + 1)% data.length

     Dequeue, front moves is front = (front + 1)% data.length

FIG example spend

Enqueue operation, tail = (1 + 1)% 8 = 2, tail into 2

Dequeue operation, front = (3 + 1)% 8 = 4, front becomes 4

7 when the front position, dequeue, fornt = (7 + 1)% 8 = 0, at this time point to the front position subscript 0

7, expansion, following FIG. Satisfies the condition (tail + 1)% data.length == front, capacity is needed at this time

Codes are as follows

// 基于循环数组实现队列
public class LoopQueue<E>{
    private E[] data;  // 数组
    private int front, tail;  //队头、队尾
    private int size;  //队列元素大小

    public LoopQueue(){
        data = (E[]) new Object[11];  //初始化队列的数组
        // 初始化时队头、队尾下标都为0,队列大小也是0
        front = 0;
        tail = 0;
        size = 0;
    }

    // 队列容量是数组长度减1,因为要空一个元素,以便区别队列是否为空、队列是否满了需要扩容
    public int getCapacity(){
        return data.length -1;
    }

    //队列为空
    public boolean isEmpty(){
        return front == tail;
    }

    //队列大小
    public int getSize(){
        return size;
    }

    //扩容、缩容
    private void resize(int newCapacity){
        // 数组长度要比容量多一个
        E[] newData = (E[])new Object[newCapacity+1];
        //将旧数据从队头开始,添加到新数组中
        for (int i=0; i<size; i++){
            newData[i] = data[(i+front) % data.length];
        }
        front = 0;  //添加完成,队头在新数组下标为0的位置
        tail = size;  //添加完成,队列大小就是队尾的下标
        data = newData;  //队列的数组data指向扩容后的数组
    }

    //入队
    public void enqueue(E e){
        //如果队列满了,则扩容
        if ((tail + 1) % data.length == front){
            resize(getCapacity() * 2);
        }
        data[tail] = e;
        //队尾下标移动
        tail = (tail + 1) % data.length;
        //队列大小加一
        size++;
    }

    //出队
    public E dequeue(){
        if (isEmpty())
            throw new RuntimeException("没数据了");
        //队头数据存储到变量中
        E ret = data[front];
        data[front] = null;
        //队头下标移动
        front = (front + 1) % data.length;
        //队列大小减一
        size--;

        //这是缩容,如果队列大小小于容量的1/4且容量的1/2不为0,队列缩容为原来的1/2
        if (size < getCapacity()/4 && getCapacity()/2 != 0){
            resize(getCapacity()/2);
        }
        //返回队头数据
        return ret;
    }



    @Override
    public String toString(){

        StringBuilder res = new StringBuilder();
        res.append(String.format("Queue: size = %d , capacity = %d\n", size, getCapacity()));
        res.append("front [");
        for(int i = front ; i != tail ; i = (i + 1) % data.length){
            res.append(data[i]);
            if((i + 1) % data.length != tail)
                res.append(", ");
        }
        res.append("] tail");
        return res.toString();
    }

    public static void main(String[] args){

        _2_LoopQueue.LoopQueue<Integer> queue = new _2_LoopQueue.LoopQueue<>();
        for(int i = 0 ; i < 20 ; i ++){
            queue.enqueue(i);
            System.out.println(queue);

            if(i % 10 == 0){
                queue.dequeue();
                System.out.println(queue);
            }
        }
        for(int i = 0 ; i < 18 ; i ++){
            queue.dequeue();
            System.out.println(queue);
        }
    }

}

 

Published 51 original articles · won praise 14 · views 40000 +

Guess you like

Origin blog.csdn.net/u010606397/article/details/98173224