44import 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 */
1230public 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