教你如何使用Java手寫一個基於數組實現的隊列

  1、概述
  隊列,又稱爲佇列(queue),是先進先出(FIFO, First-In-First-Out)的線性表。在具體應用中一般用鏈表或者數組來實現。隊列只容許在後端(稱爲rear)進行插入操做,在前端(稱爲front)進行刪除操做。隊列的操做方式和堆棧相似,惟一的區別在於隊列只容許新數據在後端進行添加。前端

  在Java中隊列又能夠分爲兩個大類,一種是阻塞隊列和非阻塞隊列。java

  一、沒有實現阻塞接口:後端

  1)實現java.util.Queue的LinkList,數組

  2)實現java.util.AbstractQueue接口內置的不阻塞隊列: PriorityQueue 和 ConcurrentLinkedQueue數據結構

  二、實現阻塞接口的app

  java.util.concurrent 中加入了 BlockingQueue 接口和五個阻塞隊列類。它實質上就是一種帶有一點扭曲的 FIFO 數據結構。不是當即從隊列中添加或者刪除元素,線程執行操做阻塞,直到有空間或者元素可用。
  五個隊列所提供的各有不一樣:
   ArrayBlockingQueue :一個由數組支持的有界隊列。
  
LinkedBlockingQueue :一個由連接節點支持的可選有界隊列。
   PriorityBlockingQueue :一個由優先級堆支持的×××優先級隊列。
  
DelayQueue :一個由優先級堆支持的、基於時間的調度隊列。
  * SynchronousQueue :一個利用 BlockingQueue 接口的簡單彙集(rendezvous)機制。
  隊列是Java中經常使用的數據結構,好比在線程池中就是用到了隊列,好比消息隊列等。ide

  由隊列先入先出的特性,咱們知道隊列數據的存儲結構能夠兩種,一種是基於數組實現的,另外一種則是基於單鏈實現。前者在建立的時候就已經肯定了數組的長度,因此隊列的長度是固定的,可是能夠循環使用數組,因此這種隊列也能夠稱之爲循環隊列。後者實現的隊列內部經過指針指向造成一個隊列,這種隊列是單向且長度不固定,因此也稱之爲非循環隊列。下面我將使用兩種方式分別實現隊列。ui

  2、基於數組實現循環隊列
  因爲在往隊列中放數據或拉取數據的時候須要移動數組對應的下標,因此須要記錄一下隊尾和隊頭的位置。說一下幾個核心的屬性吧:線程

  一、queue:隊列,object類型的數組,用於存儲數據,長度固定,當存儲的數據數量大於數組當度則拋出異常;指針

  二、head:隊頭指針,int類型,用於記錄隊列頭部的位置信息。

  三、tail:隊尾指針,int類型,用於記錄隊列尾部的位置信息。

  四、size:隊列長度,隊列長度大於等於0或者小於等於數組長度。

複製代碼
/**

  • 隊列管道,當管道中存放的數據大於隊列的長度時將不會再offer數據,直至從隊列中poll數據後
    */
    private Object[] queue;
    //隊列的頭部,獲取數據時老是從頭部獲取
    private int head;
    //隊列尾部,push數據時老是從尾部添加
    private int tail;
    //隊列長度
    private int size;
    //數組中能存放數據的最大容量
    private final static int MAX_CAPACITY = 1<<30;
    //數組長度
    private int capacity;
    //最大下標
    private int maxIndex;
    複製代碼
      

  3、數據結構

  圖中,紅色部分即爲隊列的長度,數組的長度爲16。由於這個隊列是循環隊列,因此隊列的頭部不必定要在隊列尾部前面,只要隊列的長度不大於數組的長度就能夠了。

  4、構造方法
  一、MyQueue(int initialCapacity):建立一個最大長度爲 initialCapacity的隊列。

  二、MyQueue():建立一個默認最大長度的隊列,默認長度爲16;

複製代碼
public MyQueue(int initialCapacity){
if (initialCapacity > MAX_CAPACITY)
throw new OutOfMemoryError("initialCapacity too large");
if (initialCapacity <= 0)
throw new IndexOutOfBoundsException("initialCapacity must be more than zero");
queue = new Object[initialCapacity];
capacity = initialCapacity;
maxIndex = initialCapacity - 1;
head = tail = -1;
size = 0;
}
public MyQueue(){
queue = new Object[16];
capacity = 16;
head = tail = -1;
size = 0;
maxIndex = 15;
}
複製代碼

  5、往隊列添加數據
  添加數據時,首先判斷隊列的長度是否超出了數組的長度,若是超出了就添加失敗(也能夠設置成等待,等到有人消費了隊列裏的數據,而後再添加進去)。都是從隊列的尾部添加數據的,添加完數據後tail指針也會相應自增1。具體實現如一下代碼:

