1. 程式人生 > >數據結構 - 循環隊列

數據結構 - 循環隊列

interface i++ obj inter 變量 數組實現 需要 數據 illegal

循環隊列

  在基於數組的隊列中我們發現,在移出隊首元素時時間復雜度為O(n),為了解決這個問題,我們引出了循環隊列。

  

  實現原理:基於數組實現,以數組頭為隊首,以數組尾為隊尾, 此時多出一個front變量指向隊首,當隊首元素移出時,基於數組實現的隊列中的元素不需要全部向前移動一個位置,只需要指向下一個元素。

   實現循環隊列的源碼如下:

package queue;

public interface Queue<E> {

public void enqueue(E e);

public E dequeue();

public E getFront();

public int getSize();

public boolean isEmpty();
}

package queue;

/**
* 循環隊列
*
* @author DELL
*
* @param <E>
*/
public class LoopQueue<E> implements Queue<E> {

private E[] data;
private int front; //指向隊首的索引
private int tail; //指向隊尾的索引
private int size; //隊列中元素的個數

/**
* 構造方法
* @param capacity
* 隊列的容量
*/
public LoopQueue(int capacity){
data = (E[])new Object[capacity];
front = 0;
tail = 0;
size = 0;
}

/**
* 無參構造方法,默認容量為0
*/
public LoopQueue(){
this(10);
}

/**
* 獲得隊列的容量
* @return
*/
public int getCapacity(){
return data.length;
}

/**
* 判斷隊列是否為空
*/
@Override
public boolean isEmpty() {
return size == 0;
}

/**
* 獲取隊列裏元素的個數
*/
@Override
public int getSize() {
return size;
}

/**
* 向隊列的隊尾添加一個元素
*/
@Override
public void enqueue(E e) {

if (size == data.length) {
resize(data.length * 2);
}
data[tail] = e;
tail = (tail + 1) % data.length;
size++;
}

/**
* 將隊首的元素移出並返回
*/
@Override
public E dequeue() {
if (isEmpty()) {
throw new IllegalArgumentException("Cannot dequeue from an emtry queue.");
}

E res = data[front];
data[front] = null;
front = (front + 1) % data.length;
size--;

if(size == data.length / 4 && data.length / 2 != 0){
resize(data.length / 2);
}
return res;
}

/**
* 瞧一眼隊首的元素
*/
@Override
public E getFront() {
if (isEmpty()) {
throw new IllegalArgumentException("Queue is empty.");
}
return data[front];
}

/**
* 重置隊列的容量
* @param newCapacity
*/
private void resize(int newCapacity) {
E[] newData = (E[])new Object[newCapacity];
for(int i = 0; i < size; i++){
newData[i] = data[(i + front) % data.length];
}

tail = data.length;
data = newData;
front = 0;



}

@Override
public String toString(){
StringBuilder res = new StringBuilder();

res.append(String.format("capacity = %d size = %d\n", getCapacity(),getSize()));
res.append("Front: ");
res.append(‘[‘);
int j = front; //遍歷隊列時記錄指向隊首的索引
for (int i = 0; i < size; i++) {
res.append(data[j]);
if (i != getSize() - 1) {
res.append(", ");
}
j = (j + 1) % data.length;
}
res.append(‘]‘);
res.append("tail");

return res.toString();
}
}

經典的實現循環隊列實現中只用了front和tail變量,一個指向隊首和一個指向隊尾,size變量可以通過這兩個變量推導出來,這種實現方式需要浪費一個空間,

當(front == tail時隊列為空,(tail+1) % data.length == front隊列滿)。

循環隊列的時間復雜度的分析:

  *void enqueue(E e) : O(1) 均攤

  *E dequeue() : O(1) 均攤

  *E getFront() : O(1)

  *E getSize() : O(1)

  *boolean isEmpty() : O(1)

數據結構 - 循環隊列