Java--循环队列

Java–循环队列–基于泛型数组

一、为什么需要循环队列?

循环队列使出队操作的时间复杂度降到了O(1)级别

二、底层维护:
  • data : 泛型数组

  • front: 指向队首

  • tail : 指向队尾(下一个待插入的位置

  • size : 实际元素个数

三、基于数组的循环队列以一个额外空间为代价维护以下条件:
  1. 队列空:front = tail
  2. 队列满:(tail+1)%data.length = front
  3. (tail+1) % data.length:是什么意思?以循环的方式向后移动一位
四、原理图:

在这里插入图片描述
在这里插入图片描述

五、注意
  1. 涉及队尾,队首指针的移动必须以循环的方式移动,而不是直接"++"就完事
  • (tail+1)%data.length

  • (front+1)%data.length

  1. 基于数组的循环队列的遍历方式
/**
 *
 * @author a_apple
 * @create 2020-04-14 21:00
 */
public class LoopQueue<E> implements Queue<E> {

    private E[] data;
    private int front, tail;
    private int size;

    public LoopQueue(int capacity) {
        //用户期望存储capacity个元素,但底层需要浪费一个空间维护,所以创建capacity+1
        data = (E[]) new Object[capacity + 1];
        front = 0;
        tail = 0;
        size = 0;
    }

    public LoopQueue() {
        this(10);
    }

    //获取队列 实际可存储最大容量
    public int getCapacity() {
        return data.length - 1;
    }

    //队尾进队
    @Override
    public void enQueue(E e) {
        //1.先判断队列是否满了,满了要扩容
        if (isFull()) {
            resize(getCapacity() * 2);
        }
        data[tail] = e;
        //tail以循环的方式向后移一位
        tail = (tail + 1) % data.length;
        size++;
    }
    
    //队首出队  时间复杂度变成了O(1)
    @Override
    public E deQueue() {
        //先判断是否队列空
        if (isEmpty()) {
            throw new IllegalArgumentException("deQueue error, Queue is Empty!");
        }
        E ret = data[front];
        //front以循环的方式向后移一位
        front = (front + 1) % data.length;
        size--;
        //当size == capacity/4  ,进行缩容操作,并且缩容的容量!=0
        if (size == getCapacity() / 4 && getCapacity() / 2 != 0)
            resize(getCapacity() / 2);
        return ret;
    }
    
    //扩容
    private void resize(int newCapacity) {
        //扩容时,同样需要多添加一个额外的空间
        E[] newData = (E[]) new Object[newCapacity + 1];
        //遍历循环队列的一种方式
        for (int i = 0; i < size; i++) {
            //把front到tail复制到newData
            //把front 放到i=0     front+1 放到i=1   front+2 放到i=2
            //为啥还要 % data.length ?因为front+i可能会>size-1,此时需要返回到队首
            newData[i] = data[(front + i) % data.length];
        }
        data = newData;
        front = 0;
        tail = size;  //下一个待进队的位置
    }

    //获取队首元素
    @Override
    public E getFront() {
        //先判断是否队列空
        if (isEmpty()) {
            throw new IllegalArgumentException("getFront error, Queue is Empty!");
        }
        return data[front];
    }

    @Override
    public int getSize() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return front == tail;
    }

    //判断队列满:(tail + 1) % data.length == front
    public boolean isFull() {
        return (tail + 1) % data.length == front;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(String.format("Queue: size=%d,capacity=%d\n", size, getCapacity()));
        sb.append(" front [");
        //i循环的向后移1位,因为i可能会大于size-1
        for (int i = front; i != tail; i = (i + 1) % data.length) {
            sb.append(data[i]);
            //判断是否是最后一个元素,因为最后一个元素的下一个元素坐标就是tail
            if ((i + 1) % data.length != tail) {
                sb.append(",");
            }
        }
        sb.append("] tail");
        return sb.toString();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值