循環隊列:解決數組隊列出隊的時間復雜度


思路分析:

1.記錄數組的隊首和隊尾的位置,當front 和tail指在一起的時候數組為空。

 

2.出隊的時候front指針往后挪一位。這樣出隊操作就由數組隊列的 O(N) 變成  循環隊列的O(1)了。

讓數組循環利用起來:

當前索引+1 再百分之我們數組的長度    比如我們到了最后一位7, 7+1 = 8 就是我們數組的長度    8對8 求余 = 0   

就跟鍾表一樣   找到它的范圍  然后讓它在范圍內循環。    1%12 = 1;  2 % 12 = 2; .... 11%12=11 12%12 = 0  這樣就能無限在范圍內循環。

然而有一個問題我們front = tail 表示空數組,也可以表示滿數組。為了達到區分我們要刻意浪費一個空間,tail+1 = front = 滿數組!! 

 

 

 

 

package com.dapeng.Queue;
/**
 * @author gdp
 * @date 2020/4/5 23:06
 */
public class LoopQueue<E> implements Queue<E> {
    private E[] data;
    private int  front, tail; //數據首位   front==tail的時候空數組 但是也代表數組滿了 所以我們設計為tail+1 為數組滿了有意的浪費一個空間來做出區分
    private int size; //數組數據個數

    public LoopQueue(int capacity){
        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 boolean  isEmpty(){ return front == tail;}

    @Override
    public   int getSize(){ return size;}
    @Override
    public void enqueue(E e){
         //最后一個元素+1  取模
        if( (tail + 1) % data.length == front )
            resize(this.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  == this.getCapacity() /  4 && getCapacity()/2 != 0)
         {
             resize(getCapacity() / 2);
         }
        return ret;
    }

    @Override
    public E getFront(){
        if(isEmpty()) throw new IllegalArgumentException("  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++ )
         {
             newData[i] = data[(front + i) % data.length];
             data = newData;
             front = 0;
             tail = size;
         }
    }

    @Override
    public String toString()
    {
        StringBuilder res   = new StringBuilder();
        res.append(String.format("Queen: size = %d, capacity = %d\n",size,getCapacity()));
        res.append("front [");
        for(int i = front; i != tail; i = (i+1) % data.length)
        {
            res.append(data[i]);
            if(i!=size-1)
                res.append(",");
        }
        res.append("]tail");
        return res.toString();
    }



    public static void main(String[] args) {
        LoopQueue<Integer> queue = new LoopQueue<>();
        for(int i = 0 ; i < 10 ; i++ ){
            queue.enqueue(i);

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


}

這個是測試兩種隊列效率的代碼:顯然循環隊列是快了很多的。

package com.dapeng.Queue;
import java.util.Random;
/**
 * @author gdp
 * @date 2020/4/6 18:41
 */
public class queueTest {
   private static double test(Queue<Integer> queue, int opCount){
       long startTime = System.nanoTime();
       Random random = new Random();
       for (int i = 0; i< opCount ; i++) queue.enqueue(random.nextInt(Integer.MAX_VALUE));
       for (int i = 0; i< opCount ; i++)  queue.dequeue();
       long endTime = System.nanoTime();

       return (endTime - startTime) / 100000000.0;
   }

    public static void main(String[] args) {
        int     opCount = 1000000;
        ArrayQueue<Integer> arrayQueue = new ArrayQueue<>();
        double time1 = test(arrayQueue, opCount);
        System.out.println("ArrayQueue, time:" +time1+"  s");

        LoopQueue<Integer> LoopQueue = new LoopQueue<>();
        double time2 = test(LoopQueue, opCount);
        System.out.println("LoopQueue, time:" +time2+"  s");
    }

}

兩個耗時結果比較:

ArrayQueue, time:2926.524975 s
LoopQueue, time:0.457739 s

 

文章視頻鏈接:https://www.ixigua.com/i6815911054443282948/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM