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 @   IslandZzzz  阅读(262)  评论(0编辑  收藏  举报
编辑推荐:
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
点击右上角即可分享
微信分享提示