隊列(FIFO)詳解


寫在前面的話:

一枚自學Java和算法的工科妹子。

  • 算法學習書目:算法(第四版) Robert Sedgewick
  • 算法視頻教程:Coursera  Algorithms Part1&2

本文是根據《算法(第四版)》的個人總結,如有錯誤,請批評指正。

 

一、隊列的定義

先進先出隊列(簡稱隊列)是一種基於先進先出(FIFO)策略的集合類型。

當foreach語句迭代訪問隊列中的元素時,元素的處理順序就是它們添加到隊列中的順序。

 

二、隊列的實現

1.數組實現(可動態調整數組大小的隊列)

import java.util.Iterator;
import java.util.NoSuchElementException;

public class ResizingArrayQueue<Item> implements Iterable<Item> {
    private Item[] q;       // queue elements
    private int n;          // number of elements on queue
    private int first;      // index of first element of queue
    private int last;       // index of next available slot

    public ResizingArrayQueue() {
        q = (Item[]) new Object[2];
        n = 0;
        first = 0;
        last = 0;
    }

    public boolean isEmpty() {
        return n == 0;
    }

    public int size() {
        return n;
    }

    private void resize(int capacity) {
        assert capacity >= n;
        Item[] temp = (Item[]) new Object[capacity];
        for (int i = 0; i < n; i++) {
            temp[i] = q[(first + i) % q.length];
        }
        q = temp;
        first = 0;
        last  = n;
    }

    public void enqueue(Item item) {
        // double size of array if necessary and recopy to front of array
        if (n == q.length) resize(2*q.length);   // double size of array if necessary
        q[last++] = item;                        // add item
        if (last == q.length) last = 0;          // wrap-around
        n++;
    }

    public Item dequeue() {
        if (isEmpty()) throw new NoSuchElementException("Queue underflow");
        Item item = q[first];
        q[first] = null;                            // to avoid loitering
        n--;
        first++;
        if (first == q.length) first = 0;           // wrap-around
        // shrink size of array if necessary
        if (n > 0 && n == q.length/4) resize(q.length/2); 
        return item;
    }

    public Item peek() {
        if (isEmpty()) throw new NoSuchElementException("Queue underflow");
        return q[first];
    }

    public Iterator<Item> iterator() {
        return new ArrayIterator();
    }

    private class ArrayIterator implements Iterator<Item> {
        private int i = 0;
        public boolean hasNext()  { return i < n;                               }
        public void remove()      { throw new UnsupportedOperationException();  }

        public Item next() {
            if (!hasNext()) throw new NoSuchElementException();
            Item item = q[(i + first) % q.length];
            i++;
            return item;
        }
    }

    public static void main(String[] args) {
        ResizingArrayQueue<String> queue = new ResizingArrayQueue<String>();
        while (!StdIn.isEmpty()) {
            String item = StdIn.readString();
            if (!item.equals("-")) queue.enqueue(item);
            else if (!queue.isEmpty()) StdOut.print(queue.dequeue() + " ");
        }
        StdOut.println("(" + queue.size() + " left on queue)");
    }

}

 

2.鏈表實現

import java.util.Iterator;
import java.util.NoSuchElementException;

public class Queue<Item> implements Iterable<Item> {
    private Node<Item> first;    // beginning of queue
    private Node<Item> last;     // end of queue
    private int n;               // number of elements on queue

    // helper linked list class
    private static class Node<Item> {
        private Item item;
        private Node<Item> next;
    }

    public Queue() {
        first = null;
        last  = null;
        n = 0;
    }

    public boolean isEmpty() {
        return first == null;
    }

    public int size() {
        return n;
    }

    public Item peek() {
        if (isEmpty()) throw new NoSuchElementException("Queue underflow");
        return first.item;
    }

   // 在表尾插入結點
    public void enqueue(Item item) {
        Node<Item> oldlast = last;
        last = new Node<Item>();
        last.item = item;
        last.next = null;
        if (isEmpty()) first = last;
        else           oldlast.next = last;
        n++;
    }

  // 在表頭刪除結點
    public Item dequeue() {
        if (isEmpty()) throw new NoSuchElementException("Queue underflow");
        Item item = first.item;
        first = first.next;
        n--;
        if (isEmpty()) last = null;   // to avoid loitering
        return item;
    }

    public String toString() {
        StringBuilder s = new StringBuilder();
        for (Item item : this) {
            s.append(item);
            s.append(' ');
        }
        return s.toString();
    } 
  
    public Iterator<Item> iterator()  {
        return new ListIterator<Item>(first);  
    }

    private class ListIterator<Item> implements Iterator<Item> {
        private Node<Item> current;

        public ListIterator(Node<Item> first) {
            current = first;
        }

        public boolean hasNext()  { return current != null;                     }
        public void remove()      { throw new UnsupportedOperationException();  }

        public Item next() {
            if (!hasNext()) throw new NoSuchElementException();
            Item item = current.item;
            current = current.next; 
            return item;
        }
    }

    public static void main(String[] args) {
        Queue<String> queue = new Queue<String>();
        while (!StdIn.isEmpty()) {
            String item = StdIn.readString();
            if (!item.equals("-"))
                queue.enqueue(item);
            else if (!queue.isEmpty())
                StdOut.print(queue.dequeue() + " ");
        }
        StdOut.println("(" + queue.size() + " left on queue)");
    }
}

 兩種實現方式的比較見前一篇文章----下壓棧(LIFO)詳解

 

三、隊列的應用

In類的靜態方法readInts()的一種實現

注意:《算法(第四版)》書中為了方便向文件中讀取和寫入原始數據類型(或String類型),提供了In和Out API。感興趣的朋友可以去http://algs4.cs.princeton.edu/下載。

代碼的解釋:In類中的readInt()方法,其實就是用了Scanner中的nextInt()方法,讀取一個整數;

                   Queue類是用鏈表實現的隊列。

readInts()作用:這個方法為用例解決的問題是用例無需預先知道文件的大俠即可將文件中的所有整數讀入一個數組中。

  • 將文件中所有的整數讀入隊列(鏈表實現的),用enqueue()方法;
  • Queue類的size()方法得到隊列中元素的數目,即確定數組的大小;
  • 創建數組,並將隊列的所有整數移動到數組中,用dequeue()方法。

隊列之所以合適是因為它的先進先出策略,可以將所有的整數按照文件中的順序放入數組中。

public static int[] readInts(String name){

    In in = new In(name);
    Queue<String> q = new Queue<String>;

    while(!in.isEmpty()){
    q.enqueue(in.readInt());
    }

    int N = q.size();
    int[] a = new int[N];
    for(int i = 0; i < N; i++)
         a[i]=q.dequeue();
     
    return a;
}

 

 

作者: 鄒珍珍(Pearl_zhen)

出處: http://www.cnblogs.com/zouzz/

聲明:本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出 原文鏈接 如有問題, 可郵件(zouzhenzhen@seu.edu.cn)咨詢.


免責聲明!

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



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