From a89368d3c795eadfcca9d86d4be014799a8e1fcd Mon Sep 17 00:00:00 2001 From: jrtechs Date: Sun, 26 Aug 2018 15:03:49 -0400 Subject: [PATCH] Created a BinaryHeap and JUnit tests for it. --- .../Lists/ArrayList/ArrayBackedList.java | 46 ++++- .../DataStructures/Trees/Heap/BinaryHeap.java | 160 ++++++++++++++++++ .../www/DataStructures/Trees/Heap/IHeap.java | 33 ++++ .../DataStructures/Lists/ArrayListTest.java | 2 + .../DataStructures/trees/BinaryHeapTest.java | 91 ++++++++++ 5 files changed, 331 insertions(+), 1 deletion(-) create mode 100644 src/main/java/net/jrtechs/www/DataStructures/Trees/Heap/BinaryHeap.java create mode 100644 src/main/java/net/jrtechs/www/DataStructures/Trees/Heap/IHeap.java create mode 100644 src/test/java/net/jrtechs/www/DataStructures/trees/BinaryHeapTest.java diff --git a/src/main/java/net/jrtechs/www/DataStructures/Lists/ArrayList/ArrayBackedList.java b/src/main/java/net/jrtechs/www/DataStructures/Lists/ArrayList/ArrayBackedList.java index 57cf917..ac9cab5 100644 --- a/src/main/java/net/jrtechs/www/DataStructures/Lists/ArrayList/ArrayBackedList.java +++ b/src/main/java/net/jrtechs/www/DataStructures/Lists/ArrayList/ArrayBackedList.java @@ -165,6 +165,50 @@ public class ArrayBackedList implements IList @Override public E get(int index) { - return (E)dataList[index]; + return (E)this.dataList[index]; + } + + + /** + * Sets an element in the array list + * + * @Warning This can go out of bounds with bad input + * + * @param index of desired element + * @return element of a specific index + */ + public void set(int index, E o) + { + this.dataList[index] = o; + } + + + /** + * Swaps two elements in the list by their index + * + * @param index1 index of first element + * @param index2 index of second element + */ + public void swap(int index1, int index2) + { + Object temp = this.dataList[index1]; + this.dataList[index1] = dataList[index2]; + this.dataList[index2] = temp; + } + + + /** + * Creates a string representation of the list. + * + * @return string corresponding to the list + */ + public String toString() + { + String s = ""; + for(int i = 0; i < this.currentSize; i++) + { + s+= this.dataList[i] + ", "; + } + return s; } } diff --git a/src/main/java/net/jrtechs/www/DataStructures/Trees/Heap/BinaryHeap.java b/src/main/java/net/jrtechs/www/DataStructures/Trees/Heap/BinaryHeap.java new file mode 100644 index 0000000..a7c7568 --- /dev/null +++ b/src/main/java/net/jrtechs/www/DataStructures/Trees/Heap/BinaryHeap.java @@ -0,0 +1,160 @@ +package net.jrtechs.www.DataStructures.Trees.Heap; + + +import net.jrtechs.www.DataStructures.Lists.ArrayList.ArrayBackedList; + +/** + * Basic implementation of a {@link IHeap}. By default, this is + * a min heap, however, using the second constructor with + * (BinaryHeap.MAX_HEAP) will create a max heap. To keep the + * performance of using an array, while having a dynamically scalable + * heap, {@link ArrayBackedList} was used since it. + * + * Operation complexities: + * insertion: O(logN) + * delete extrema: O(logN) + * get extrema: O(1) + * + * Basic Heap Operations: + * Parent index = (i-1)/2 or (i-2)/2 + * Left Node = 2n + 1 + * Right Node = 2n + 1 + * + * @author Jeffery Russell 8-26-18 + */ +public class BinaryHeap + implements IHeap +{ + /** Used to define comparisons for a Max heap */ + public static final int MAX_HEAP = -1; + + /** Used to define comparisons for a Min heap */ + public static final int MIN_HEAP = 1; + + /** Where the heap is storing data */ + private ArrayBackedList data; + + /** Ordering which heap is using defined by + * MAX_HEAP, and MIN_HEAP */ + private int ordering; + + + /** + * Creates a new min Binary Heap + */ + public BinaryHeap() + { + this.data = new ArrayBackedList<>(); + this.ordering = MIN_HEAP; + } + + + /** + * Creates a new binary heap with a specific ordering defined by + * the MAX_HEAP, and MIN_HEAP constants + * + * @param ordering type of ordering to use + */ + public BinaryHeap(int ordering) + { + this.ordering = ordering; + this.data = new ArrayBackedList<>(); + } + + + /** + * Inserts a new element at the end of the array, and then shifts it + * up to perserve the order of the heap. + * + * @param o element to insert + */ + @Override + public void insert(E o) + { + this.data.add(o); + this.shiftUp(this.data.size() -1); + } + + + /** + * Preserves structure of heap after a element has been + * added to the end of the heap. + * + * @param nodeIndex index of node to recursively bring up + */ + private void shiftUp(int nodeIndex) + { + if(nodeIndex != 0) + { + int parentIndex = (nodeIndex -1)/2; + + if(data.get(parentIndex).compareTo(data.get(nodeIndex)) == ordering) + { + data.swap(nodeIndex, parentIndex); + + shiftUp(parentIndex); + } + } + } + + + /** + * Preserves the order of heap after the top element has been + * removed. + * + * @param i index of element to recursively heapify + */ + private void heapify(int i) + { + int left = 2 * i + 1; + int right = 2 * i + 2; + + int extrema = (left < data.size() && + data.get(left).compareTo(data.get(i)) != ordering) + ? left : i; + extrema = (right < data.size() && + data.get(right).compareTo(data.get(extrema)) != ordering) + ? right: extrema; + + if(extrema != i) + { + this.data.swap(i, extrema); + heapify(extrema); + } + } + + + /** + * Removes the top element of the heap. + * + * @return top element + */ + @Override + public E remove() + { + if(this.data.size() == 0) + return null; + + E element = this.data.get(0); + + this.data.set(0, this.data.remove(this.data.size() -1)); + + this.heapify(0); + + return element; + } + + + /** + * Returns the min/max value of the heep + * + * @return extrema value + */ + @Override + public E peek() + { + if(data.size() == 0) + return null; + return data.get(0); + } +} diff --git a/src/main/java/net/jrtechs/www/DataStructures/Trees/Heap/IHeap.java b/src/main/java/net/jrtechs/www/DataStructures/Trees/Heap/IHeap.java new file mode 100644 index 0000000..2fa918c --- /dev/null +++ b/src/main/java/net/jrtechs/www/DataStructures/Trees/Heap/IHeap.java @@ -0,0 +1,33 @@ +package net.jrtechs.www.DataStructures.Trees.Heap; + + +/** + * Definition for behavior of heaps + * + * @author Jeffery Russell 8-26-18 + */ +public interface IHeap +{ + /** + * Add element to heap. + * + * @param o + */ + public void insert(E o); + + + /** + * Remove top element from heap + * + * @return top element + */ + public E remove(); + + + /** + * Fetches top element + * + * @return top element + */ + public E peek(); +} diff --git a/src/test/java/net/jrtechs/www/DataStructures/Lists/ArrayListTest.java b/src/test/java/net/jrtechs/www/DataStructures/Lists/ArrayListTest.java index f4ffea5..1d5bd67 100644 --- a/src/test/java/net/jrtechs/www/DataStructures/Lists/ArrayListTest.java +++ b/src/test/java/net/jrtechs/www/DataStructures/Lists/ArrayListTest.java @@ -7,6 +7,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; + /** * JUnit tests for {@link ArrayBackedList} * @@ -92,6 +93,7 @@ public class ArrayListTest assertTrue(list.contains(13.0)); } + /** * Tests linked deletion based on element */ diff --git a/src/test/java/net/jrtechs/www/DataStructures/trees/BinaryHeapTest.java b/src/test/java/net/jrtechs/www/DataStructures/trees/BinaryHeapTest.java new file mode 100644 index 0000000..18e3a6c --- /dev/null +++ b/src/test/java/net/jrtechs/www/DataStructures/trees/BinaryHeapTest.java @@ -0,0 +1,91 @@ +package net.jrtechs.www.DataStructures.trees; + + +import net.jrtechs.www.DataStructures.Trees.Heap.BinaryHeap; +import org.junit.Test; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +/** + * JUnit tests for binary heap + * + * @author Jeffery Russell 8-26-18 + */ +public class BinaryHeapTest +{ + + @Test + public void testCreation() + { + BinaryHeap heap = new BinaryHeap<>(); + assertNotNull(heap); + } + + @Test + public void testInsertion() + { + BinaryHeap heap = new BinaryHeap<>(); + heap.insert(12.9); + + heap.insert(12.8); + + assertTrue(heap.peek() == 12.8); + } + + @Test + public void testRemoval() + { + BinaryHeap heap = new BinaryHeap<>(); + heap.insert(1.5); + heap.insert(-9.8); + heap.insert(999.0); + + heap.remove(); + heap.remove(); + heap.remove(); + + assertNull(heap.remove()); + } + + @Test + public void testMinOrdering() + { + BinaryHeap heap = new BinaryHeap<>(BinaryHeap.MIN_HEAP); + heap.insert(2.0); // + heap.insert(-4.0); // + heap.insert(69.0); + heap.insert(-99.0); // + heap.insert(1.0); // + heap.insert(3.0); // + heap.insert(99.0); + + + assertTrue(heap.remove() == -99.0); + assertTrue(heap.remove() == -4.0); + assertTrue(heap.remove() == 1.0); + assertTrue(heap.remove() == 2.0); + assertTrue(heap.remove() == 3.0); + assertTrue(heap.remove() == 69.0); + assertTrue(heap.remove() == 99.0); + } + + + @Test + public void testMaxOrdering() + { + BinaryHeap heap = new BinaryHeap<>(BinaryHeap.MAX_HEAP); + heap.insert(1.0); + heap.insert(3.0); + heap.insert(2.0); + heap.insert(-4.0); + heap.insert(99.0); + assertTrue(heap.remove() == 99.0); + assertTrue(heap.remove() == 3.0); + assertTrue(heap.remove() == 2.0); + assertTrue(heap.remove() == 1.0); + assertTrue(heap.remove() == -4.0); + assertNull(heap.remove()); + } +}