Queues

advertisement
Queues (Continued)
•
•
•
•
•
Applications for a queue
Linked queue implementation
Array queue implementation
Circular array queue implementation
Reading L&C 3rd: 5.2-5.5, 8.3 2nd : 7.1-7.8
1
Applications for a Queue
• A queue can be used as an underlying
mechanism for many common applications
– Simulation of client-server operations
– Radix Sort
– Scheduling processes in an operating system
such as printer queues
2
Cycling through Code Keys
• The Caesar cipher is simple letter shifting
• Each letter is treated as its number 0-25 in
the alphabet and each letter is encoded as:
cipher value = (letter value + constant) % 26
• The message is decoded letter by letter:
letter value = (cipher value – constant) % 26
if (letter value < 0) letter value += 26
• Using the constant 7, the word “queue”
would be coded as “xblbl”
• Note: the word’s “pattern” is recognizable
3
Cycling through Code Keys
• The Caesar cipher is easy to solve because
there are only 26 possible “keys” to try
• It can be made harder by cycling through a
key set of values such as 3, 1, 7, 4, 2, 5
• We put that sequence of numbers in a queue
• As we encode each letter, we dequeue a
number for the constant and re-enqueue it cycling through the entire key set as many
times as needed for the message length
4
Cycling through Code Keys
• Using that queue of numbers as the constant
values, the word “queue” becomes “tvlyg”
• Note: the word’s “pattern” is not recognizable
• If we are encoding a message containing the
entire Unicode character set, we can omit the
modulo 26 operator as in the text book code
• See L&C, Listing 5.2
5
Ticket Counter Simulation
• See L&C Listing 5.3 and 5.4
• The simulation in this example sets up the
queue with customers arriving at regular
15 second intervals
• This is not the most meaningful analysis
because it doesn’t take into account the
typical variations in arrival rate
• One customer every 15 seconds could
mean 8 customers arriving at one time and
then 2 minutes with no arriving customers
6
Linked Queue Implementation
• We can use the same LinearNode class that
we used for LinkedStack implementation
• We use attribute names “front” and “rear” to
have a meaning consistent with a queue
front
rear
LinearNode next;
T element;
LinearNode next;
T element;
LinearNode next;
T element;
Object of type T
Object of type T
Object of type T
count
integer
null
7
Linked Queue Implementation
• enqueue – O(1)
public void enqueue (T element)
{
LinearNode<T> node = new LinearNode<T>(element);
if (isEmpty())
front = node;
else
rear.setNext(node);
rear = node;
count++;
}
• Note the difference between the enqueue
method and the Stack push method
8
Linked Queue Implementation
• dequeue – O(1)
public T dequeue () throws EmptyStackException
{
if (isEmpty()) throw new EmptyStackException();
T result = front.getElement();
front = front.getNext();
count--;
if (isEmpty())
rear = null;
return result;
}
• Note the difference between the dequeue
method and the stack pop method
9
Array Queue Implementation
• We can use an array of elements as a queue
• The front is implicitly index 0 and rear is the
index of next available element in the array
rear
T [ ] queue
Object of type T Object of type T
Object of type T
null
10
Array Queue Implementation
• enqueue – O(1)
public void enqueue (T element)
{
if (size() == queue.length)
expandCapacity();
stack [rear++] = element;
}
• expandCapacity is similar to private helper
method used in ArraySet and Stack classes
11
Array Queue Implementation
• dequeue() – O(n)
public T dequeue() throws EmptyStackException
{
if (isEmpty())
throw new EmptyStackException();
T result = queue[0];
rear--;
for (int scan = 0; scan < rear; scan++)
queue[scan] = queue[scan + 1];
queue[rear] = null;
return result;
}
12
Array Queue Implementation
• Notice that the dequeue is O(n) due to the
shifting of the elements in the array queue
after the 0th element has been copied out
• This introduces a potential performance
problem that we would like to avoid
• Using the 0th element of the array as the
rear of the queue doesn’t solve the problem
– just moves it to the enqueue operation
• With a better design, we can avoid it
13
Circular Array Queue Implementation
• This design eliminates the shifting of the
elements as part of the dequeue operation
• Commonly called circular queue
• We keep an integer for both the front and
rear of the queue in the array and never
shift the elements in the array
• When we increment either front or rear to
the length of the array, we do not expand
the capacity. We set them back to zero to
reuse the lower elements in the array
14
Circular Array Queue Implementation
N-1
0
N-2
front
1
3
2
3
rear
4
7
5
6
7
count
4
15
Circular Array Queue Implementation
front
N-2
N-1
0
N-2
1
2
rear
2
3
4
count
5
4
6
7
16
Circular Array Queue Implementation
• Method enqueue can not use:
rear++;
• Method dequeue can not use:
front++;
• To increment rear, enqueue must use:
rear = (rear + 1) % queue.length;
• To increment front, dequeue must use:
front = (front + 1) % queue.length;
17
Circular Array Queue Implementation
• When the front catches up to the rear (a
snake eating its own tail?), our code must
expand the capacity of the array (replacing
the original array with a larger one)
• When our code expands the capacity, it
must cycle through the original array from
front index to rear index value as it copies
from the smaller array to the larger array
• Then, it sets new values for front and rear
18
Download