複製代碼
/**

  • 往隊列尾部添加數據
  • @param object 數據
    */
    public void offer(Object object){
    if (size >= capacity){
    System.out.println("queue's size more than or equal to array's capacity");
    return;
    }
    if (++tail > maxIndex){
    tail = 0;
    }
    queue[tail] = object;
    size++;
    }
    複製代碼

  6、向隊列中拉取數據
  拉取數據是從隊列頭部拉取的,拉取完以後將該元素刪除,隊列的長度減一,head自增1。代碼以下:

複製代碼
/**

  • 從隊列頭部拉出數據
  • @return 返回隊列的第一個數據
    */
    public Object poll(){
    if (size <= 0){
    System.out.println("the queue is null");
    return null;
    }
    if (++head > maxIndex){
    head = 0;
    }
    size--;
    Object old = queue[head];
    queue[head] = null;
    return old;
    }
    複製代碼
      

  7、其餘方法
  一、查看數據:這個方法跟拉取數據同樣都是獲取到隊列頭部的數據,區別是該方法不會將對頭數據刪除:

複製代碼
/**

  • 查看第一個數據
  • @return
    */
    public Object peek(){
    return queue[head];
    }
    複製代碼
      二、清空隊列:

複製代碼
/**

  • 清空隊列
    */
    public void clear(){
    for (int i = 0; i < queue.length; i++) {
    queue[i] = null;
    }
    tail = head = -1;
    size = 0;
    }
    複製代碼
      完整的代碼以下:

複製代碼
/**

  • 隊列
    */
    public class MyQueue {

    /**

    • 隊列管道,當管道中存放的數據大於隊列的長度時將不會再offer數據,直至從隊列中poll數據後
      */
      private Object[] queue;
      //隊列的頭部,獲取數據時老是從頭部獲取
      private int head;
      //隊列尾部,push數據時老是從尾部添加
      private int tail;
      //隊列長度
      private int size;
      //數組中能存放數據的最大容量
      private final static int MAX_CAPACITY = 1<<30;
      //數組長度
      private int capacity;
      //最大下標
      private int maxIndex;

    public MyQueue(int initialCapacity){
    if (initialCapacity > MAX_CAPACITY)
    throw new OutOfMemoryError("initialCapacity too large");
    if (initialCapacity <= 0)
    throw new IndexOutOfBoundsException("initialCapacity must be more than zero");
    queue = new Object[initialCapacity];
    capacity = initialCapacity;
    maxIndex = initialCapacity - 1;
    head = tail = -1;
    size = 0;
    }
    public MyQueue(){
    queue = new Object[16];
    capacity = 16;
    head = tail = -1;
    size = 0;
    maxIndex = 15;
    }

    /**

    • 往隊列尾部添加數據
    • @param object 數據
      */
      public void offer(Object object){
      if (size >= capacity){
      System.out.println("queue's size more than or equal to array's capacity");
      return;
      }
      if (++tail > maxIndex){
      tail = 0;
      }
      queue[tail] = object;
      size++;
      }

    /**

    • 從隊列頭部拉出數據
    • @return 返回隊列的第一個數據
      */
      public Object poll(){
      if (size <= 0){
      System.out.println("the queue is null");
      return null;
      }
      if (++head > maxIndex){
      head = 0;
      }
      size--;
      Object old = queue[head];
      queue[head] = null;
      return old;
      }

    /**

    • 查看第一個數據
    • @return
      */
      public Object peek(){
      return queue[head];
      }

    /**

    • 隊列中存儲的數據量
    • @return
      */
      public int size(){
      return size;
      }

    /**

    • 隊列是否爲空
    • @return
      */
      public boolean isEmpty(){
      return size == 0;
      }

    /**

    • 清空隊列
      */
      public void clear(){
      for (int i = 0; i < queue.length; i++) {
      queue[i] = null;
      }
      tail = head = -1;
      size = 0;
      }

    @Overridepublic String toString() {if (size <= 0) return "{}";StringBuilder builder = new StringBuilder(size + 8);builder.append("{");int h = head;int count = 0;while (count < size){if (++h > maxIndex) h = 0;builder.append(queue[h]);builder.append(", ");count++;}return builder.substring(0,builder.length()-2) + "}";}}複製代碼

相關文章
相關標籤/搜索