@@ -142,6 +142,52 @@ export default class Heap {
142
142
return this ;
143
143
}
144
144
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
+
145
191
/**
146
192
* @param {* } item
147
193
* @param {Comparator } [customComparator]
@@ -174,11 +220,69 @@ export default class Heap {
174
220
return this . heapContainer . toString ( ) ;
175
221
}
176
222
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
+ }
179
239
}
180
240
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
+ ` ) ;
183
287
}
184
288
}
0 commit comments