diff --git a/DataStructuresPractice/BinaryHeap.java b/DataStructuresPractice/BinaryHeap.java index 593d7e1b..3de58f77 100644 --- a/DataStructuresPractice/BinaryHeap.java +++ b/DataStructuresPractice/BinaryHeap.java @@ -1,20 +1,143 @@ -public class BinaryHeap { - private DynamicResizingArray array = new DynamicResizingArray(); +import java.util.Arrays; + + +public class BinaryHeap> { + private DynamicResizingArray array; public BinaryHeap() { - // nothing + array = new DynamicResizingArray(); + } + + public BinaryHeap(T[] items) { + array = new DynamicResizingArray(); + for (int i = 0; i < items.length; i++) { + T item = items[i]; + // System.out.printf("inserting %d\n", item); + this.insert(item); + System.out.println("array is now:"); + print(); + } + } + + public int getLength() { + return array.length; // NOT array.array.length, which is the capacity (also array.capacity) } public T extractMax() { - return null; // TODO + // extract root, move last item to root position + // then rebalance by swapping item with largest child until heap property is satisfied + T item = array.extractFirstAndMoveLast(); + heapifyDown(0); + return item; } public void insert(T item) { // put it at the end and then swap up with parent as much as needed for heap property - // TODO + array.insert(item); + heapifyUp(array.length - 1); + } + + private void heapifyUp(int index) { + // starting with item at index, swap up until heap is good + if (index == 0) { + // nothing to do + return; + } + + int parentIndex = getParentIndex(index); + T parent = array.getItem(parentIndex); + T item = array.getItem(index); + + if (parent == null) { + throw new RuntimeException("parent is null"); + } + if (item == null) { + throw new RuntimeException("item is null"); + } + // System.out.printf("parent: %d; item: %d\n", parent, item); + boolean needToSwap = parent.compareTo(item) < 0; + if (needToSwap) { + System.out.printf("heapifyUp swapping %d and %d\n", parent, item); + array.swap(index, parentIndex); + heapifyUp(parentIndex); + } + } + + private void heapifyDown(int index) { + // starting with item at index, swap down until heap is good + int leftChildIndex = getLeftChildIndex(index); + int rightChildIndex = getRightChildIndex(index); + T left = array.getItem(leftChildIndex); + T right = array.getItem(rightChildIndex); + + T bigger; + int biggerIndex; + if (left == null) { + if (right != null) { + throw new RuntimeException("left is null but right is not"); + } + // don't do any swaps + return; + } else if (right == null) { + // the largest child is the only child, left + bigger = left; + biggerIndex = leftChildIndex; + } else { + boolean leftGeqRight = left.compareTo(right) >= 0; + bigger = leftGeqRight ? left : right; + biggerIndex = leftGeqRight ? leftChildIndex : rightChildIndex; + } + + T item = array.getItem(index); + boolean needToSwap = item.compareTo(bigger) < 0; + if (needToSwap) { + System.out.printf("heapifyDown swapping %d and %d\n", item, bigger); + array.swap(index, biggerIndex); + heapifyDown(biggerIndex); + } + } + + private int getParentIndex(int index) { + return Math.floorDiv(index - 1, 2); + } + + private int getLeftChildIndex(int index) { + return index * 2 + 1; + } + + private int getRightChildIndex(int index) { + return index * 2 + 2; + } + + public void print() { + array.print(); + } + + public static > Comparable[] heapSort(T2[] items) { + BinaryHeap heap = new BinaryHeap<>(items); + T2[] sorted = (T2[]) new Comparable[items.length]; + for (int i = 0; i < items.length; i++) { + T2 next = heap.extractMax(); + sorted[i] = next; + } + return sorted; + } + + public static Integer[] copyComparableArrayToIntegerArray(Comparable[] a) { + // stupid Java crap + Integer[] b = new Integer[a.length]; + for (int i = 0; i < a.length; i++) { + b[i] = (Integer) a[i]; + } + return b; } public static void main(String[] args) { - BinaryHeap heap = new BinaryHeap(); + Integer[] a = {30, 41, 5, 2, 27, 11, 70, 35, 56, 8, 14, 33, 74, 94}; + // BinaryHeap heap = new BinaryHeap<>(a); + // heap.print(); + Comparable[] rawSorted = heapSort(a); + Integer[] sorted = copyComparableArrayToIntegerArray(rawSorted); + System.out.println(Arrays.toString(sorted)); } } diff --git a/DataStructuresPractice/DynamicResizingArray.java b/DataStructuresPractice/DynamicResizingArray.java index 6d382fae..71319f67 100644 --- a/DataStructuresPractice/DynamicResizingArray.java +++ b/DataStructuresPractice/DynamicResizingArray.java @@ -8,33 +8,82 @@ public DynamicResizingArray() { } public void insert(T item) { - array[length] = item; + System.out.printf("inserting item %d at index %d\n", item, length); + setItem(length, item); length++; resize(); } private void resize() { + int newCapacity; if (length == capacity) { // resize to double - int newCapacity = 2 * capacity; - T[] newArray = (T[]) new Object[newCapacity]; - copyItems(array, newArray); - array = newArray; + System.out.println("doubling array"); + newCapacity = 2 * capacity; + } else if (length * 2 == capacity) { + // resize to half + System.out.println("halving array"); + newCapacity = length; + } else if (length > capacity) { + throw new RuntimeException("shouldn't happen"); + } else { + // no need to resize right now + return; } + + T[] newArray = (T[]) new Object[newCapacity]; + copyItems(array, newArray); + array = newArray; + capacity = newCapacity; } - private void copyItems(T[] array, T[] newArray) { - for (int i = 0; i < array.length; i++) { - newArray[i] = array[i]; + private void copyItems(T[] oldArray, T[] newArray) { + int newLength = Math.min(oldArray.length, newArray.length); + for (int i = 0; i < newLength; i++) { + newArray[i] = oldArray[i]; } } - public void push(T item) { - int index = length; - setItem(index, item); + public T getItem(int index) { + if (0 <= index && index < length) { + return array[index]; + } + return null; } public void setItem(int index, T item) { array[index] = item; } + + public T extractFirstAndMoveLast() { + T item = array[0]; + array[0] = array[length - 1]; + array[length - 1] = null; + length--; + resize(); + return item; + } + + public void swap(int index1, int index2) { + T x1 = array[index1]; + T x2 = array[index2]; + setItem(index1, x2); + setItem(index2, x1); + } + + public void print() { + String s = "["; + for (int i = 0; i < length; i++) { + s += array[i].toString(); + if (i < length - 1) { + s += ", "; + } + } + s += "]"; + if (capacity > length) { + String nNulls = Integer.toString(capacity - length); + s += " (plus " + nNulls + " empty slots)"; + } + System.out.println(s); + } }