Skip to content

Commit a73e373

Browse files
committed
refactor: Enhance docs, add tests in MaxHeap
1 parent 5246f63 commit a73e373

File tree

3 files changed

+287
-49
lines changed

3 files changed

+287
-49
lines changed

src/main/java/com/thealgorithms/datastructures/heaps/Heap.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,5 @@ public interface Heap {
4040
* @param elementIndex int containing the position in the heap of the
4141
* element to be deleted.
4242
*/
43-
void deleteElement(int elementIndex);
43+
void deleteElement(int elementIndex) throws EmptyHeapException;
4444
}

src/main/java/com/thealgorithms/datastructures/heaps/MaxHeap.java

Lines changed: 136 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,46 @@
44
import java.util.List;
55

66
/**
7-
* Heap tree where a node's key is higher than or equal to its parent's and
8-
* lower than or equal to its children's.
7+
* A Max Heap implementation where each node's key is higher than or equal to its children's keys.
8+
* This data structure provides O(log n) time complexity for insertion and deletion operations,
9+
* and O(1) for retrieving the maximum element.
10+
*
11+
* Properties:
12+
* 1. Complete Binary Tree
13+
* 2. Parent node's key ≥ Children nodes' keys
14+
* 3. Root contains the maximum element
15+
*
16+
* Example usage:
17+
* ```java
18+
* List<HeapElement> elements = Arrays.asList(
19+
* new HeapElement(5, "Five"),
20+
* new HeapElement(2, "Two")
21+
* );
22+
* MaxHeap heap = new MaxHeap(elements);
23+
* heap.insertElement(new HeapElement(7, "Seven"));
24+
* HeapElement max = heap.getElement(); // Returns and removes the maximum element
25+
* ```
926
*
1027
* @author Nicolas Renard
28+
* @author [Your name] (documentation improvements)
1129
*/
1230
public class MaxHeap implements Heap {
1331

32+
/** The internal list that stores heap elements */
1433
private final List<HeapElement> maxHeap;
1534

35+
/**
36+
* Constructs a new MaxHeap from a list of elements.
37+
* Null elements in the input list are ignored with a warning message.
38+
*
39+
* @param listElements List of HeapElement objects to initialize the heap
40+
* @throws IllegalArgumentException if the input list is null
41+
*/
1642
public MaxHeap(List<HeapElement> listElements) {
43+
if (listElements == null) {
44+
throw new IllegalArgumentException("Input list cannot be null");
45+
}
46+
1747
maxHeap = new ArrayList<>();
1848
for (HeapElement heapElement : listElements) {
1949
if (heapElement != null) {
@@ -28,104 +58,162 @@ public MaxHeap(List<HeapElement> listElements) {
2858
}
2959

3060
/**
31-
* Get the element at a given index. The key for the list is equal to index
32-
* value - 1
61+
* Retrieves the element at the specified index without removing it.
62+
* Note: The index is 1-based for consistency with heap operations.
3363
*
34-
* @param elementIndex index
35-
* @return heapElement
64+
* @param elementIndex 1-based index of the element to retrieve
65+
* @return HeapElement at the specified index
66+
* @throws IndexOutOfBoundsException if the index is invalid
3667
*/
3768
public HeapElement getElement(int elementIndex) {
3869
if ((elementIndex <= 0) || (elementIndex > maxHeap.size())) {
39-
throw new IndexOutOfBoundsException("Index out of heap range");
70+
throw new IndexOutOfBoundsException("Index " + elementIndex + " is out of heap range [1, " + maxHeap.size() + "]");
4071
}
4172
return maxHeap.get(elementIndex - 1);
4273
}
4374

44-
// Get the key of the element at a given index
75+
/**
76+
* Retrieves the key value of an element at the specified index.
77+
*
78+
* @param elementIndex 1-based index of the element
79+
* @return double value representing the key
80+
* @throws IndexOutOfBoundsException if the index is invalid
81+
*/
4582
private double getElementKey(int elementIndex) {
4683
if ((elementIndex <= 0) || (elementIndex > maxHeap.size())) {
47-
throw new IndexOutOfBoundsException("Index out of heap range");
84+
throw new IndexOutOfBoundsException("Index " + elementIndex + " is out of heap range [1, " + maxHeap.size() + "]");
4885
}
49-
5086
return maxHeap.get(elementIndex - 1).getKey();
5187
}
5288

53-
// Swaps two elements in the heap
89+
/**
90+
* Swaps two elements in the heap.
91+
*
92+
* @param index1 1-based index of first element
93+
* @param index2 1-based index of second element
94+
*/
5495
private void swap(int index1, int index2) {
5596
HeapElement temporaryElement = maxHeap.get(index1 - 1);
5697
maxHeap.set(index1 - 1, maxHeap.get(index2 - 1));
5798
maxHeap.set(index2 - 1, temporaryElement);
5899
}
59100

60-
// Toggle an element up to its right place as long as its key is lower than its parent's
101+
/**
102+
* Moves an element up the heap until heap properties are satisfied.
103+
* This operation is called after insertion to maintain heap properties.
104+
*
105+
* @param elementIndex 1-based index of the element to move up
106+
*/
61107
private void toggleUp(int elementIndex) {
62108
double key = maxHeap.get(elementIndex - 1).getKey();
63-
while (getElementKey((int) Math.floor(elementIndex / 2.0)) < key) {
109+
while (elementIndex > 1 && getElementKey((int) Math.floor(elementIndex / 2.0)) < key) {
64110
swap(elementIndex, (int) Math.floor(elementIndex / 2.0));
65111
elementIndex = (int) Math.floor(elementIndex / 2.0);
66112
}
67113
}
68114

69-
// Toggle an element down to its right place as long as its key is higher
70-
// than any of its children's
115+
/**
116+
* Moves an element down the heap until heap properties are satisfied.
117+
* This operation is called after deletion to maintain heap properties.
118+
*
119+
* @param elementIndex 1-based index of the element to move down
120+
*/
71121
private void toggleDown(int elementIndex) {
72122
double key = maxHeap.get(elementIndex - 1).getKey();
73-
boolean wrongOrder = (key < getElementKey(elementIndex * 2)) || (key < getElementKey(Math.min(elementIndex * 2, maxHeap.size())));
74-
while ((2 * elementIndex <= maxHeap.size()) && wrongOrder) {
75-
// Check whether it shall swap the element with its left child or its right one if any.
76-
if ((2 * elementIndex < maxHeap.size()) && (getElementKey(elementIndex * 2 + 1) > getElementKey(elementIndex * 2))) {
77-
swap(elementIndex, 2 * elementIndex + 1);
78-
elementIndex = 2 * elementIndex + 1;
123+
boolean wrongOrder = (2 * elementIndex <= maxHeap.size() && key < getElementKey(elementIndex * 2)) || (2 * elementIndex + 1 <= maxHeap.size() && key < getElementKey(elementIndex * 2 + 1));
124+
125+
while (2 * elementIndex <= maxHeap.size() && wrongOrder) {
126+
int largerChildIndex;
127+
if (2 * elementIndex + 1 <= maxHeap.size() && getElementKey(elementIndex * 2 + 1) > getElementKey(elementIndex * 2)) {
128+
largerChildIndex = 2 * elementIndex + 1;
79129
} else {
80-
swap(elementIndex, 2 * elementIndex);
81-
elementIndex = 2 * elementIndex;
130+
largerChildIndex = 2 * elementIndex;
82131
}
83-
wrongOrder = (key < getElementKey(elementIndex * 2)) || (key < getElementKey(Math.min(elementIndex * 2, maxHeap.size())));
132+
133+
swap(elementIndex, largerChildIndex);
134+
elementIndex = largerChildIndex;
135+
136+
wrongOrder = (2 * elementIndex <= maxHeap.size() && key < getElementKey(elementIndex * 2)) || (2 * elementIndex + 1 <= maxHeap.size() && key < getElementKey(elementIndex * 2 + 1));
84137
}
85138
}
86139

87-
private HeapElement extractMax() {
140+
/**
141+
* Extracts and returns the maximum element from the heap.
142+
*
143+
* @return HeapElement with the highest key
144+
* @throws EmptyHeapException if the heap is empty
145+
*/
146+
private HeapElement extractMax() throws EmptyHeapException {
147+
if (maxHeap.isEmpty()) {
148+
throw new EmptyHeapException("Cannot extract from empty heap");
149+
}
88150
HeapElement result = maxHeap.get(0);
89-
deleteElement(0);
151+
deleteElement(1);
90152
return result;
91153
}
92154

155+
/**
156+
* {@inheritDoc}
157+
*/
93158
@Override
94-
public final void insertElement(HeapElement element) {
159+
public void insertElement(HeapElement element) {
160+
if (element == null) {
161+
throw new IllegalArgumentException("Cannot insert null element");
162+
}
95163
maxHeap.add(element);
96164
toggleUp(maxHeap.size());
97165
}
98166

167+
/**
168+
* {@inheritDoc}
169+
*/
99170
@Override
100-
public void deleteElement(int elementIndex) {
171+
public void deleteElement(int elementIndex) throws EmptyHeapException {
101172
if (maxHeap.isEmpty()) {
102-
try {
103-
throw new EmptyHeapException("Attempt to delete an element from an empty heap");
104-
} catch (EmptyHeapException e) {
105-
e.printStackTrace();
106-
}
173+
throw new EmptyHeapException("Cannot delete from empty heap");
107174
}
108175
if ((elementIndex > maxHeap.size()) || (elementIndex <= 0)) {
109-
throw new IndexOutOfBoundsException("Index out of heap range");
176+
throw new IndexOutOfBoundsException("Index " + elementIndex + " is out of heap range [1, " + maxHeap.size() + "]");
110177
}
111-
// The last element in heap replaces the one to be deleted
112-
maxHeap.set(elementIndex - 1, getElement(maxHeap.size()));
113-
maxHeap.remove(maxHeap.size());
114-
// Shall the new element be moved up...
115-
if (getElementKey(elementIndex) > getElementKey((int) Math.floor(elementIndex / 2.0))) {
116-
toggleUp(elementIndex);
117-
} // ... or down ?
118-
else if (((2 * elementIndex <= maxHeap.size()) && (getElementKey(elementIndex) < getElementKey(elementIndex * 2))) || ((2 * elementIndex < maxHeap.size()) && (getElementKey(elementIndex) < getElementKey(elementIndex * 2)))) {
119-
toggleDown(elementIndex);
178+
179+
// Replace with last element and remove last position
180+
maxHeap.set(elementIndex - 1, maxHeap.get(maxHeap.size() - 1));
181+
maxHeap.remove(maxHeap.size() - 1);
182+
183+
// No need to toggle if we just removed the last element
184+
if (!maxHeap.isEmpty() && elementIndex <= maxHeap.size()) {
185+
// Determine whether to toggle up or down
186+
if (elementIndex > 1 && getElementKey(elementIndex) > getElementKey((int) Math.floor(elementIndex / 2.0))) {
187+
toggleUp(elementIndex);
188+
} else {
189+
toggleDown(elementIndex);
190+
}
120191
}
121192
}
122193

194+
/**
195+
* {@inheritDoc}
196+
*/
123197
@Override
124198
public HeapElement getElement() throws EmptyHeapException {
125-
try {
126-
return extractMax();
127-
} catch (Exception e) {
128-
throw new EmptyHeapException("Heap is empty. Error retrieving element", e);
129-
}
199+
return extractMax();
200+
}
201+
202+
/**
203+
* Returns the current size of the heap.
204+
*
205+
* @return number of elements in the heap
206+
*/
207+
public int size() {
208+
return maxHeap.size();
209+
}
210+
211+
/**
212+
* Checks if the heap is empty.
213+
*
214+
* @return true if the heap contains no elements
215+
*/
216+
public boolean isEmpty() {
217+
return maxHeap.isEmpty();
130218
}
131219
}

0 commit comments

Comments
 (0)