数据结构学习(二):循环队列

版权声明:文章为作者原创,若要转载请获得作者同意。尊重版权,从你我做起! https://blog.csdn.net/qq_37768971/article/details/88077426

一、实现目标

1.实现循环队列,减少出列的复杂度为O1;

2.在刘宇波老师的代码基础上不使用size;

3.难度更大,挑战性更大。

二、具体代码

package com.company;

public class LoopQueue <E>implements Queue<E>{
    private E [] loopqueue;
    int front,tail;

    public LoopQueue(int capacity){
        loopqueue=(E[]) new Object[capacity+1];
        front=0;
        tail=0;
    }

    public LoopQueue(){
        this(10);
    }
    public int getCapacity(){
        return loopqueue.length-1;
    }

    @Override
    public int getSize(){
        if (tail>=front)return tail-front;
        else return tail+loopqueue.length-front;
    }

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

    @Override
    public E getFront(){
        return loopqueue[front];
    }

    @Override
    public void enqueue(E e){
        if ((tail + 1) % loopqueue.length == front)
            resize(getCapacity()*2);
        loopqueue[tail]=e;
        tail=(tail+1)%(loopqueue.length);
    }

    public void resize(int capacity){
        E[] reloopqueue=(E[]) new Object [capacity+1];
        for (int i =0; i<getSize();i++){
            reloopqueue[i]=loopqueue[(i +front) % loopqueue.length];
        }
        tail=getSize();
        front =0;
        loopqueue=reloopqueue;


    }
    @Override
    public E dequeue(){
        if(isEmpty()) throw new IllegalArgumentException("Cannot dequeue from an empty queue.");
        E out= loopqueue[front];
        loopqueue[front] = null;
        front=(front+1)%loopqueue.length;
        if(getSize() == getCapacity() / 4 && getCapacity() / 2 != 0)
            resize(getCapacity() / 2);
        return out;
    }

    @Override
    public String toString() {

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


接口:
 

public interface Queue<E> {

    int getSize();
    boolean isEmpty();
    void enqueue(E e);
    E dequeue();
    E getFront();
}

三、测试用例:

   public static void main(String[] args){

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

            if(i % 3 == 2){
                queue.dequeue();
                System.out.println(queue);
            }
        }
    }

result:

LoopQueue: size = 1 , capacity = 10
[0]
LoopQueue: size = 2 , capacity = 10
[0, 1]
LoopQueue: size = 3 , capacity = 10
[0, 1, 2]
LoopQueue: size = 2 , capacity = 5
[1, 2]
LoopQueue: size = 3 , capacity = 5
[1, 2, 3]
LoopQueue: size = 4 , capacity = 5
[1, 2, 3, 4]
LoopQueue: size = 5 , capacity = 5
[1, 2, 3, 4, 5]
LoopQueue: size = 4 , capacity = 5
[2, 3, 4, 5]
LoopQueue: size = 5 , capacity = 5
[2, 3, 4, 5, 6]
LoopQueue: size = 6 , capacity = 10
[2, 3, 4, 5, 6, 7]
LoopQueue: size = 7 , capacity = 10
[2, 3, 4, 5, 6, 7, 8]
LoopQueue: size = 6 , capacity = 10
[3, 4, 5, 6, 7, 8]
LoopQueue: size = 7 , capacity = 10
[3, 4, 5, 6, 7, 8, 9]
 

四、分析

结果显示:每增加三个元素出队一个元素,队列满时自动扩容。队列元素减少到容量1/4时,自动缩减1/2的容量。

注意事项

1.想要获得队列当前容纳的数据个数需要分两种情况:

public int getSize(){
        if (tail>=front)return tail-front;
        else return tail+loopqueue.length-front;
    }

2.在进行resize时特别要注意使用上一点提到的getSize:

  tail=getSize();
        front =0;
        loopqueue=reloopqueue;

因为当tail<front时getSize与capacity是相关的,所以要提前将tail=getSize写咋子loopqueue=reloopqueue之前,而不能像波波老师的课程代码那样写。

3.每次front+1或者tail+1都是对length取余数,而不是capacity:
front=(front+1)%loopqueue.length;
因为整个队列的长度实际上是length,而capacity在初始化数组的时候已经进行+1。

4.还有一些bug可能不具有普遍性,总之收获真的很大,希望大家都要尝试一下,惊险刺激!

猜你喜欢

转载自blog.csdn.net/qq_37768971/article/details/88077426