1. 程式人生 > 實用技巧 >06-java實現佇列

06-java實現佇列

06-java實現佇列

本人git https://github.com/bigeyes-debug/Algorithm

一丶佇列

  • 佇列是特殊的線性結構,只能在頭尾兩端操作
  • 隊尾入隊,隊頭出隊,
  • FIFO
  • 佇列可以用動態陣列和雙向連結串列實現
  • 優先使用雙向連結串列,主要在頭尾進行操作

二丶佇列的介面設計(和之前的線性結構類似)

public class Queue<E> {
    // 使用雙向連結串列實現佇列
    private List<E> list = new LinkedList<>();
    // 元素的數量
    public int size();
    // 是否為空
    public boolean isEmpty();
    // 入隊
    public void enQueue(E element);
    // 出隊
    public E deQueue();
    // 獲取佇列的頭元素
    public E front();
}

三丶佇列的實現

public class Queue<E> {
    private List<E> list = new LinkedList<>();
	
    public int size() {
        return list.size();
    }

    public boolean isEmpty() {
        return list.isEmpty();
    }

    public void enQueue(E element) {
        list.add(element);
    }

    public E deQueue() {
        return list.remove(0);
    }

    public E front() {
        return list.get(0);
    }
}

四丶雙端佇列

  • 雙端佇列,頭可以入隊出隊,尾可以入隊出隊

五、雙端佇列的介面設計&實現

public class Deque<E> {
    private List<E> list = new LinkedList<>();
	
    // 元素的數量
    public int size() {
        return list.size();
    }
    // 是否為空
    public boolean isEmpty() {
        return list.isEmpty();
    }
    // 從隊頭出隊
    public E deQueueFront() {
        return list.remove(0);
    }
    // 從隊頭入隊
    public void enQueueFront(E element) {
        list.add(0, element);
    }
    // 從隊尾入隊
    public void enQueueRear(E element) {
        list.add(element);
    }
    // 從隊尾出隊
    public E deQueueRear() {
        return list.remove(list.size() - 1);
    }
    // 獲取佇列的頭元素
    public E front() {
        return list.get(0);
    }
    // 獲取佇列的尾元素
    public E rear() {
        return list.get(list.size() - 1);
    }
}

六丶迴圈佇列

  • 佇列內部實現也可以用動態陣列實現,並且將各項介面優化到O(1)的時間複雜度, 這個用陣列實現並優化之後的佇列就叫做: 迴圈佇列。

七、迴圈佇列的介面設計

public class CircleQueue<E> {
    // 記錄第0個元素的索引
    private int front;
    // 當前佇列儲存的元素個數
    private int size;
    // 用來儲存元素的陣列
    private E[] elements;
    // 當前佇列儲存的元素數量
    public int size();
    // 當前佇列是否為空
    public boolean isEmpty();
    // 入隊
    public void enQueue(E element);
    // 出隊
    public E deQueue();
    // 檢視索引為0的元素
    public E front();
}

八丶迴圈佇列的實現

3.1 構造方法

public class ArrayList<E> {
    private E[] elements;
    // 設定elements陣列預設的初始化空間
    private static final int DEFAULT_CAPACITY = 10;
	
    public CircleQueue() {
        elements = (E[]) new Object[DEFAULT_CAPACITY];
    }
}

3.2 入隊

  • 入隊前需要考慮兩個問題:佇列是否需要擴容和計算入隊實際索引。

3.2.1 動態擴容

動態陣列的擴容方法拿來直接用即可

private void ensureCapacity(int capacity) {
    int oldCapacity = elements.length;
    if (oldCapacity >= capacity) return;
		
    // 新容量為舊容量的1.5倍
    int newCapacity = oldCapacity + (oldCapacity >> 1); //位運算
    E[] newElements = (E[]) new Object[newCapacity];
    for (int i = 0; i < size; i++) {
        newElements[i] = elements[index(i)];
    }
    elements = newElements;
		
    // 重置front
    front = 0;
}

3.2.2 索引計算

  • 獲取實際索引公式 (front+index)%elements.length;
     private int index(int index) {
          return (front +index)%elements.length;
     }

入隊程式碼

public void enQueue(E element) {
    // 陣列擴容判斷
    ensureCapacity(size + 1);
    // 索引計算,並賦值
    elements[index(size)] = element;
    // size加一
    size++;
}

3.3 出隊

  • 一定要更新front指標,一定不要忘
public E deQueue() {
    // 獲取出隊元素
    E frontElement = elements[front];
    // 將索引位置致空
    elements[front] = null;
    // 更新font
    front = index(1);
    // size減一
    size--;
    // 返回出隊元素
    return frontElement;
}