LoopQueue

 

Code:

package dataStucture2.stackandqueue;

/**
 * 循环队列
 *
 * @param <E>
 */
public class MyLoopQueue<E> implements Queue<E> {

    /*
     * 成员变量:泛型数组、两个指向变量、循环队列个数size
     */
    private E[] data;
    private int front, tail;
    private int size;

    // 有参构造,初始化数组容量大小,指向变量指向索引为0
    public MyLoopQueue(int capacity) {
        // 判断tail在front前一位时队列为满,为了达到用户要求的容量,要求capacity比默认大1,此时多出的一位用于判断队列为满
        //实际长度:capacity+1  可用长度:capacity
        data = (E[]) new Object[capacity + 1];
        front = 0;
        tail = 0;
        size = 0;
    }

    // 无参构造,默认容量为10
    public MyLoopQueue() {
        this(10);
    }

    // 获取循环队列容量 ,1的存在为了判断队列为满,并不存储元素,此处减去
    int getCapacity() {
        //实际长度:capacity+1  可用长度:capacity
        return data.length - 1;
    }

    @Override
    // front和tail指向同一个位置,循环队列为空
    public boolean isEmpty() {
        return front == tail;
    }

    @Override
    // 获得循环队列元素个数
    public int getSize() {
        return size;
    }

    @Override
    //入队
    public void enqueue(E e) {        
        //首先判断队列是满,如果满了,进行扩容
        if((tail + 1) % data.length == front){
            resize(getCapacity() * 2);
        }    
        //如果没满,入队
        data[tail] = e;
        tail = (tail + 1) % data.length;
        size ++;
    }
    
    @Override
    //出队
    public E dequeue() {
        //首先判断队列是否为空,如果为空,抛出异常
        if(isEmpty()){
            throw new IllegalArgumentException(" Cannot dequeue from an empty queue ! ");
        }
        //如果不为空,出队
        E ret = data[front];
        data[front] = null;
        front = (front + 1) % data.length;
        size -- ;
        //动态扩容
        if(size == getCapacity() / 4 && getCapacity() / 2 != 0)
            resize(getCapacity() / 2);
        return ret;
    }
    
    @Override
    //获取队首元素
    public E getFront() {
        if(isEmpty()){
            throw new IllegalAccessError("Queue is empty.");
        }
        return data[front];
    }
    
    
    //循环队列动态扩容
    private void resize(int newCapacity){
        E[] newData = (E[])new Object[newCapacity +1];
        for(int i = 0 ; i < size ; i ++){
            //循环队列,%data.length为了防止越界
            newData[i] = data[( i + front ) % data.length];
        }
        /**
         * 此处错误:不应当每次扩容遍历都resize,遍历的目的是复制元素到新的数组,复制完了原数组指向新的数组完成扩容
         */
            data = newData;
            front = 0;
            tail = size;
        
    }
    
    @Override
    //打印循环队列
    public String toString() {
        
        StringBuilder res = new StringBuilder();
        res.append(String.format("Queue: size = %d , capacity = %d\n", size , getCapacity()));
        res.append("front [");
        //遍历循环队列,和resize中的循环遍历是两种方式,都可以达到母的
        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();
    }
    
}

 

循环队列解决了普通队列出队复杂度为O(n)的问题

toString方法和resize方法中,遍历循环队列的异同

循环队列的简单时间复杂度分析:

 

posted @ 2019-04-11 13:38  IslandZzzz  阅读(260)  评论(0编辑  收藏  举报