28 Generics 2
28 Generics 2
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();
public E dequeue();
15
import java.util.List;
import java.util.ArrayList;
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);
}
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
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
33
Example of a full queue
34
After eleven more dequeue operations
35
After one more dequeue operation
36
Queue as a circular array
front moves
clockwise during
dequeue
back moves
clockwise during
enqueue
37
public class ArrayQueue<E> implements Queue<E> {
38
public ArrayQueue() {
this.arr = new Object[ArrayQueue.DEFAULT_CAPACITY];
this.front = 0;
this.back = -1;
this.size = 0;
}
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];
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
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
46