1. 程式人生 > >資料結構之 佇列(Queue)的實現 Java

資料結構之 佇列(Queue)的實現 Java

佇列 - 實現

為了實現佇列,我們可以使用動態陣列和指向佇列頭部的索引。

如上所述,佇列應支援兩種操作:入隊和出隊。入隊會向佇列追加一個新元素,而出隊會刪除第一個元素。 所以我們需要一個索引來指出起點。

這是一個供你參考的實現:

// "static void main" must be defined in a public class.

class MyQueue {
    // store elements
    private List<Integer> data;         
    // a pointer to indicate the start position
    private int p_start;            
    public MyQueue() {
        data = new ArrayList<Integer>();
        p_start = 0;
    }
    /** Insert an element into the queue. Return true if the operation is successful. */
    public boolean enQueue(int x) {
        data.add(x);
        return true;
    };    
    /** Delete an element from the queue. Return true if the operation is successful. */
    public boolean deQueue() {
        if (isEmpty() == true) {
            return false;
        }
        p_start++;
        return true;
    }
    /** Get the front item from the queue. */
    public int Front() {
        return data.get(p_start);
    }
    /** Checks whether the queue is empty or not. */
    public boolean isEmpty() {
        return p_start >= data.size();
    }     
};

public class Main {
    public static void main(String[] args) {
        MyQueue q = new MyQueue();
        q.enQueue(5);
        q.enQueue(3);
        if (q.isEmpty() == false) {
            System.out.println(q.Front());
        }
        q.deQueue();
        if (q.isEmpty() == false) {
            System.out.println(q.Front());
        }
        q.deQueue();
        if (q.isEmpty() == false) {
            System.out.println(q.Front());
        }
    }
}

缺點

上面的實現很簡單,但在某些情況下效率很低。 隨著起始指標的移動,浪費了越來越多的空間。 當我們有空間限制時,這將是難以接受的。

讓我們考慮一種情況,即我們只能分配一個最大長度為 5 的陣列。當我們只新增少於 5 個元素時,我們的解決方案很有效。 例如,如果我們只調用入隊函式四次後還想要將元素 10 入隊,那麼我們可以成功。

但是我們不能接受更多的入隊請求,這是合理的,因為現在佇列已經滿了。但是如果我們將一個元素出隊呢?

實際上,在這種情況下,我們應該能夠再接受一個元素。

 迴圈佇列

此前,我們提供了一種簡單但低效的佇列實現。

更有效的方法是使用迴圈佇列。 具體來說,我們可以使用固定大小的陣列

兩個指標來指示起始位置和結束位置。 目的是重用我們之前提到的被浪費的儲存

 設計迴圈佇列

設計你的迴圈佇列實現。 迴圈佇列是一種線性資料結構,其操作表現基於 FIFO(先進先出)原則並且隊尾被連線在隊首之後以形成一個迴圈。它也被稱為“環形緩衝器”。 迴圈佇列的一個好處是我們可以利用這個佇列之前用過的空間。在一個普通佇列裡,一旦一個佇列滿了,我們就不能插入下一個元素,即使在佇列前面仍有空間。但是使用迴圈佇列,我們能使用這些空間去儲存新的值。 你的實現應該支援如下操作:

  • MyCircularQueue(k): 構造器,設定佇列長度為 k 。
  • Front: 從隊首獲取元素。如果佇列為空,返回 -1 。
  • Rear: 獲取隊尾元素。如果佇列為空,返回 -1 。
  • enQueue(value): 向迴圈佇列插入一個元素。如果成功插入則返回真。
  • deQueue(): 從迴圈佇列中刪除一個元素。如果成功刪除則返回真。
  • isEmpty(): 檢查迴圈佇列是否為空。
  • isFull(): 檢查迴圈佇列是否已滿。

示例:

MyCircularQueue circularQueue = new MycircularQueue(3); // 設定長度為3

circularQueue.enQueue(1);  // 返回true

circularQueue.enQueue(2);  // 返回true

circularQueue.enQueue(3);  // 返回true

circularQueue.enQueue(4);  // 返回false,佇列已滿

circularQueue.Rear();  // 返回3

circularQueue.isFull();  // 返回true

circularQueue.deQueue();  // 返回true

circularQueue.enQueue(4);  // 返回true

circularQueue.Rear();  // 返回4

程式碼如下:

public class MyCircularQueue {

    int [] mcq ;
    int k;
    int head=0;
    int tail=0;

    /** Initialize your data structure here. Set the size of the queue to be k. */
        public MyCircularQueue(int k) {
            this.k=k+1;
            mcq=new int[k+1];
            for(int i:mcq){
                mcq[i]=-1;
            }
            head=0;
            tail=0;
        }

        /** Insert an element into the circular queue. Return true if the operation is successful. */
        public boolean enQueue(int value) {
            if(isFull()){
                return false;
            }
            else{

                if(tail!=k-1){
                    mcq[tail++]=value;
                }
                else{
                    mcq[tail]=value;
                    tail=0;
                }
                return true;
            }


        }

        /** Delete an element from the circular queue. Return true if the operation is successful. */
        public boolean deQueue() {
            if(isEmpty()){
                return false;
            }
            else {
                mcq[head]=0;
               if(head!=k-1){
                   head++;
               }
               else {
                   head=0;
               }
                return true;
            }

        }

        /** Get the front item from the queue. */
        public int Front() {
            if(isEmpty()){
                return  -1;
            }
            else {
                return mcq[head];
            }

        }

        /** Get the last item from the queue. */
        public int Rear() {
           if(isEmpty()){
               return -1;
           }
           else {
               if(tail!=0){
                   return mcq[tail-1];
               }
               else{
                   return mcq[k-1];
               }
           }

        }

        /** Checks whether the circular queue is empty or not. */
        public boolean isEmpty() {
            if(head==tail){
                return true;
            }
            else {
                return false;
            }

        }

        /** Checks whether the circular queue is full or not. */
        public boolean isFull() {
            if((head==0 && tail==k-1) || head-1==tail){
                return true;
            }
            else {
                return false;
            }

        }


    public static void main(String[] args) {
            MyCircularQueue t=new MyCircularQueue(6);
            System.out.println(t.enQueue(1));
            System.out.println(t.enQueue(2));
            System.out.println(t.enQueue(3));
            System.out.println(t.enQueue(4));
            System.out.println(t.enQueue(5));
            System.out.println(t.enQueue(6));
            System.out.println(t.Rear());
            System.out.println(t.Rear());
            System.out.println(t.deQueue());
            System.out.println(t.enQueue(5));
            System.out.println(t.Rear());
            System.out.println(t.deQueue());
            System.out.println(t.Front());
            System.out.println(t.deQueue());
            System.out.println(t.deQueue());
            System.out.println(t.deQueue());



    }


}