1. 程式人生 > >數據結構:隊列

數據結構:隊列

turn docs size ces 限制 color 操作 nbsp oid

數據結構:隊列

先入先出的數據結構

說明

  技術分享圖片

  在先入先出數據結構中,將首先處理隊列中的第一個元素,即front所指的位置元素

  如上圖所示,隊列是典型的 FIFO 數據結構。插入(insert)操作也稱作入隊(enqueue)新元素始終被添加在隊列的末尾 刪除(delete)操作也被稱為出隊(dequeue)。 你只能移除第一個元素

示例

入隊操作

    技術分享圖片

出隊操作

技術分享圖片

隊列實現

  為了實現隊列,我們可以使用動態數組和指向隊列頭部的索引

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

// "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());
        }
    }
}

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

  技術分享圖片

  如果我們出隊了一個元素,此時第一個位置將空出來,這個空間的浪費我們可以使用循環隊列來解決

循環隊列

說明

  循環隊列是一種線性數據結構,其操作表現基於 FIFO(先進先出)原則並且隊尾被連接在隊首之後以形成一個循環。它也被稱為“環形緩沖器”。

  循環隊列的一個好處是我們可以利用這個隊列之前用過的空間。在一個普通隊列裏,一旦一個隊列滿了,我們就不能插入下一個元素,即使在隊列前面仍有空間。但是使用循環隊列,我們能使用這些空間去存儲新的值。

實現

class MyCircularQueue {
    
    private int[] data;
    private int head;
    private int tail;
    private int size;

    /** Initialize your data structure here. Set the size of the queue to be k. */
    public MyCircularQueue(int k) {
        data = new int[k];
        head = -1;
        tail = -1;
        size = k;
    }
    
    /** Insert an element into the circular queue. Return true if the operation is successful. */
    public boolean enQueue(int value) {
        if (isFull() == true) {
            return false;
        }
        if (isEmpty() == true) {
            head = 0;
        }
        tail = (tail + 1) % size;
        data[tail] = value;
        return true;
    }
    
    /** Delete an element from the circular queue. Return true if the operation is successful. */
    public boolean deQueue() {
        if (isEmpty() == true) {
            return false;
        }
        if (head == tail) {
            head = -1;
            tail = -1;
            return true;
        }
        head = (head + 1) % size;
        return true;
    }
    
    /** Get the front item from the queue. */
    public int Front() {
        if (isEmpty() == true) {
            return -1;
        }
        return data[head];
    }
    
    /** Get the last item from the queue. */
    public int Rear() {
        if (isEmpty() == true) {
            return -1;
        }
        return data[tail];
    }
    
    /** Checks whether the circular queue is empty or not. */
    public boolean isEmpty() {
        return head == -1;
    }
    
    /** Checks whether the circular queue is full or not. */
    public boolean isFull() {
        return ((tail + 1) % size) == head;
    }
}

/**
 * Your MyCircularQueue object will be instantiated and called as such:
 * MyCircularQueue obj = new MyCircularQueue(k);
 * boolean param_1 = obj.enQueue(value);
 * boolean param_2 = obj.deQueue();
 * int param_3 = obj.Front();
 * int param_4 = obj.Rear();
 * boolean param_5 = obj.isEmpty();
 * boolean param_6 = obj.isFull();
 */

隊列用法

  除基本Collection操作外,隊列還提供額外的插入,提取和檢查操作。這些方法中的每一種都以兩種形式存在:一種在操作失敗時拋出異常,另一種返回特殊值(nullfalse,具體取決於操作)後一種形式的插入操作專門用於容量限制的隊列 實現; 在大多數實現中,插入操作不會失敗。

技術分享圖片

技術分享圖片

// "static void main" must be defined in a public class.
public class Main {
    public static void main(String[] args) {
        // 1. Initialize a queue.
        Queue<Integer> q = new LinkedList();
        // 2. Get the first element - return null if queue is empty.
        System.out.println("The first element is: " + q.peek());
        // 3. Push new element.
        q.offer(5);
        q.offer(13);
        q.offer(8);
        q.offer(6);
        // 4. Pop an element.
        q.poll();
        // 5. Get the first element.
        System.out.println("The first element is: " + q.peek());
        // 7. Get the size of the queue.
        System.out.println("The size is: " + q.size());
    }
}

數據結構:隊列