队列

队列

一般队列

在这里插入图片描述
队列是一种先进先出的数据结构。

public class MyQueue<E> {
    private Object[] data;
    private int maxSize;
    private int size;
    private int front;
    private int tail;

    public MyQueue(int maxSize) {
        if (maxSize <= 0)
            throw new IllegalArgumentException("队列容量必须大于0 : " + maxSize);
        this.maxSize = maxSize;
        data = new Object[this.maxSize];
    }

    public void add(E e) {
        if (this.isFull())
            throw new IllegalArgumentException("队列已经满了,无法再加入……");
        data[tail++] = e;
        size++;
    }

    public E remove() {
        if (isEmpty())
            throw new IllegalArgumentException("队列是空的,无法移除……");
        E e  = (E)data[front];
        data[front++] = null;
        size--;
        return e;
    }

    public boolean isFull() {
        // 最后一个位置是不存储数据的
        return tail == maxSize-1;
    }

    public boolean isEmpty() {
        //队列头和队列尾指向同一空间的时候,并且没到队尾,表示队列是空的
        return front == tail && !isFull();
    }

    public int getSize() {
        return size;
    }
}

测试一下

public static void main(String[] args) {
        MyQueue myQueue = new MyQueue(10);
        System.out.println("isEmpty()=" + myQueue.isEmpty());
        System.out.println("isFull()=" + myQueue.isFull());
        System.out.println("getSize()=" + myQueue.getSize());
        for (int i = 0; i < 9; i++) {
            myQueue.add(i * 100);
            myQueue.remove();
        }
        System.out.println("----------------------------");
        System.out.println("isEmpty()=" + myQueue.isEmpty());
        System.out.println("isFull()=" + myQueue.isFull());
        System.out.println("getSize()=" + myQueue.getSize());
    }

运行结果

isEmpty()=true
isFull()=false
getSize()=0
----------------------------
isEmpty()=false
isFull()=true
getSize()=0

我们添加了9次,然后又移除了9次,结果队列竟然满了,如果我们再添加一次的话肯定会抛异常,但实际上队列的size是0,还是空的,也就是说数组的每个位置只能使用一次,这样就造成了极大的浪费。那么前面使用过的空间还能不能再次利用了呢,实际上是可以的,我们可以把队列看成是环形的,当tail到达数组末尾的时候,如果数组的前面有空位子,我们可以让tail从头开始,这个时候一个新的队列就产生了,那就是双端队列。

双端队列

在这里插入图片描述
双端队列的队首和队尾都可以添加和删除元素,这样空间就可以循环利用了,不会造成浪费。

public class MyQueue<E> {
    private Object[] data;
    private int front;
    private int tail;

    public MyQueue(int maxSize) {
        data = new Object[maxSize];
    }

    // //空间扩容,这里选择扩大一倍
    private void doubleCapacity() {
        int p = front;
        int n = data.length;
        // 扩大一倍
        Object [] newData = new Object[n<<1];
        // 先 copy 后面的r个
        System.arraycopy(data, p, newData, 0, n-p);
        // 再 copy 前面的p个
        System.arraycopy(data, 0, newData, n-p, p);
        data = newData;
        // 重新调整 front 和 tail 的值
        front = 0;
        tail = n;
    }

    // 添加到第一个
    public void addFirst(E e) {
        // 添加到 front 的前面,所以 front-1
        front = (front - 1 + data.length) % data.length;
        data[front] = e;
        if (front == tail) // 如果已满就扩容
            doubleCapacity();
    }

    // 添加到最后一个
    public void addLast(E e) {
        // 因为 tail 位置是空的
        data[tail] = e;
        tail = (tail + 1) % data.length;
        if (tail == front)//判断是否满
            doubleCapacity();
    }

    // 删除第一个
    public E removeFirst() {
        if (isEmpty())
            throw new IllegalArgumentException("队列是空的,无法移除……");
        E e  = (E)data[front];
        data[front] = null;
        front = (front + 1 + data.length) % data.length;
        return e;
    }

    // 删除最后一个
    public E removelast() {
        if (isEmpty())
            throw new IllegalArgumentException("队列是空的,无法移除……");
        tail = (tail - 1 + data.length) % data.length;
        E e  = (E)data[tail];
        data[tail] = null;
        return e;
    }

    // 返回第一个
    public E peekFirst() {
        if (isEmpty())
            throw new IllegalArgumentException("队列是空的,无法移除……");
        return (E)data[front];
    }

    // 返回最后一个
    public E peekLast() {
        if (isEmpty())
            throw new IllegalArgumentException("队列是空的,无法移除……");
        return (E)data[(tail - 1 + data.length) % data.length];
    }

    public boolean isEmpty() {
        //队列头和队列尾指向同一空间的时候,并且没到队尾,表示队列是空的
        return front == tail;
    }

    public int getSize() {
        return (tail - front + data.length) % data.length;
    }

测试一下

    public static void main(String[] args) {
        MyQueue myQueue = new MyQueue(10);
        System.out.println("isEmpty()=" + myQueue.isEmpty());
        System.out.println("getSize()=" + myQueue.getSize());
        for (int i = 0; i < 5; i++)
            myQueue.addFirst(i * 100);
        for (int i = 5; i < 10; i++)
            myQueue.addLast(i * 100);
        myQueue.removeFirst();
        myQueue.removelast();
        System.out.println("----------------------------");
        System.out.println("isEmpty()=" + myQueue.isEmpty());
        System.out.println("getSize()=" + myQueue.getSize());
        System.out.println("----------------------------");
        System.out.println("First Element=" + myQueue.peekFirst());
        System.out.println("Last Element=" + myQueue.peekLast());
    }
}

运行结果

isEmpty()=true
getSize()=0
----------------------------
isEmpty()=false
getSize()=8
----------------------------
First Element=300
Last Element=800
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值