@@ -142,6 +142,52 @@ export default class Heap {
142142 return this ;
143143 }
144144
145+ /**
146+ * @param {* } item
147+ * @param {Comparator } [customFindingComparator]
148+ * @return {Heap }
149+ */
150+ remove ( item , customFindingComparator ) {
151+ // Find number of items to remove.
152+ const customComparator = customFindingComparator || this . compare ;
153+ const numberOfItemsToRemove = this . find ( item , customComparator ) . length ;
154+
155+ for ( let iteration = 0 ; iteration < numberOfItemsToRemove ; iteration += 1 ) {
156+ // We need to find item index to remove each time after removal since
157+ // indices are being change after each heapify process.
158+ const indexToRemove = this . find ( item , customComparator ) . pop ( ) ;
159+
160+ // If we need to remove last child in the heap then just remove it.
161+ // There is no need to heapify the heap afterwards.
162+ if ( indexToRemove === ( this . heapContainer . length - 1 ) ) {
163+ this . heapContainer . pop ( ) ;
164+ } else {
165+ // Move last element in heap to the vacant (removed) position.
166+ this . heapContainer [ indexToRemove ] = this . heapContainer . pop ( ) ;
167+
168+ // Get parent.
169+ const parentItem = this . hasParent ( indexToRemove ) ? this . parent ( indexToRemove ) : null ;
170+ const leftChild = this . hasLeftChild ( indexToRemove ) ? this . leftChild ( indexToRemove ) : null ;
171+
172+ // If there is no parent or parent is in incorrect order with the node
173+ // we're going to delete then heapify down. Otherwise heapify up.
174+ if (
175+ leftChild !== null
176+ && (
177+ parentItem === null
178+ || ! this . pairIsInCorrectOrder ( parentItem , this . heapContainer [ indexToRemove ] )
179+ )
180+ ) {
181+ this . heapifyDown ( indexToRemove ) ;
182+ } else {
183+ this . heapifyUp ( indexToRemove ) ;
184+ }
185+ }
186+ }
187+
188+ return this ;
189+ }
190+
145191 /**
146192 * @param {* } item
147193 * @param {Comparator } [customComparator]
@@ -174,11 +220,69 @@ export default class Heap {
174220 return this . heapContainer . toString ( ) ;
175221 }
176222
177- heapifyUp ( ) {
178- throw new Error ( 'You have to implement this method!' ) ;
223+ /**
224+ * @param {number } [customStartIndex]
225+ */
226+ heapifyUp ( customStartIndex ) {
227+ // Take last element (last in array or the bottom left in a tree) in
228+ // a heap container and lift him up until we find the parent element
229+ // that is less then the current new one.
230+ let currentIndex = customStartIndex || this . heapContainer . length - 1 ;
231+
232+ while (
233+ this . hasParent ( currentIndex )
234+ && ! this . pairIsInCorrectOrder ( this . parent ( currentIndex ) , this . heapContainer [ currentIndex ] )
235+ ) {
236+ this . swap ( currentIndex , this . getParentIndex ( currentIndex ) ) ;
237+ currentIndex = this . getParentIndex ( currentIndex ) ;
238+ }
179239 }
180240
181- heapifyDown ( ) {
182- throw new Error ( 'You have to implement this method!' ) ;
241+ /**
242+ * @param {number } [customStartIndex]
243+ */
244+ heapifyDown ( customStartIndex ) {
245+ // Compare the root element to its children and swap root with the smallest
246+ // of children. Do the same for next children after swap.
247+ let currentIndex = customStartIndex || 0 ;
248+ let nextIndex = null ;
249+
250+ while ( this . hasLeftChild ( currentIndex ) ) {
251+ if (
252+ this . hasRightChild ( currentIndex )
253+ && this . pairIsInCorrectOrder ( this . rightChild ( currentIndex ) , this . leftChild ( currentIndex ) )
254+ ) {
255+ nextIndex = this . getRightChildIndex ( currentIndex ) ;
256+ } else {
257+ nextIndex = this . getLeftChildIndex ( currentIndex ) ;
258+ }
259+
260+ if ( ! this . pairIsInCorrectOrder (
261+ this . heapContainer [ nextIndex ] ,
262+ this . heapContainer [ currentIndex ] ,
263+ ) ) {
264+ break ;
265+ }
266+
267+ this . swap ( currentIndex , nextIndex ) ;
268+ currentIndex = nextIndex ;
269+ }
270+ }
271+
272+ /**
273+ * Checks if pair of heap elements is in correct order.
274+ * For MinHeap the first element must be always smaller or equal.
275+ * For MaxHeap the first element must be always bigger or equal.
276+ *
277+ * @param {* } firstElement
278+ * @param {* } secondElement
279+ * @return {boolean }
280+ */
281+ /* istanbul ignore next */
282+ pairIsInCorrectOrder ( firstElement , secondElement ) {
283+ throw new Error ( `
284+ You have to implement heap pair comparision method
285+ for ${ firstElement } and ${ secondElement } values.
286+ ` ) ;
183287 }
184288}
0 commit comments