【学习笔记】Queues

121 阅读1分钟

A queue is a collection of objects that are inserted and removed according to the first-in, first-out (FIFO) principle.
By convention, we assume that elements added to the queue can have arbitrary type and that a newly created queue is empty.

Queue Interface

public interface Queue<E> {
	int size(); 
	boolean isEmpty(); 
	// Inserts an element at the rear of the queue
	void enqueue(E e); 
	// Returns, but does not remove, the first element of the queue (null if empty)
	E first();  
	// Removes and returns the first element of the queue (null if empty)
	E dequeue(); 
}

Array-based Queue Implementation

/* Implementation of the queue ADT using a fixed-length array. */
public class ArrayQueue<E> implements Queue<E> {
	private E[] data; 
	private int f = 0;      // index of the front element
	private int sz = 0;     // current number of elements (size) 

	// constructors 
	public ArrayQueue() { this(CAPACITY); } 
	public ArrayQueue(int capacity) {
		data = (E[]) new Object[capacity]; 
	} 

	// methods
	public int size() { return sz; } 
	public boolean isEmpty() { return (sz == 0); } 

	// insert an element at the rear of the queue 
	public void enqueue(E e) throws IllegalStateException {
		if(sz == data.length) throw new IllegalStateException("Queue is full"); 
		int avail = (f + sz) % data.length; 
		data[avail] = e; 
		sz++; 
	}

	// returns, but does not remove, the first element of the queue (null if empty) 
	public E first() {
		if(isEmpty()) return null; 
		return data[f]; 
	} 

	// removes and returns the first element of the queue (null if empty) 
	public E dequeue() {
		if(isEmpty()) return null; 
		E answer = data[f]; 
		data[f] = null;        // deference to help garbage collection
		f = (f + 1) % data.length; 
		sz--; 
		return answer; 
	}
}

enqueue(E e)分析

public void enqueue(E e) throws IllegalStateException {
        if(sz == data.length) throw new IllegalStateException("Queue is full"); 
        int avail = (f + sz) % data.length; 
        data[avail] = e; 
        sz++; 
}

新元素能插入的前提是Queue还没有装满,也就是说sz < data.length
假设f = 11, sz = 10, data.length = 20
现在我们要在这个Queue的末尾插入一个新元素E e

avail = (11 + 10) % 20    // 1  
data[1] = e;   
sz++;    // 11

dequeue()分析

public E dequeue() {
        if(isEmpty()) return null; 
        E answer = data[f]; 
        data[f] = null;        // deference to help garbage collection
        f = (f + 1) % data.length; 
        sz--; 
        return answer; 
}

f的范围就是[0, data.length-1]

这种实现方法的好处是,dequeue的操作,在移除Queue第一个元素之后,不需要通过一个for loop把后面的元素全部向前挪动一位,因为使用for loop会降低dequeue操作的效率。

Implementing A Queue with A Singly Linked List

public class LinkedQueue<E> implements Queue<E> {
	private SinglyLinkedList<E> list = new SinglyLinkedList<>();   // an empty list
	public LinkedQueue() {}   // new queue relies on the initially empty list 
	public int size() { return list.size(); } 
	public boolean isEmpty() { return list.isEmpty(); } 
	public void enqueue(E element) { list.addLast(element); } 
	public E first() { return list.first(); } 
	public E dequeue() {return list.removeFirst(); }
}

A Circular Queue

待补充