There is an FAQ post on Piazza. Please read that post first if you have any questions.
- Implement a MinHeap
- Understand and analyze the working of Priority Queues
- Write JUnit tests to verify proper implementation
In this part of the assignment, you will implement a MinHeap and write JUnit tests to ensure that your implementation functions correctly.
Read the entire write-up before you start coding.
Download the starter code by cloning this repository.
+--PA 7
| +-- MinHeapInterface.java
| +-- PublicTester.java
| +-- MyMinHeap.java **Create this file**
| +-- MyPriorityQueue.java **Create this file**
| +-- MyAlgorithm.java **Create this file**
In this assignment, we provide a PublicTester.java
file that contains all the public test cases (visible on Gradescope) that we will use to test your MinMyHeap
and MyPriorityQueue
. We will not be grading your custom testers. We still encourage you to write your own tests to verify that your implementation follows the write-up specifications.
Your task: Implement a MinHeap. In the MyMinHeap.java
file, add the following:
Instance Variable | Description |
protected ArrayList<E> data
|
The underlying data structure of MyMinHeap. You must use 0-based indexing to store the heap (the root of the tree at index 0). |
In this file, you may import the following:
java.util.ArrayList
java.util.Collection
MyMinHeap
should have a constraint on the generic parameter E
such that E
implements Comparable<E>
so you can compare the elements. You should also implement MinHeapInterface<E>
.
Note: Do not add any other instance variables and do not add any static variables (other than private static final
variables to be used as constants).
Constructor | Description |
public MyMinHeap()
|
No-argument constructor that initializes data to an empty ArrayList .
|
public MyMinHeap(Collection<? extends E> collection)
|
Initializes a min-heap using the elements in collection .
NullPointerException if collection or any element in collection is null.
|
You should find these methods useful to implement the actual functionality of MyMinHeap and also to implement other helper methods.
Important Note: These helper methods are meant to be called inside the core methods and other helper methods. Therefore, you have some design choice in the helper methods for 1) whether you want to assume all arguments are in-bounds and 2) if you do not want to assume, then what out-of-bounds behavior you want. If you assume all arguments are in bounds, you must make sure that all arguments follow the assumptions before calling your helper method.
Note:
- In practice, these would be private methods, but for our assignment, they will be protected so that we can auto-grade your methods and provide feedback for them. To be clear, these methods are required.
- All tests assume that you use 0-based indexing to store the heap in the array.
Helper Method Name | Description |
protected void swap(int from, int to)
|
Swap the elements at from and to indices in data.
|
protected static int getParentIdx(int index)
|
Calculate and return the parent index of the parameter index .
|
protected static int getLeftChildIdx(int index)
|
Calculate and return the left child index of the parameter index.
|
protected static int getRightChildIdx(int index)
|
Calculate and return the right child index of the parameter index.
|
protected int getMinChildIdx(int index)
|
Return the index of the smaller child of the element at index . If the two children are equal, return the index of the left child. If the node at index is a leaf (has no children), return -1 .
|
protected void percolateUp(int index)
|
Percolate the element at index up until no heap properties are violated by this element (the heap properties will not be violated once this element's parent is not greater than it). Do this by swapping the element with its parent as needed.
|
protected void percolateDown(int index)
|
Percolate the element at index down until no heap properties are violated by this element (the heap properties will not be violated once this element is not greater than its children). If swapping is needed, always swap places with the smaller child. If both children are equal and swapping is needed, swap with the left child.
|
protected E deleteIndex(int index)
|
Remove the element at index from data and return it.
|
Method Name | Description |
public void insert(E element)
|
Add element to the end of the heap (so that it is the right-most element in the bottom-most level) and percolate only the inserted element up until no heap properties are violated (all fixes to the heap properties should be by this percolation).
Throw a The insertion explanation can be found in the Appendix |
public E getMin()
|
Return the root (this will be the smallest) element of the heap.
If the heap is empty, return null instead.
|
public E remove()
|
Remove and return the root (this will be the smallest) element in the heap. Use deleteIndex() helper method here.
If the heap is empty, return null instead.
|
public int size()
|
Return the number of elements in this min-heap. |
public void clear()
|
Clear out the entire heap (the heap should be empty after this call). |
In this part of the assignment, you will understand how a priority queue can be implemented using a min heap.
public class MyPriorityQueue<E extends Comparable<E>>
A priority queue is a queue where elements are sorted by their priority. Popping/dequeuing from the priority queue should always yield an element with the highest priority. In other words, elements with higher priority will be closer to the front of the priority queue.
Our MyPriorityQueue
implementation will be using a MyMinHeap
backend. Our underlying data structure is a min-heap, so smaller elements (as defined by compareTo()
) have higher priorities. The root node of the min-heap is the one with the highest priority and is also the smallest element in the min-heap.
protected MyMinHeap<E> heap;
- We will be using a single instance variable for our
MyPriorityQueue
. ThisMyMinHeap
will contain all information we need to keep track of our heap. You should only use theMyMinHeap
public methods in yourMyPriorityQueue
implementation. Do not directly accessheap.list
in your implementation ofMyPriorityQueue
(treat it as if it were a private instance variable). - Note: Do not add any other instance variables and do not add any static variables (other than
private static final
variables to be used as constants).
- This heap holds and sorts all elements for our priority queue. Since we are using our
MyMinHeap
to store our elements,null
is not allowed in this priority queue.
public MyPriorityQueue();
public MyPriorityQueue(Collection<? extends E> collection);
- This no-argument constructor initializes
heap
to be an emptyMyMinHeap
.
- You may import
java.util.Collection
- Throw a
NullPointerException
ifcollection
or any element incollection
isnull
. - Otherwise, this constructor initializes
heap
to contain the elements incollection
. Remember that we have already written a handy-dandy constructor forMyMinHeap
.
public void push(E element);
public E peek();
public E pop();
public int getLength();
public void clear();
- Throw a
NullPointerException
and do not add to the priority queue ifelement
isnull
. - Otherwise, add
element
to this priority queue.heap
should be fixed accordingly.
- Return the element with the highest priority. Remember that this should be whichever element our min-heap says is the smallest element.
- If the priority queue is empty, return
null
instead.
- Remove and return the element with the highest priority. Remember that this should be whichever element our min-heap says is the smallest element.
heap
should be fixed accordingly. - If the priority queue is empty, return
null
(and do no removal) instead.
- Return the number of elements in the priority queue.
- Clear out the entire priority queue (the priority queue should be empty after this call).
heap
should be an emptyMyMinHeap
, notnull
, after this function is completed.
In this part of the assignment, you will use your implementation of a priority queue to run experiments on a list of atoms.
Your task: Create a a new class called MyAlgorithm
in a new file called MyAlgorithm.java
.
In this file, you may import the following:
java.util.ArrayList
Implement the following method:
- You are given a list of atoms where each atom is denoted by its type (i.e., “1” denotes an atom of type 1). In each experiment, we select the two atoms with the smallest types. If their types are the same, they will react by combining into a new atom whose type is equal to the sum of the types of the initial atoms (stable reaction). If their types differ, the reaction will be unstable and the atoms will combine into a new atom whose type is equal to the absolute difference between the types of the initial atoms. These experiments are to continue until there is one final atom.
- Return the type of the last remaining atom.
- Throw a
NullPointerException
ifatoms
isnull
. - You can assume:
- All given atom types are positive.
- There is no guarantee on the ordering of
atoms
. - The sum of two atoms will never exceed
Integer.MAX_VALUE
. - If
atoms
is not null, there is at least one atom inatoms
.
- You are required to use a MyPriorityQueue object in your implementation. Your algorithm must run in O(nlogn) time for full-credit.
- The tests associated with
lastAtom()
will account for about 4% of your autograder score.
For example: Given a list of atoms [1, 1, 3]
:
- The first experiment will select atom 1 and 1 to produce an atom of type 2. The list of atoms is now
[2, 3]
. - The second experiment will select atom 2 and 3 to produce an atom of type 1. The list of atoms is now
[1]
. - There is only one atom remaining, so the type of the last atom, which is
1
, is returned.
Coding style is an important part of ensuring readability and maintainability of your code. We will grade your code style in all submitted code files according to the style guidelines. Namely, there are a few things you must have in each file/class/method:
- File header
- Class header
- Method header(s)
- Inline comments
- Proper indentation
- Descriptive variable names
- No magic numbers (Exception: Magic numbers can be used for testing.)
- Reasonably short methods (if you have implemented each method according to the specification in this write-up, you’re fine). This is not enforced as strictly.
- Lines shorter than 80 characters
- Javadoc conventions (
@param
,@return
tags,/** comments */
, etc.)
A full style guide can be found here and a sample styled file can be found here. If you need any clarifications, feel free to ask on Piazza.
Turning in your code
Submit all of the following files to Gradescope by May 23rd, 2024 @ 11:59 PM PST
- MyMinHeap.java
- MyPriorityQueue.java
- MyAlgorithm.java
Important: Even if your code does not pass all the tests, you will still be able to submit your homework to receive partial points for the tests that you passed. Make sure your code compiles in order to receive partial credit.
Running the tester on UNIX based systems (including a mac):
- Compile:
javac -cp ../libs/junit-4.13.2.jar:../libs/hamcrest-2.2.jar:. PublicTester.java
- Execute:
java -cp ../libs/junit-4.13.2.jar:../libs/hamcrest-2.2.jar:. org.junit.runner.JUnitCore PublicTester
Running the tester on Windows systems:
- Compile:
javac -cp ".;..\libs\junit-4.13.2.jar;..\libs\hamcrest-2.2.jar" PublicTester.java
- Execute:
java -cp ".;..\libs\junit-4.13.2.jar;..\libs\hamcrest-2.2.jar" org.junit.runner.JUnitCore PublicTester
deleteIndex() Figure 0: Begin deletion at index 0, which currently contains the element A
.
deleteIndex() Figure 1: A
is removed and set aside to be returned. The last element in the heap, G
, is moved to the old position to replace it. We then begin the process of percolating G
down. There is a violation because the element G
is greater than the element D
. Since both children are equal, we swap with the left child.
deleteIndex() Figure 2: G
has now swapped with D
, but there is still a violation because G
is greater than E
, so we will swap those two.
deleteIndex() Figure 3: G
has now swapped with E
and there are no more heap violations, thus ending the percolation process.We have completed the deletion process and will return the original deleted element, A
.
insert() Figure 0: Begin insertion of element D
.
insert() Figure 1: Add D
to the end of the min-heap.
insert() Figure 2: There is a violation since D
is less than its parent G
, so we will swap those.
insert() Figure 3: D
has now swapped with 'G' and there are no more heap violations, thus ending the percolation process. We have completed the insertion process.