2019-02-07 00:11:13 +08:00
|
|
|
package DataStructures.Heaps;
|
2018-04-14 11:45:48 +08:00
|
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Heap tree where a node's key is higher than or equal to its parent's and lower than or equal
|
|
|
|
* to its children's.
|
|
|
|
*
|
2019-02-06 10:13:55 +08:00
|
|
|
* @author Nicolas Renard
|
2018-04-14 11:45:48 +08:00
|
|
|
*/
|
|
|
|
public class MaxHeap implements Heap {
|
2019-02-06 10:13:55 +08:00
|
|
|
|
2018-04-14 11:45:48 +08:00
|
|
|
private final List<HeapElement> maxHeap;
|
2019-02-06 10:13:55 +08:00
|
|
|
|
|
|
|
public MaxHeap(List<HeapElement> listElements) {
|
|
|
|
maxHeap = new ArrayList<>();
|
2018-04-14 11:45:48 +08:00
|
|
|
for (HeapElement heapElement : listElements) {
|
|
|
|
if (heapElement != null) insertElement(heapElement);
|
|
|
|
else System.out.println("Null element. Not added to heap");
|
|
|
|
}
|
|
|
|
if (maxHeap.size() == 0) System.out.println("No element has been added, empty heap.");
|
2019-02-06 10:13:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the element at a given index. The key for the list is equal to index value - 1
|
|
|
|
*
|
|
|
|
* @param elementIndex index
|
|
|
|
* @return heapElement
|
|
|
|
*/
|
2018-04-14 11:45:48 +08:00
|
|
|
public HeapElement getElement(int elementIndex) {
|
2019-02-06 10:13:55 +08:00
|
|
|
if ((elementIndex <= 0) || (elementIndex > maxHeap.size()))
|
|
|
|
throw new IndexOutOfBoundsException("Index out of heap range");
|
2018-04-14 11:45:48 +08:00
|
|
|
return maxHeap.get(elementIndex - 1);
|
|
|
|
}
|
2019-02-06 10:13:55 +08:00
|
|
|
|
2018-04-14 11:45:48 +08:00
|
|
|
// Get the key of the element at a given index
|
|
|
|
private double getElementKey(int elementIndex) {
|
|
|
|
return maxHeap.get(elementIndex - 1).getKey();
|
|
|
|
}
|
2019-02-06 10:13:55 +08:00
|
|
|
|
2018-04-14 11:45:48 +08:00
|
|
|
// Swaps two elements in the heap
|
|
|
|
private void swap(int index1, int index2) {
|
|
|
|
HeapElement temporaryElement = maxHeap.get(index1 - 1);
|
|
|
|
maxHeap.set(index1 - 1, maxHeap.get(index2 - 1));
|
|
|
|
maxHeap.set(index2 - 1, temporaryElement);
|
|
|
|
}
|
2019-02-06 10:13:55 +08:00
|
|
|
|
|
|
|
// Toggle an element up to its right place as long as its key is lower than its parent's
|
2018-04-14 11:45:48 +08:00
|
|
|
private void toggleUp(int elementIndex) {
|
|
|
|
double key = maxHeap.get(elementIndex - 1).getKey();
|
2020-05-25 05:21:28 +08:00
|
|
|
while (getElementKey((int) Math.floor(elementIndex / 2.0)) < key) {
|
|
|
|
swap(elementIndex, (int) Math.floor(elementIndex / 2.0));
|
|
|
|
elementIndex = (int) Math.floor(elementIndex / 2.0);
|
2018-04-14 11:45:48 +08:00
|
|
|
}
|
|
|
|
}
|
2019-02-06 10:13:55 +08:00
|
|
|
|
2018-04-14 11:45:48 +08:00
|
|
|
// Toggle an element down to its right place as long as its key is higher
|
2019-02-06 10:13:55 +08:00
|
|
|
// than any of its children's
|
2018-04-14 11:45:48 +08:00
|
|
|
private void toggleDown(int elementIndex) {
|
|
|
|
double key = maxHeap.get(elementIndex - 1).getKey();
|
2019-02-06 10:13:55 +08:00
|
|
|
boolean wrongOrder = (key < getElementKey(elementIndex * 2)) || (key < getElementKey(Math.min(elementIndex * 2, maxHeap.size())));
|
|
|
|
while ((2 * elementIndex <= maxHeap.size()) && wrongOrder) {
|
2018-04-14 11:45:48 +08:00
|
|
|
// Check whether it shall swap the element with its left child or its right one if any.
|
2019-02-06 10:13:55 +08:00
|
|
|
if ((2 * elementIndex < maxHeap.size()) && (getElementKey(elementIndex * 2 + 1) > getElementKey(elementIndex * 2))) {
|
|
|
|
swap(elementIndex, 2 * elementIndex + 1);
|
|
|
|
elementIndex = 2 * elementIndex + 1;
|
|
|
|
} else {
|
|
|
|
swap(elementIndex, 2 * elementIndex);
|
|
|
|
elementIndex = 2 * elementIndex;
|
2018-04-14 11:45:48 +08:00
|
|
|
}
|
2019-02-06 10:13:55 +08:00
|
|
|
wrongOrder = (key < getElementKey(elementIndex * 2)) || (key < getElementKey(Math.min(elementIndex * 2, maxHeap.size())));
|
|
|
|
|
2018-04-14 11:45:48 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private HeapElement extractMax() {
|
|
|
|
HeapElement result = maxHeap.get(0);
|
|
|
|
deleteElement(0);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void insertElement(HeapElement element) {
|
|
|
|
maxHeap.add(element);
|
|
|
|
toggleUp(maxHeap.size());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void deleteElement(int elementIndex) {
|
2019-02-06 10:13:55 +08:00
|
|
|
if (maxHeap.isEmpty())
|
|
|
|
try {
|
|
|
|
throw new EmptyHeapException("Attempt to delete an element from an empty heap");
|
|
|
|
} catch (EmptyHeapException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
if ((elementIndex > maxHeap.size()) || (elementIndex <= 0))
|
|
|
|
throw new IndexOutOfBoundsException("Index out of heap range");
|
2018-04-14 11:45:48 +08:00
|
|
|
// The last element in heap replaces the one to be deleted
|
|
|
|
maxHeap.set(elementIndex - 1, getElement(maxHeap.size()));
|
|
|
|
maxHeap.remove(maxHeap.size());
|
|
|
|
// Shall the new element be moved up...
|
2020-05-25 05:21:28 +08:00
|
|
|
if (getElementKey(elementIndex) > getElementKey((int) Math.floor(elementIndex / 2.0))) toggleUp(elementIndex);
|
2019-02-06 10:13:55 +08:00
|
|
|
// ... or down ?
|
|
|
|
else if (((2 * elementIndex <= maxHeap.size()) && (getElementKey(elementIndex) < getElementKey(elementIndex * 2))) ||
|
|
|
|
((2 * elementIndex < maxHeap.size()) && (getElementKey(elementIndex) < getElementKey(elementIndex * 2))))
|
|
|
|
toggleDown(elementIndex);
|
2018-04-14 11:45:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public HeapElement getElement() throws EmptyHeapException {
|
|
|
|
try {
|
|
|
|
return extractMax();
|
|
|
|
} catch (Exception e) {
|
|
|
|
throw new EmptyHeapException("Heap is empty. Error retrieving element");
|
|
|
|
}
|
|
|
|
}
|
2019-02-06 10:13:55 +08:00
|
|
|
}
|