Generic queues
1
Queue
example of a queue
2
Front and back of a queue
front back
3
Queue Operations
classically, queues only support two operations
1. enqueue
add to the back of the queue
2. dequeue
remove from the front of the queue
error to dequeue an empty queue
4
Queue Optional Operations
optional operations
1. size
number of elements in the queue
2. isEmpty
is the queue empty?
3. peek
get the front element (without removing it)
4. contains
find the position of a specified element in the queue
5
Enqueue
1. q.enqueue("A")
2. q.enqueue("B")
3. q.enqueue("C")
4. q.enqueue("D")
5. q.enqueue("E")
A B C D E
F B B B B
B
6
Dequeue
1. String s = q.dequeue()
A B C D E
F B
7
Dequeue
1. String s = q.dequeue()
2. s = q.dequeue()
B C D E
F B
8
Dequeue
1. String s = q.dequeue()
2. s = q.dequeue()
3. s = q.dequeue()
C D E
F B
9
Dequeue
1. String s = q.dequeue()
2. s = q.dequeue()
3. s = q.dequeue()
4. s = q.dequeue()
D E
F B
10
Dequeue
1. String s = q.dequeue()
2. s = q.dequeue()
3. s = q.dequeue()
4. s = q.dequeue()
5. s = q.dequeue()
B
11
FIFO
queue is a First-In-First-Out (FIFO) data structure
the first element enqueued in the queue is the first element
that can be accessed from the queue
12
Applications
queues are used widely in computer science and
computer engineering
online customer queues
web servers use queues to service requests
operating systems use queues to distribute resources
printer, disk, CPU queues
network devices use queues to determine which packets to
service
breadth-first search
https://en.wikipedia.org/wiki/Queueing_theory
13
Queue interface
public interface Queue<E> {
public int size();
default boolean isEmpty() {
return this.size() == 0;
}
public void enqueue(E elem);
public E dequeue();
public E front(); // returns front element
public E back(); // returns back element
}
14
Implementation with List
a queue implementation using a list is similar to that
for a stack except that dequeue removes the element
at the front of the list
15
import java.util.List;
import java.util.ArrayList;
public class ListQueue<E> implements Queue<E> {
private List<E> q;
public ListQueue() {
this.q = new ArrayList<>();
}
@Override
public int size() {
return this.q.size();
}
@Override
public void enqueue(E elem) {
this.q.add(elem);
}
16
private void throwIfEmpty() {
if (this.isEmpty()) {
throw new RuntimeException("empty queue");
}
}
@Override
public E dequeue() {
this.throwIfEmpty();
return this.q.remove(0);
}
Remove from front of an array-
Remove from front of an array-
based list is in
based list is in
17
@Override
public E front() {
this.throwIfEmpty();
return this.q.get(0);
}
@Override
public E back() {
this.throwIfEmpty();
return this.q.get(this.q.size() - 1);
}
@Override
public String toString() {
return this.q.toString();
}
}
18
Implementation with an array
the fact that removal and additions occur at different
ends of the queue make an array-based
implementation somewhat tricky
we use 4 fields:
Field name Purpose
arr array for the elements of the queue
size number of elements in the queue
front array index of element currently at the front of the queue
back array index of element currently at the back of the queue
19
New empty queue
20
enqueue algorithm
enqueueing an element is similar to pushing an
element onto the top of a stack
1. if arr[length] == size, then make a new array
with greater capacity and copy the existing elements
into the new array
2. move back one position to the right
3. set the element at arr[back] to the enqueued
element
21
After one enqueue
22
After another enqueue
23
After another enqueue
24
After five enqueue operations
25
dequeue algorithm
1. elem = arr[front]
2. arr[front] = null
3. front moves one position to the right
4. return elem
26
After one dequeue
27
After two dequeue operations
28
After four dequeue operations
29
After five dequeue operations
back is one less than front in this empty queue, but this
is not a reliable indicator of an empty queue
30
After one enqueue operation
31
After ten more enqueue operations
32
After one more enqueue operation
back wraps around to the front of the array
back can be less than front in a non-empty queue
33
Example of a full queue
back is one less than front in this full queue (same as in
the previous empty queue example)
34
After eleven more dequeue operations
35
After one more dequeue operation
front wraps around to the front of the array
36
Queue as a circular array
front moves
clockwise during
dequeue
back moves
clockwise during
enqueue
37
public class ArrayQueue<E> implements Queue<E> {
// the default capacity of the queue
private static final int DEFAULT_CAPACITY = 16;
// the array that stores the queue
private Object[] arr;
// the index of the element at the front of the queue
private int front;
// the index of the element at the back of the queue
private int back;
// the number of elements in the queue
private int size;
38
public ArrayQueue() {
this.arr = new Object[ArrayQueue.DEFAULT_CAPACITY];
this.front = 0;
this.back = -1;
this.size = 0;
}
public ArrayQueue(ArrayQueue<E> other) {
this.arr = Arrays.copyOf(other.arr, other.arr.length);
this.front = other.front;
this.back = other.back;
this.size = other.size;
}
39
@Override
public E front() {
if (this.isEmpty()) {
throw new RuntimeException("no front element");
}
return (E) this.arr[this.front];
}
@Override
public E back() {
if (this.isEmpty()) {
throw new RuntimeException("no back element");
}
return (E) this.arr[this.back];
}
40
@Override
public E dequeue() {
if (this.isEmpty()) {
throw new RuntimeException("dequeued an empty queue");
}
Object elem = this.arr[this.front];
// null out the value stored in the array
this.arr[this.front] = null;
this.front = (this.front + 1) % this.arr.length;
this.size--;
return (E) elem;
}
41
Resizing the array
resizing the internal array when it reaches its capacity
is slightly more complicated than for a stack because
the order of the elements is not necessarily from the
beginning of the array to the end
42
Naïve array resizing
resizing the internal array when it reaches its capacity
is slightly more complicated than for a stack
oops, elements are
out of order
starting from here
43
Correct array resizing
one way to correctly copy the elements from the old
array is to put the front element of the queue at index
0 of the new array
44
@Override
public void enqueue(E elem) {
if (this.size == this.arr.length) {
Object[] tmp = new Object[this.arr.length * 2];
for (int i = 0; i < this.size; i++) {
tmp[i] = this.arr[(this.front + i) %
this.arr.length];
}
this.arr = tmp;
this.front = 0;
this.back = this.size - 1;
}
this.back = (this.back + 1) % this.arr.length;
this.arr[this.back] = elem;
this.size++;
}
45
Exercises for the student
implement the following copy constructor without
using a temporary collection
public ArrayQueue(Queue<E> other)
implement equals where a Queue<E> instance can be
equal to an ArrayQueue<E> instance
46