A heap is the best choice of data structure when we need quick access to the largest or smallest value in a queue. Some applications are:
Discuss in small groups:
ER is empty
4 patients waiting.
Next patient to be seen: Patient severity: 5, arrival time: 09:41:30.597749
Seeing patients:
Patient severity: 5, arrival time: 09:41:30.597749
Patient severity: 4, arrival time: 09:41:30.588172
Patient severity: 2, arrival time: 09:41:30.597763
Patient severity: 1, arrival time: 09:41:30.597723
public class RunER {
public static void main(String[] args) {
Triage er = new Triage();
System.out.println(er);
er.insert(new Patient(4));
er.insert(new Patient(1));
er.insert(new Patient(5));
er.insert(new Patient(2));
System.out.println(er);
System.out.println("Seeing patients: ");
while (!er.isEmpty()) {
System.out.println(er.seePatient());
}
}
}import java.time.LocalTime;
import java.time.Duration;
public class Patient implements Comparable<Patient> {
private int severity;
private LocalTime arrivalTime;
public Patient(int severity) {
if (!validSeverity(severity)) throw new RuntimeException("severity must be 1-5");
this.severity = severity;
arrivalTime = LocalTime.now();
}
private boolean validSeverity(int severity) {
return severity >= 1 && severity <= 5;
}
public int getSeverity() { return severity; }
public boolean setSeverity(int severity) {
if (!validSeverity(severity)) return false;
this.severity = severity;
return true;
}
public LocalTime getArrivalTime() { return arrivalTime; }
public double getWaitTimeMinutes() {
Duration wait = Duration.between(arrivalTime,LocalTime.now());
return wait.toMinutes();
}
public int compareTo(Patient other) {
if (other == null) return 1;
if (this == other) return 0;
return this.severity - other.severity;
}
public String toString() {
String out = "Patient severity: " + severity;
out += ", arrival time: " + arrivalTime;
return out;
}
}public class Triage {
private Patient[] patients;
private int patientCount = 0;
private int erCapacity = 100;
public Triage() {
patients = new Patient[erCapacity];
}
public int getPatientCount() {
return patientCount;
}
private int parent(int i) { return (i - 1) / 2; }
private int leftChild(int i) { return 2 * i + 1; }
private int rightChild(int i){ return 2 * i + 2; }
private boolean hasParent(int i) { return i > 0; }
private boolean hasLeftChild(int i) { return leftChild(i) < patientCount; }
private boolean hasRightChild(int i) { return rightChild(i) < patientCount; }
public boolean isEmpty() { return patientCount == 0; }
// Returns the minimum element (root) without removing it — O(1)
public Patient nextPatientInfo() {
if (isEmpty()) throw new IllegalStateException("ER is empty");
return patients[0];
}
// Inserts a new value and restores the heap property — O(log n)
public void insert(Patient value) {
if (patientCount == erCapacity) throw new IllegalStateException("ER is full");
patients[patientCount] = value; // place at the next open spot
patientCount++;
bubbleUp(patientCount - 1); // restore heap property upward
}
// Removes and returns the minimum element — O(log n)
public Patient seePatient() {
if (isEmpty()) throw new IllegalStateException("ER is empty");
Patient min = patients[0];
patients[0] = patients[patientCount - 1];
patientCount--;
bubbleDown(0);
return min;
}
private void swap(int a, int b) {
Patient temp = patients[a];
patients[a] = patients[b];
patients[b] = temp;
}
private void bubbleUp(int i) {
while (hasParent(i) && patients[i].compareTo(patients[parent(i)]) > 0) {
swap(i, parent(i));
i = parent(i);
}
}
// used after pop min
private void bubbleDown(int i) {
while (hasLeftChild(i)) {
int largerChild = leftChild(i);
// find the smaller of the two children
if (hasRightChild(i) && patients[rightChild(i)].compareTo(patients[leftChild(i)]) > 0) {
largerChild = rightChild(i);
}
if (patients[i].compareTo(patients[largerChild]) >= 0) return;
swap(i, largerChild);
i = largerChild;
}
}
public String toString() {
if (isEmpty()) return "ER is empty";
String out = "Patient list:\n";
for (int i = 0; i < patientCount; i++) out += patients[i] + "\n";
out += "\nNext patient to be seen: " + nextPatientInfo().toString();
return out.trim();
}
}Heap Sort achieves a time complexity of \(O(n \log n)\)
Algorithm:
i is used as argument in bubbleDown
for (int i = n / 2 - 1; i >= 0; i--) bubbleDown(arr, n, i);
Note bubbleDown takes an array as argument because we are writing static methods.
for (int i = n - 1; i > 0; i--) {
swap(arr, 0, i);
bubbleDown(arr, i, 0);
}
Note swap and bubbleDown take an array as argument because we are writing static methods.
Test your code:
public static void main(String[] args) {
int[] arr = {12, 11, 13, 5, 6, 7, 0, 30, 2, 67};
sort(arr);
System.out.println(java.util.Arrays.toString(arr));
// [0, 2, 5, 6, 7, 11, 12, 13, 30, 67]
}
Submit your HeapSort.java to gradescope.
public class HeapSort {
private static void swap(int[] arr, int indexOne, int indexTwo) {
int temp = arr[indexOne];
arr[indexOne] = arr[indexTwo];
arr[indexTwo] = temp;
}
public static void sort(int[] arr) {
int n = arr.length;
// build max heap -- start from the last non-leaf node (n/2 - 1)
for (int i = n / 2 - 1; i >= 0; i--)
bubbleDown(arr, n, i);
// extract elements from heap one by one
for (int i = n - 1; i > 0; i--) { // backwards to ignore the end of the array
// move current root (max) to end
swap(arr,0, i);
// heapify the reduced heap
bubbleDown(arr, i, 0);
}
}
// recursive, heapify subtree rooted at index i, heap size n
private static void bubbleDown(int[] arr, int n, int i) {
int largest = i;
int left = 2 * i + 1; // get left child index
int right = 2 * i + 2; // get right child index
// if there's a left child, and left child is larger, make largest the left
if (left < n && arr[left] > arr[largest])
largest = left;
// if there's a right child, and the right child is larger, make largest the right
if (right < n && arr[right] > arr[largest])
largest = right;
// if parent is not the largest
if (largest != i) {
swap(arr, i, largest);
bubbleDown(arr, n, largest);
}
}
public static void main(String[] args) {
int[] arr = {12, 11, 13, 5, 6, 7, 0, 30, 2, 67};
sort(arr);
System.out.println(java.util.Arrays.toString(arr));
}
}Disadvantage: Heap sort is unstable.