The goal of this lab is to learn the specification, implementation, and uses of the priority queue abstract data type.
Refer to the pre-project reading to review introductory information about priority queues and heaps.
I am providing a bunch of code for you.
Copy all the files from the proj2
folder in the
course public directory.
cp -r ~tvandrun/Public/cs345/proj2/. .
This will give you three packages, adt
,
pq
, and test
.
Make a new Eclipse project, selecting the folder containing those
three packages.
Heap
class The abstract class Heap
contains the basic
functionality for a heap that you will extend to make a priority queue.
It already has an internal array as an instance variable (plus
a heapSize
variable that tells how much of the array is in use)
and helper methods
to calculate the children and parent from a given index.
What you need to provide for the heap is the implementation for a helper method
heapify()
, which we call on a heap given a node identified
by its index.
heapify()
enforces the heap property on the tree
rooted at the given index--- under certain assumptions.
This method can be used to set up the array so that it satisfies
the heap property, or it can be used to fix up the heap if some other
operations result in a violation of the heap property.
This method assumes that both subtrees of the given node satisfy
the heap property (they are greater than their children, etc), but
the given node might violate it; it might be smaller than
one of its children.
heapify()
fixes up the subtree rooted at the given
node by pushing it down until there no longer is a violation.
The following illustrates the process needed to fix up the heap
if 19 were replaced with 10.
Study this example and figure out what's going on.
Write this method.
Then you can test it using the JUnit test in
test.TestHeapify
.
Before we implement priority queues, we'll explore a bonus application of heaps: A nifty and very efficient sorting algorithm, called heapsort.
It works in two steps. First, given an array to sort, we rearrange the array so that it is a heap. (The result is that the maxiumum element must be the root, at position 0.) Then we take that maximum element (the root) and swap it with the last element in the heap (the rightmost leaf in the last level). Then we decrease the size of the heap by one, so that the largest element (now at the end of the array) "doesn't count" any more. Consider the following illustration Now 19 is correctly placed in the array, but we no longer have a heap
because 5 is in violation.
So we call heapify()
with the root to fix up the
violation incurred.
We repeat this whole process (swapping the root with the last
leaf, then heapifying) until the heap is "empty"-- although the array is still full,
it's just that none of it is counted as part of the heap.
The method sort()
in class HeapSorter
is static, but it instantiates subclass HeapSorter
of Heap
to store its data.
Complete the constructor of this class so that it initially converts
an array into a heap (using repeated and strategic calls to heapify()
---
think about this carefully)
and write the code for the sort()
method, using the
strategy described above.
The JUnit testcase test.TestHeapSort
will
test this, but I have also included a test program that you can
run from the commandline that might give more useful
debugging information if you have a problem.
Open it to see how it works. By running
java pq.Test heapsort
it will sort an array and print out the sorted version. The correct result is
11 22 33 44 55 66 77 88 99
PriorityQueue
Now we will implement the priority queue class.
This also is an extension of the Heap
class.
The isEmpty()
, isFull()
, and
max()
methods are easy and already completed for you.
What remains is code for adding and removing elements.
First, adding an element. Our strategy is simply to place it in the next available position in the array and increment the size of the heap. This may result in a violation of the heap property--the new element may be larger than its parent. If that happens, then we move the new element up the tree until it is in an appropriate place. Consider the following illustration of adding the element 16:
Next, removing the maximum element. Our strategy is to copy the last element in the heap to the first position in the array and then decrease the size of the heap, as illustrated here.
Then use heapify()
to correct the violation incurred.
Implement these two methods, then test it using
test.TestPQ
.
You also can test it from the command line using
java pq.Test pq
.
The correct result is
33 99 88 77 66 55 44 22 11
To take us back around to stacks and queues, consider how a priority queue can be used to implement a queue: As each element is entered into the priority queue, it is assigned a priority based on its time of arrival. This implies that the element is distinct from its priority---different from the examples we've seen so far where the element is an integer which is used as its priority.
To get around this, the class PQQueue
has two instance
variables--- a PriorityQueue
and a HashMap
.
The HashMap
associates priorities with elements, and
the PriorityQueue
stores priorities.
Consider this scenario. An element, say 3, is entered into the queue.
It is assigned a priority 15.
Thus we insert 15 into the PriorityQueue
and associate 15 with
3 in the HashMap
.
Sometime later, removeFront()
is called on the Queue
,
which in turn calls extractMax()
on the PriorityQueue
,
which returns 15.
We then lookup 15 in the HashMap
and find 3;
3 then is the value returned from removeFront()
.
The real trick to all this is determining how to assign priorities.
Implement what's left in the PQQueue
class,
and test it using test.TestQueue
.
You can also use java pq.Test queue
.
The correct result is
33 22 66 99 11 88 55 77 44
Finally, do the same thing as in the previous section, but implement
a stack (PQStack
).
The only real difference is how you assign priorities.
Test using test.TestStack
and java Test stack
.
The correct result is
22 11 77 44 55 88 99 66 33
Copy the files you modified to a turn-in folder:
cp (filename) /cslab.all/ubuntu/cs345/turnin/(your id)/proj2
Due Friday, Feb 6, 5:00 pm. Late days may not be applied to this project.