It is again appropriate to create a new class for the implementation of the abstract data type queue. As before, we will use the power and simplicity of a list to build the internal representation of the queue.
We need to decide which end of the list to use as the tail and which to use as the head. The implementation shown in Listingย 3.12.1 assumes that the tail is at position 0 in the list. This allows us to use the add function on lists to add new elements to the tail of the queue. The remove operation can be used to remove the head element (the last element of the list). Recall that this also means that enqueue will be \(O(n)\) and dequeue will be \(O(1)\text{.}\)
class ListQueue<T> : QueueADT<T> {
/*
* The tail of the queue is at the beginning
* of the list; the head is the last item
*/
private val items = mutableListOf<T>()
/*
* Returns true if there are no items in the queue;
* false otherwise.
*/
override fun isEmpty(): Boolean {
return items.isEmpty()
}
/*
* Add an item to the tail of the queue
*/
override fun enqueue(item: T) {
items.add(0, item)
}
/*
* Remove the item at the head of the queue and return it.
* If the queue is empty, throws an exception.
*/
override fun dequeue(): T {
if (isEmpty()) {
throw NoSuchElementException("Queue is empty.")
}
return items.removeLast()
}
/*
* Return the item at the head of the queue, but do not remove it.
* If the queue is empty, throws an exception.
*/
override fun peek(): T {
if (isEmpty()) {
throw NoSuchElementException("Queue is empty.")
}
return items[items.count() - 1]
}
/*
* Returns the number of items in the queue.
*/
override fun size(): Int {
return items.count()
}
/*
* Convert to string as an array from tail to head
*/
override fun toString(): String {
return items.toString()
}
}
Listingย 3.12.2 shows the ListQueue class in action as we perform the sequence of operations from Sectionย 3.11.