mirror of
https://github.com/TheAlgorithms/Java.git
synced 2026-03-13 08:40:43 +08:00
Enhance docs, add tests in MaxHeap (#5983)
This commit is contained in:
@@ -488,6 +488,7 @@
|
|||||||
* [PalindromePrime](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/PalindromePrime.java)
|
* [PalindromePrime](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/PalindromePrime.java)
|
||||||
* [PalindromeSinglyLinkedList](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/PalindromeSinglyLinkedList.java)
|
* [PalindromeSinglyLinkedList](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/PalindromeSinglyLinkedList.java)
|
||||||
* [RangeInSortedArray](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/RangeInSortedArray.java)
|
* [RangeInSortedArray](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/RangeInSortedArray.java)
|
||||||
|
* [ShuffleArray](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/ShuffleArray.java)
|
||||||
* [Sparsity](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/Sparsity.java)
|
* [Sparsity](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/Sparsity.java)
|
||||||
* [ThreeSumProblem](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/ThreeSumProblem.java)
|
* [ThreeSumProblem](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/ThreeSumProblem.java)
|
||||||
* [TwoSumProblem](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/TwoSumProblem.java)
|
* [TwoSumProblem](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/TwoSumProblem.java)
|
||||||
@@ -876,6 +877,7 @@
|
|||||||
* [HeapElementTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/heaps/HeapElementTest.java)
|
* [HeapElementTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/heaps/HeapElementTest.java)
|
||||||
* [KthElementFinderTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/heaps/KthElementFinderTest.java)
|
* [KthElementFinderTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/heaps/KthElementFinderTest.java)
|
||||||
* [LeftistHeapTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/heaps/LeftistHeapTest.java)
|
* [LeftistHeapTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/heaps/LeftistHeapTest.java)
|
||||||
|
* [MaxHeapTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/heaps/MaxHeapTest.java)
|
||||||
* [MedianFinderTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/heaps/MedianFinderTest.java)
|
* [MedianFinderTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/heaps/MedianFinderTest.java)
|
||||||
* [MergeKSortedArraysTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/heaps/MergeKSortedArraysTest.java)
|
* [MergeKSortedArraysTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/heaps/MergeKSortedArraysTest.java)
|
||||||
* [MinHeapTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/heaps/MinHeapTest.java)
|
* [MinHeapTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/heaps/MinHeapTest.java)
|
||||||
@@ -1136,6 +1138,7 @@
|
|||||||
* [PalindromePrimeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/PalindromePrimeTest.java)
|
* [PalindromePrimeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/PalindromePrimeTest.java)
|
||||||
* [PalindromeSinglyLinkedListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/PalindromeSinglyLinkedListTest.java)
|
* [PalindromeSinglyLinkedListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/PalindromeSinglyLinkedListTest.java)
|
||||||
* [RangeInSortedArrayTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/RangeInSortedArrayTest.java)
|
* [RangeInSortedArrayTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/RangeInSortedArrayTest.java)
|
||||||
|
* [ShuffleArrayTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/ShuffleArrayTest.java)
|
||||||
* [SparsityTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/SparsityTest.java)
|
* [SparsityTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/SparsityTest.java)
|
||||||
* [ThreeSumProblemTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/ThreeSumProblemTest.java)
|
* [ThreeSumProblemTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/ThreeSumProblemTest.java)
|
||||||
* [TwoSumProblemTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/TwoSumProblemTest.java)
|
* [TwoSumProblemTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/TwoSumProblemTest.java)
|
||||||
|
|||||||
@@ -143,10 +143,9 @@ public class HeapElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compares this heap element to another object for equality.
|
* @param o : an object to compare with the current element
|
||||||
*
|
* @return true if the keys on both elements are identical and the
|
||||||
* @param o the object to compare with
|
* additional info objects are identical.
|
||||||
* @return true if the keys and additional information are identical, false otherwise
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
|
|||||||
@@ -4,128 +4,245 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Heap tree where a node's key is higher than or equal to its parent's and
|
* A Max Heap implementation where each node's key is higher than or equal to its children's keys.
|
||||||
* lower than or equal to its children's.
|
* This data structure provides O(log n) time complexity for insertion and deletion operations,
|
||||||
|
* and O(1) for retrieving the maximum element.
|
||||||
|
*
|
||||||
|
* Properties:
|
||||||
|
* 1. Complete Binary Tree
|
||||||
|
* 2. Parent node's key ≥ Children nodes' keys
|
||||||
|
* 3. Root contains the maximum element
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
* <pre>
|
||||||
|
* List<HeapElement> elements = Arrays.asList(
|
||||||
|
* new HeapElement(5, "Five"),
|
||||||
|
* new HeapElement(2, "Two")
|
||||||
|
* );
|
||||||
|
* MaxHeap heap = new MaxHeap(elements);
|
||||||
|
* heap.insertElement(new HeapElement(7, "Seven"));
|
||||||
|
* HeapElement max = heap.getElement(); // Returns and removes the maximum element
|
||||||
|
* </pre>
|
||||||
*
|
*
|
||||||
* @author Nicolas Renard
|
* @author Nicolas Renard
|
||||||
*/
|
*/
|
||||||
public class MaxHeap implements Heap {
|
public class MaxHeap implements Heap {
|
||||||
|
|
||||||
|
/** The internal list that stores heap elements */
|
||||||
private final List<HeapElement> maxHeap;
|
private final List<HeapElement> maxHeap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new MaxHeap from a list of elements.
|
||||||
|
* Null elements in the input list are ignored.
|
||||||
|
*
|
||||||
|
* @param listElements List of HeapElement objects to initialize the heap
|
||||||
|
* @throws IllegalArgumentException if the input list is null
|
||||||
|
*/
|
||||||
public MaxHeap(List<HeapElement> listElements) {
|
public MaxHeap(List<HeapElement> listElements) {
|
||||||
|
if (listElements == null) {
|
||||||
|
throw new IllegalArgumentException("Input list cannot be null");
|
||||||
|
}
|
||||||
|
|
||||||
maxHeap = new ArrayList<>();
|
maxHeap = new ArrayList<>();
|
||||||
|
|
||||||
|
// Safe initialization: directly add non-null elements first
|
||||||
for (HeapElement heapElement : listElements) {
|
for (HeapElement heapElement : listElements) {
|
||||||
if (heapElement != null) {
|
if (heapElement != null) {
|
||||||
insertElement(heapElement);
|
maxHeap.add(heapElement);
|
||||||
} else {
|
|
||||||
System.out.println("Null element. Not added to heap");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (maxHeap.isEmpty()) {
|
|
||||||
System.out.println("No element has been added, empty heap.");
|
// Heapify the array bottom-up
|
||||||
|
for (int i = maxHeap.size() / 2; i >= 0; i--) {
|
||||||
|
heapifyDown(i + 1); // +1 because heapifyDown expects 1-based index
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the element at a given index. The key for the list is equal to index
|
* Maintains heap properties by moving an element down the heap.
|
||||||
* value - 1
|
* Similar to toggleDown but used specifically during initialization.
|
||||||
*
|
*
|
||||||
* @param elementIndex index
|
* @param elementIndex 1-based index of the element to heapify
|
||||||
* @return heapElement
|
*/
|
||||||
|
private void heapifyDown(int elementIndex) {
|
||||||
|
int largest = elementIndex - 1;
|
||||||
|
int leftChild = 2 * elementIndex - 1;
|
||||||
|
int rightChild = 2 * elementIndex;
|
||||||
|
|
||||||
|
if (leftChild < maxHeap.size() && maxHeap.get(leftChild).getKey() > maxHeap.get(largest).getKey()) {
|
||||||
|
largest = leftChild;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rightChild < maxHeap.size() && maxHeap.get(rightChild).getKey() > maxHeap.get(largest).getKey()) {
|
||||||
|
largest = rightChild;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (largest != elementIndex - 1) {
|
||||||
|
HeapElement swap = maxHeap.get(elementIndex - 1);
|
||||||
|
maxHeap.set(elementIndex - 1, maxHeap.get(largest));
|
||||||
|
maxHeap.set(largest, swap);
|
||||||
|
|
||||||
|
heapifyDown(largest + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the element at the specified index without removing it.
|
||||||
|
* Note: The index is 1-based for consistency with heap operations.
|
||||||
|
*
|
||||||
|
* @param elementIndex 1-based index of the element to retrieve
|
||||||
|
* @return HeapElement at the specified index
|
||||||
|
* @throws IndexOutOfBoundsException if the index is invalid
|
||||||
*/
|
*/
|
||||||
public HeapElement getElement(int elementIndex) {
|
public HeapElement getElement(int elementIndex) {
|
||||||
if ((elementIndex <= 0) || (elementIndex > maxHeap.size())) {
|
if ((elementIndex <= 0) || (elementIndex > maxHeap.size())) {
|
||||||
throw new IndexOutOfBoundsException("Index out of heap range");
|
throw new IndexOutOfBoundsException("Index " + elementIndex + " is out of heap range [1, " + maxHeap.size() + "]");
|
||||||
}
|
}
|
||||||
return maxHeap.get(elementIndex - 1);
|
return maxHeap.get(elementIndex - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the key of the element at a given index
|
/**
|
||||||
|
* Retrieves the key value of an element at the specified index.
|
||||||
|
*
|
||||||
|
* @param elementIndex 1-based index of the element
|
||||||
|
* @return double value representing the key
|
||||||
|
* @throws IndexOutOfBoundsException if the index is invalid
|
||||||
|
*/
|
||||||
private double getElementKey(int elementIndex) {
|
private double getElementKey(int elementIndex) {
|
||||||
if ((elementIndex <= 0) || (elementIndex > maxHeap.size())) {
|
if ((elementIndex <= 0) || (elementIndex > maxHeap.size())) {
|
||||||
throw new IndexOutOfBoundsException("Index out of heap range");
|
throw new IndexOutOfBoundsException("Index " + elementIndex + " is out of heap range [1, " + maxHeap.size() + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
return maxHeap.get(elementIndex - 1).getKey();
|
return maxHeap.get(elementIndex - 1).getKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Swaps two elements in the heap
|
/**
|
||||||
|
* Swaps two elements in the heap.
|
||||||
|
*
|
||||||
|
* @param index1 1-based index of first element
|
||||||
|
* @param index2 1-based index of second element
|
||||||
|
*/
|
||||||
private void swap(int index1, int index2) {
|
private void swap(int index1, int index2) {
|
||||||
HeapElement temporaryElement = maxHeap.get(index1 - 1);
|
HeapElement temporaryElement = maxHeap.get(index1 - 1);
|
||||||
maxHeap.set(index1 - 1, maxHeap.get(index2 - 1));
|
maxHeap.set(index1 - 1, maxHeap.get(index2 - 1));
|
||||||
maxHeap.set(index2 - 1, temporaryElement);
|
maxHeap.set(index2 - 1, temporaryElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toggle an element up to its right place as long as its key is lower than its parent's
|
/**
|
||||||
|
* Moves an element up the heap until heap properties are satisfied.
|
||||||
|
* This operation is called after insertion to maintain heap properties.
|
||||||
|
*
|
||||||
|
* @param elementIndex 1-based index of the element to move up
|
||||||
|
*/
|
||||||
private void toggleUp(int elementIndex) {
|
private void toggleUp(int elementIndex) {
|
||||||
double key = maxHeap.get(elementIndex - 1).getKey();
|
double key = maxHeap.get(elementIndex - 1).getKey();
|
||||||
while (getElementKey((int) Math.floor(elementIndex / 2.0)) < key) {
|
while (elementIndex > 1 && getElementKey((int) Math.floor(elementIndex / 2.0)) < key) {
|
||||||
swap(elementIndex, (int) Math.floor(elementIndex / 2.0));
|
swap(elementIndex, (int) Math.floor(elementIndex / 2.0));
|
||||||
elementIndex = (int) Math.floor(elementIndex / 2.0);
|
elementIndex = (int) Math.floor(elementIndex / 2.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toggle an element down to its right place as long as its key is higher
|
/**
|
||||||
// than any of its children's
|
* Moves an element down the heap until heap properties are satisfied.
|
||||||
|
* This operation is called after deletion to maintain heap properties.
|
||||||
|
*
|
||||||
|
* @param elementIndex 1-based index of the element to move down
|
||||||
|
*/
|
||||||
private void toggleDown(int elementIndex) {
|
private void toggleDown(int elementIndex) {
|
||||||
double key = maxHeap.get(elementIndex - 1).getKey();
|
double key = maxHeap.get(elementIndex - 1).getKey();
|
||||||
boolean wrongOrder = (key < getElementKey(elementIndex * 2)) || (key < getElementKey(Math.min(elementIndex * 2, maxHeap.size())));
|
boolean wrongOrder = (2 * elementIndex <= maxHeap.size() && key < getElementKey(elementIndex * 2)) || (2 * elementIndex + 1 <= maxHeap.size() && key < getElementKey(elementIndex * 2 + 1));
|
||||||
while ((2 * elementIndex <= maxHeap.size()) && wrongOrder) {
|
|
||||||
// Check whether it shall swap the element with its left child or its right one if any.
|
while (2 * elementIndex <= maxHeap.size() && wrongOrder) {
|
||||||
if ((2 * elementIndex < maxHeap.size()) && (getElementKey(elementIndex * 2 + 1) > getElementKey(elementIndex * 2))) {
|
int largerChildIndex;
|
||||||
swap(elementIndex, 2 * elementIndex + 1);
|
if (2 * elementIndex + 1 <= maxHeap.size() && getElementKey(elementIndex * 2 + 1) > getElementKey(elementIndex * 2)) {
|
||||||
elementIndex = 2 * elementIndex + 1;
|
largerChildIndex = 2 * elementIndex + 1;
|
||||||
} else {
|
} else {
|
||||||
swap(elementIndex, 2 * elementIndex);
|
largerChildIndex = 2 * elementIndex;
|
||||||
elementIndex = 2 * elementIndex;
|
|
||||||
}
|
}
|
||||||
wrongOrder = (key < getElementKey(elementIndex * 2)) || (key < getElementKey(Math.min(elementIndex * 2, maxHeap.size())));
|
|
||||||
|
swap(elementIndex, largerChildIndex);
|
||||||
|
elementIndex = largerChildIndex;
|
||||||
|
|
||||||
|
wrongOrder = (2 * elementIndex <= maxHeap.size() && key < getElementKey(elementIndex * 2)) || (2 * elementIndex + 1 <= maxHeap.size() && key < getElementKey(elementIndex * 2 + 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private HeapElement extractMax() {
|
/**
|
||||||
HeapElement result = maxHeap.get(0);
|
* Extracts and returns the maximum element from the heap.
|
||||||
deleteElement(0);
|
*
|
||||||
|
* @return HeapElement with the highest key
|
||||||
|
* @throws EmptyHeapException if the heap is empty
|
||||||
|
*/
|
||||||
|
private HeapElement extractMax() throws EmptyHeapException {
|
||||||
|
if (maxHeap.isEmpty()) {
|
||||||
|
throw new EmptyHeapException("Cannot extract from an empty heap");
|
||||||
|
}
|
||||||
|
HeapElement result = maxHeap.getFirst();
|
||||||
|
deleteElement(1);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public final void insertElement(HeapElement element) {
|
public void insertElement(HeapElement element) {
|
||||||
|
if (element == null) {
|
||||||
|
throw new IllegalArgumentException("Cannot insert null element");
|
||||||
|
}
|
||||||
maxHeap.add(element);
|
maxHeap.add(element);
|
||||||
toggleUp(maxHeap.size());
|
toggleUp(maxHeap.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void deleteElement(int elementIndex) {
|
public void deleteElement(int elementIndex) throws EmptyHeapException {
|
||||||
if (maxHeap.isEmpty()) {
|
if (maxHeap.isEmpty()) {
|
||||||
try {
|
throw new EmptyHeapException("Cannot delete from an empty heap");
|
||||||
throw new EmptyHeapException("Attempt to delete an element from an empty heap");
|
|
||||||
} catch (EmptyHeapException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if ((elementIndex > maxHeap.size()) || (elementIndex <= 0)) {
|
if ((elementIndex > maxHeap.size()) || (elementIndex <= 0)) {
|
||||||
throw new IndexOutOfBoundsException("Index out of heap range");
|
throw new IndexOutOfBoundsException("Index " + elementIndex + " is out of heap range [1, " + maxHeap.size() + "]");
|
||||||
}
|
}
|
||||||
// The last element in heap replaces the one to be deleted
|
|
||||||
maxHeap.set(elementIndex - 1, getElement(maxHeap.size()));
|
// Replace with last element and remove last position
|
||||||
maxHeap.remove(maxHeap.size());
|
maxHeap.set(elementIndex - 1, maxHeap.getLast());
|
||||||
// Shall the new element be moved up...
|
maxHeap.removeLast();
|
||||||
if (getElementKey(elementIndex) > getElementKey((int) Math.floor(elementIndex / 2.0))) {
|
|
||||||
toggleUp(elementIndex);
|
// No need to toggle if we just removed the last element
|
||||||
} // ... or down ?
|
if (!maxHeap.isEmpty() && elementIndex <= maxHeap.size()) {
|
||||||
else if (((2 * elementIndex <= maxHeap.size()) && (getElementKey(elementIndex) < getElementKey(elementIndex * 2))) || ((2 * elementIndex < maxHeap.size()) && (getElementKey(elementIndex) < getElementKey(elementIndex * 2)))) {
|
// Determine whether to toggle up or down
|
||||||
toggleDown(elementIndex);
|
if (elementIndex > 1 && getElementKey(elementIndex) > getElementKey((int) Math.floor(elementIndex / 2.0))) {
|
||||||
|
toggleUp(elementIndex);
|
||||||
|
} else {
|
||||||
|
toggleDown(elementIndex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public HeapElement getElement() throws EmptyHeapException {
|
public HeapElement getElement() throws EmptyHeapException {
|
||||||
try {
|
return extractMax();
|
||||||
return extractMax();
|
}
|
||||||
} catch (Exception e) {
|
|
||||||
throw new EmptyHeapException("Heap is empty. Error retrieving element", e);
|
/**
|
||||||
}
|
* Returns the current size of the heap.
|
||||||
|
*
|
||||||
|
* @return number of elements in the heap
|
||||||
|
*/
|
||||||
|
public int size() {
|
||||||
|
return maxHeap.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the heap is empty.
|
||||||
|
*
|
||||||
|
* @return true if the heap contains no elements
|
||||||
|
*/
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return maxHeap.isEmpty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,144 @@
|
|||||||
|
package com.thealgorithms.datastructures.heaps;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for MaxHeap implementation
|
||||||
|
*/
|
||||||
|
class MaxHeapTest {
|
||||||
|
|
||||||
|
private MaxHeap heap;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
// Create a fresh heap for each test
|
||||||
|
List<HeapElement> elements = Arrays.asList(new HeapElement(5.0, "Five"), new HeapElement(2.0, "Two"), new HeapElement(8.0, "Eight"), new HeapElement(1.0, "One"), new HeapElement(9.0, "Nine"));
|
||||||
|
heap = new MaxHeap(elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConstructorWithNullList() {
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> new MaxHeap(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConstructorWithEmptyList() {
|
||||||
|
MaxHeap emptyHeap = new MaxHeap(new ArrayList<>());
|
||||||
|
assertTrue(emptyHeap.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConstructorWithNullElements() {
|
||||||
|
List<HeapElement> elements = Arrays.asList(new HeapElement(1.0, "One"), null, new HeapElement(2.0, "Two"));
|
||||||
|
MaxHeap heap = new MaxHeap(elements);
|
||||||
|
assertEquals(2, heap.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testInsertElement() {
|
||||||
|
heap.insertElement(new HeapElement(10.0, "Ten"));
|
||||||
|
assertEquals(10.0, heap.getElement(1).getKey());
|
||||||
|
assertEquals(6, heap.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testInsertNullElement() {
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> heap.insertElement(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetElementAtIndex() {
|
||||||
|
HeapElement element = heap.getElement(1);
|
||||||
|
assertEquals(9.0, element.getKey());
|
||||||
|
assertEquals("Nine", element.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetElementAtInvalidIndex() {
|
||||||
|
assertThrows(IndexOutOfBoundsException.class, () -> heap.getElement(0));
|
||||||
|
assertThrows(IndexOutOfBoundsException.class, () -> heap.getElement(10));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDeleteElement() throws EmptyHeapException {
|
||||||
|
heap.deleteElement(1);
|
||||||
|
assertEquals(8.0, heap.getElement(1).getKey());
|
||||||
|
assertEquals(4, heap.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDeleteElementAtInvalidIndex() {
|
||||||
|
assertThrows(IndexOutOfBoundsException.class, () -> heap.deleteElement(0));
|
||||||
|
assertThrows(IndexOutOfBoundsException.class, () -> heap.deleteElement(10));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDeleteFromEmptyHeap() {
|
||||||
|
MaxHeap emptyHeap = new MaxHeap(new ArrayList<>());
|
||||||
|
assertThrows(EmptyHeapException.class, () -> emptyHeap.deleteElement(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testExtractMax() throws EmptyHeapException {
|
||||||
|
HeapElement max = heap.getElement();
|
||||||
|
assertEquals(9.0, max.getKey());
|
||||||
|
assertEquals("Nine", max.getValue());
|
||||||
|
assertEquals(4, heap.size());
|
||||||
|
|
||||||
|
max = heap.getElement();
|
||||||
|
assertEquals(8.0, max.getKey());
|
||||||
|
assertEquals(3, heap.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testExtractMaxFromEmptyHeap() {
|
||||||
|
MaxHeap emptyHeap = new MaxHeap(new ArrayList<>());
|
||||||
|
assertThrows(EmptyHeapException.class, () -> emptyHeap.getElement());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testHeapOrder() {
|
||||||
|
// Test that parent is always greater than or equal to children
|
||||||
|
for (int i = 1; i <= heap.size() / 2; i++) {
|
||||||
|
double parentKey = heap.getElement(i).getKey();
|
||||||
|
|
||||||
|
// Check left child
|
||||||
|
if (2 * i <= heap.size()) {
|
||||||
|
assertTrue(parentKey >= heap.getElement(2 * i).getKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check right child
|
||||||
|
if (2 * i + 1 <= heap.size()) {
|
||||||
|
assertTrue(parentKey >= heap.getElement(2 * i + 1).getKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSizeAndEmpty() {
|
||||||
|
assertEquals(5, heap.size());
|
||||||
|
assertFalse(heap.isEmpty());
|
||||||
|
|
||||||
|
// Remove all elements
|
||||||
|
while (!heap.isEmpty()) {
|
||||||
|
try {
|
||||||
|
heap.getElement();
|
||||||
|
} catch (EmptyHeapException e) {
|
||||||
|
Assertions.fail("Should not throw EmptyHeapException while heap is not empty");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(0, heap.size());
|
||||||
|
assertTrue(heap.isEmpty());
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user