數據結構-隊列

Queue

隊列(queue)簡稱隊,它同堆棧一樣,也是一種運算受限的線性表,其限制是僅允許 在表的一端進行插入,而在表的另一端進行刪除。在隊列中把插入數據元素的一端稱為隊尾(rear),刪除數據元素的一端稱為隊首(front)。向隊尾插入元素稱為進隊或入隊,新元素 入隊后成為新的隊尾元素;從隊列中刪除元素稱為離隊或出隊,元素出隊后,其后續元素成 為新的隊首元素。 由于隊列的插入和刪除操作分別在隊尾和隊首進行,每個元素必然按照進入的次序離隊,也就是說先進隊的元素必然先離隊,所以稱隊列為先進先出表(First In First Out,簡稱 FIFO)。

image.png

順序存儲結構

ArrayQueue

在隊列的順序存儲實現中,我們可以將隊列當作一般的表用數組加以實現,但這樣做的 效果并不好。盡管我們可以用一個指針 last 來指示隊尾,使得 enqueue 運算可在Ο(1)時間內 完成,但是在執行 dequeue 時,為了刪除隊首元素,必須將數組中其他所有元素都向前移動 一個位置。這樣,當隊列中有 n 個元素時,執行 dequeue 就需要Ο(n)時間。為了提高運算的效率,我們用另一種方法來表達數組中各單元的位置關系。設想數組 A[0.. capacity-1]中的單元不是排成一行,而是圍成一個圓環


ArrayQueue
public class ArrayQueue<T> extends AbstractList<T> {
    public ArrayQueue(int capacity) {
        this.capacity = capacity + 1;
        this.queue = newArray(capacity + 1);
        this.head = 0;
        this.tail = 0;
    }

    public void resize(int newcapacity) {
        int size = size();
        if (newcapacity < size)
            throw new IndexOutOfBoundsException("Resizing would lose data");
        newcapacity++;
        if (newcapacity == this.capacity)
            return;
        T[] newqueue = newArray(newcapacity);
        for (int i = 0; i < size; i++)
            newqueue[i] = get(i);
        this.capacity = newcapacity;
        this.queue = newqueue;
        this.head = 0;
        this.tail = size;
    }

    @SuppressWarnings("unchecked")
    private T[] newArray(int size) {
        return (T[]) new Object[size];
    }

    public boolean add(T o) {
        queue[tail] = o;
        int newtail = (tail + 1) % capacity;
        if (newtail == head)
            throw new IndexOutOfBoundsException("Queue full");
        tail = newtail;
        return true; // we did add something
    }

    public T remove(int i) {
        if (i != 0)
            throw new IllegalArgumentException("Can only remove head of queue");
        if (head == tail)
            throw new IndexOutOfBoundsException("Queue empty");
        T removed = queue[head];
        queue[head] = null;
        head = (head + 1) % capacity;
        return removed;
    }

    public T get(int i) {
        int size = size();
        if (i < 0 || i >= size) {
            final String msg = "Index " + i + ", queue size " + size;
            throw new IndexOutOfBoundsException(msg);
        }
        int index = (head + i) % capacity;
        return queue[index];
    }

    public int size() {
        // Can't use % here because it's not mod: -3 % 2 is -1, not +1.
        int diff = tail - head;
        if (diff < 0)
            diff += capacity;
        return diff;
    }

    private int capacity;
    private T[] queue;
    private int head;
    private int tail;
}
鏈式存儲結構

隊列的鏈式存儲可以使用單鏈表來實現。為了操作實現方便,這里采用帶頭結點的單鏈 表結構。根據單鏈表的特點,選擇鏈表的頭部作為隊首,鏈表的尾部作為隊尾。除了鏈表頭 結點需要通過一個引用來指向之外,還需要一個對鏈表尾結點的引用,以方便隊列的入隊操 作的實現。為此一共設置兩個指針,一個隊首指針和一個隊尾指針,如圖所示,隊首針指(front)向隊首元素的前一個結點,即始終指向鏈表空的頭結點; 隊尾指針(rear)指向隊列當前隊尾元素所在的結點。當隊列為空時,隊首指針與隊尾指針均指向空的頭結點。在Java中沒有顯式的指針類型,然而實際上對象的訪問就是使用指針來實現的,即在Java中是使用對象的引用來替代指針的。


LinkedQueue
node
LinkedList
public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
    transient int size = 0;

    /**
     * Pointer to first node.
     * Invariant: (first == null && last == null) ||
     *            (first.prev == null && first.item != null)
     */
    transient Node<E> first;

    /**
     * Pointer to last node.
     * Invariant: (first == null && last == null) ||
     *            (last.next == null && last.item != null)
     */
    transient Node<E> last;

public boolean offer(E e) {
        return add(e);
    }
    public boolean add(E e) {
        linkLast(e);
        return true;
    }

   void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size++;
        modCount++;
    }

public E poll() {
        final Node<E> f = first;
        return (f == null) ? null : unlinkFirst(f);
    }
    public E pop() {
        return removeFirst();
    }

    public E removeFirst() {
        final Node<E> f = first;
        if (f == null)
            throw new NoSuchElementException();
        return unlinkFirst(f);
    }

    private E unlinkFirst(Node<E> f) {
        // assert f == first && f != null;
        final E element = f.item;
        final Node<E> next = f.next;
        f.item = null;
        f.next = null; // help GC
        first = next;
        if (next == null)
            last = null;
        else
            next.prev = null;
        size--;
        modCount++;
        return element;
    }

}
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 一.隊列的定義 隊列是指在表的一端進行插入操作,在另一端進行刪除操作的一種數據結構。它是一種先進先出的線性表,就如...
    yzbkaka閱讀 493評論 0 1
  • 我們在使用手機的時候,偶爾都會碰到過卡住的時候,比如一個地方怎么點都沒有用,屏幕也卡住不顯示其他東西,但當你把卡住...
    Originalee閱讀 758評論 0 10
  • 一些概念 數據結構就是研究數據的邏輯結構和物理結構以及它們之間相互關系,并對這種結構定義相應的運算,而且確保經過這...
    Winterfell_Z閱讀 5,917評論 0 13
  • 代碼GitHub地址 隊列 隊列和棧一樣是特殊的線性表。區別只是它能尾進頭出而已 學習隊列需要清楚的認識到fron...
    HikariCP閱讀 463評論 0 0
  • 我經常會想哪里可以隨心所欲的發發心情 結果這個地方讓我特別的滿意 沒有人認識你 也不知道你長怎樣 我可不丑哦 在...
    譚秋一閱讀 229評論 5 0