data-structure-typed 1.36.7 → 1.36.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +1 -1
- package/CHANGELOG.md +2 -1
- package/dist/data-structures/heap/heap.d.ts +136 -11
- package/dist/data-structures/heap/heap.js +293 -13
- package/dist/data-structures/heap/heap.js.map +1 -1
- package/lib/data-structures/heap/heap.d.ts +136 -11
- package/lib/data-structures/heap/heap.js +290 -12
- package/package.json +3 -2
- package/src/data-structures/heap/heap.ts +337 -16
- package/test/types/index.ts +1 -0
- package/test/types/utils/big-o.ts +1 -0
- package/test/types/utils/index.ts +1 -0
- package/test/unit/data-structures/heap/heap.test.ts +189 -1
- package/test/utils/big-o.ts +193 -0
- package/test/utils/index.ts +1 -1
- package/umd/bundle.min.js +1 -1
- package/umd/bundle.min.js.map +1 -1
- package/test/utils/magnitude.ts +0 -21
|
@@ -10,7 +10,7 @@ import {DFSOrderPattern} from '../../types';
|
|
|
10
10
|
|
|
11
11
|
export class Heap<E> {
|
|
12
12
|
protected nodes: E[] = [];
|
|
13
|
-
|
|
13
|
+
protected readonly comparator: Comparator<E>;
|
|
14
14
|
|
|
15
15
|
constructor(comparator: Comparator<E>) {
|
|
16
16
|
this.comparator = comparator;
|
|
@@ -18,21 +18,29 @@ export class Heap<E> {
|
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Insert an element into the heap and maintain the heap properties.
|
|
21
|
-
* @param
|
|
21
|
+
* @param element - The element to be inserted.
|
|
22
22
|
*/
|
|
23
|
-
add(
|
|
24
|
-
this.
|
|
23
|
+
add(element: E): Heap<E> {
|
|
24
|
+
return this.push(element);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Insert an element into the heap and maintain the heap properties.
|
|
29
|
+
* @param element - The element to be inserted.
|
|
30
|
+
*/
|
|
31
|
+
push(element: E): Heap<E> {
|
|
32
|
+
this.nodes.push(element);
|
|
25
33
|
this.bubbleUp(this.nodes.length - 1);
|
|
26
34
|
return this;
|
|
27
35
|
}
|
|
28
36
|
|
|
29
37
|
/**
|
|
30
38
|
* Remove and return the top element (smallest or largest element) from the heap.
|
|
31
|
-
* @returns The top element or
|
|
39
|
+
* @returns The top element or undefined if the heap is empty.
|
|
32
40
|
*/
|
|
33
|
-
poll(): E |
|
|
41
|
+
poll(): E | undefined {
|
|
34
42
|
if (this.nodes.length === 0) {
|
|
35
|
-
return
|
|
43
|
+
return undefined;
|
|
36
44
|
}
|
|
37
45
|
if (this.nodes.length === 1) {
|
|
38
46
|
return this.nodes.pop() as E;
|
|
@@ -44,6 +52,14 @@ export class Heap<E> {
|
|
|
44
52
|
return topValue;
|
|
45
53
|
}
|
|
46
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Remove and return the top element (smallest or largest element) from the heap.
|
|
57
|
+
* @returns The top element or undefined if the heap is empty.
|
|
58
|
+
*/
|
|
59
|
+
pop(): E | undefined {
|
|
60
|
+
return this.poll();
|
|
61
|
+
}
|
|
62
|
+
|
|
47
63
|
/**
|
|
48
64
|
* Float operation to maintain heap properties after adding an element.
|
|
49
65
|
* @param index - The index of the newly added element.
|
|
@@ -97,11 +113,11 @@ export class Heap<E> {
|
|
|
97
113
|
|
|
98
114
|
/**
|
|
99
115
|
* Peek at the top element of the heap without removing it.
|
|
100
|
-
* @returns The top element or
|
|
116
|
+
* @returns The top element or undefined if the heap is empty.
|
|
101
117
|
*/
|
|
102
|
-
peek(): E |
|
|
118
|
+
peek(): E | undefined {
|
|
103
119
|
if (this.nodes.length === 0) {
|
|
104
|
-
return
|
|
120
|
+
return undefined;
|
|
105
121
|
}
|
|
106
122
|
return this.nodes[0];
|
|
107
123
|
}
|
|
@@ -115,10 +131,10 @@ export class Heap<E> {
|
|
|
115
131
|
|
|
116
132
|
/**
|
|
117
133
|
* Get the last element in the heap, which is not necessarily a leaf node.
|
|
118
|
-
* @returns The last element or
|
|
134
|
+
* @returns The last element or undefined if the heap is empty.
|
|
119
135
|
*/
|
|
120
|
-
get leaf(): E |
|
|
121
|
-
return this.nodes[this.size - 1] ??
|
|
136
|
+
get leaf(): E | undefined {
|
|
137
|
+
return this.nodes[this.size - 1] ?? undefined;
|
|
122
138
|
}
|
|
123
139
|
|
|
124
140
|
/**
|
|
@@ -147,11 +163,11 @@ export class Heap<E> {
|
|
|
147
163
|
|
|
148
164
|
/**
|
|
149
165
|
* Use a comparison function to check whether a binary heap contains a specific element.
|
|
150
|
-
* @param
|
|
166
|
+
* @param element - the element to check.
|
|
151
167
|
* @returns Returns true if the specified element is contained; otherwise, returns false.
|
|
152
168
|
*/
|
|
153
|
-
has(
|
|
154
|
-
return this.nodes.includes(
|
|
169
|
+
has(element: E): boolean {
|
|
170
|
+
return this.nodes.includes(element);
|
|
155
171
|
}
|
|
156
172
|
|
|
157
173
|
/**
|
|
@@ -235,3 +251,308 @@ export class Heap<E> {
|
|
|
235
251
|
return binaryHeap;
|
|
236
252
|
}
|
|
237
253
|
}
|
|
254
|
+
|
|
255
|
+
export class FibonacciHeapNode<E> {
|
|
256
|
+
element: E;
|
|
257
|
+
degree: number;
|
|
258
|
+
left?: FibonacciHeapNode<E>;
|
|
259
|
+
right?: FibonacciHeapNode<E>;
|
|
260
|
+
child?: FibonacciHeapNode<E>;
|
|
261
|
+
parent?: FibonacciHeapNode<E>;
|
|
262
|
+
marked: boolean;
|
|
263
|
+
constructor(element: E, degree = 0) {
|
|
264
|
+
this.element = element;
|
|
265
|
+
this.degree = degree;
|
|
266
|
+
this.marked = false;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
export class FibonacciHeap<E> {
|
|
271
|
+
root?: FibonacciHeapNode<E>;
|
|
272
|
+
protected min?: FibonacciHeapNode<E>;
|
|
273
|
+
size: number = 0;
|
|
274
|
+
protected readonly comparator: Comparator<E>;
|
|
275
|
+
|
|
276
|
+
constructor(comparator?: Comparator<E>) {
|
|
277
|
+
this.clear();
|
|
278
|
+
this.comparator = comparator || this.defaultComparator;
|
|
279
|
+
|
|
280
|
+
if (typeof this.comparator !== 'function') {
|
|
281
|
+
throw new Error('FibonacciHeap constructor: given comparator should be a function.');
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Default comparator function used by the heap.
|
|
287
|
+
* @param {E} a
|
|
288
|
+
* @param {E} b
|
|
289
|
+
* @protected
|
|
290
|
+
*/
|
|
291
|
+
protected defaultComparator(a: E, b: E): number {
|
|
292
|
+
if (a < b) return -1;
|
|
293
|
+
if (a > b) return 1;
|
|
294
|
+
return 0;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Get the size (number of elements) of the heap.
|
|
299
|
+
* @returns {number} The size of the heap. Returns 0 if the heap is empty. Returns -1 if the heap is invalid.
|
|
300
|
+
*/
|
|
301
|
+
clear(): void {
|
|
302
|
+
this.root = undefined;
|
|
303
|
+
this.min = undefined;
|
|
304
|
+
this.size = 0;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Create a new node.
|
|
309
|
+
* @param element
|
|
310
|
+
* @protected
|
|
311
|
+
*/
|
|
312
|
+
protected createNode(element: E): FibonacciHeapNode<E> {
|
|
313
|
+
return new FibonacciHeapNode<E>(element);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Merge the given node with the root list.
|
|
318
|
+
* @param node - The node to be merged.
|
|
319
|
+
*/
|
|
320
|
+
protected mergeWithRoot(node: FibonacciHeapNode<E>): void {
|
|
321
|
+
if (!this.root) {
|
|
322
|
+
this.root = node;
|
|
323
|
+
} else {
|
|
324
|
+
node.right = this.root.right;
|
|
325
|
+
node.left = this.root;
|
|
326
|
+
this.root.right!.left = node;
|
|
327
|
+
this.root.right = node;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* O(1) time operation.
|
|
333
|
+
* Insert an element into the heap and maintain the heap properties.
|
|
334
|
+
* @param element
|
|
335
|
+
* @returns {FibonacciHeap<E>} FibonacciHeap<E> - The heap itself.
|
|
336
|
+
*/
|
|
337
|
+
add(element: E): FibonacciHeap<E> {
|
|
338
|
+
return this.push(element);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* O(1) time operation.
|
|
343
|
+
* Insert an element into the heap and maintain the heap properties.
|
|
344
|
+
* @param element
|
|
345
|
+
* @returns {FibonacciHeap<E>} FibonacciHeap<E> - The heap itself.
|
|
346
|
+
*/
|
|
347
|
+
push(element: E): FibonacciHeap<E> {
|
|
348
|
+
const node = this.createNode(element);
|
|
349
|
+
node.left = node;
|
|
350
|
+
node.right = node;
|
|
351
|
+
this.mergeWithRoot(node);
|
|
352
|
+
|
|
353
|
+
if (!this.min || this.comparator(node.element, this.min.element) <= 0) {
|
|
354
|
+
this.min = node;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
this.size++;
|
|
358
|
+
return this;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* O(1) time operation.
|
|
363
|
+
* Peek at the top element of the heap without removing it.
|
|
364
|
+
* @returns The top element or undefined if the heap is empty.
|
|
365
|
+
* @protected
|
|
366
|
+
*/
|
|
367
|
+
peek(): E | undefined {
|
|
368
|
+
return this.min ? this.min.element : undefined;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* O(1) time operation.
|
|
373
|
+
* Get the size (number of elements) of the heap.
|
|
374
|
+
* @param {FibonacciHeapNode<E>} head - The head of the linked list.
|
|
375
|
+
* @protected
|
|
376
|
+
* @returns FibonacciHeapNode<E>[] - An array containing the nodes of the linked list.
|
|
377
|
+
*/
|
|
378
|
+
consumeLinkedList(head?: FibonacciHeapNode<E>): FibonacciHeapNode<E>[] {
|
|
379
|
+
const nodes: FibonacciHeapNode<E>[] = [];
|
|
380
|
+
if (!head) return nodes;
|
|
381
|
+
|
|
382
|
+
let node: FibonacciHeapNode<E> | undefined = head;
|
|
383
|
+
let flag = false;
|
|
384
|
+
|
|
385
|
+
while (true) {
|
|
386
|
+
if (node === head && flag) break;
|
|
387
|
+
else if (node === head) flag = true;
|
|
388
|
+
|
|
389
|
+
if (node) {
|
|
390
|
+
nodes.push(node);
|
|
391
|
+
node = node.right;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
return nodes;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* O(log n) time operation.
|
|
400
|
+
* Remove and return the top element (smallest or largest element) from the heap.
|
|
401
|
+
* @param node - The node to be removed.
|
|
402
|
+
* @protected
|
|
403
|
+
*/
|
|
404
|
+
protected removeFromRoot(node: FibonacciHeapNode<E>): void {
|
|
405
|
+
if (this.root === node) this.root = node.right;
|
|
406
|
+
if (node.left) node.left.right = node.right;
|
|
407
|
+
if (node.right) node.right.left = node.left;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* O(log n) time operation.
|
|
412
|
+
* Remove and return the top element (smallest or largest element) from the heap.
|
|
413
|
+
* @param parent
|
|
414
|
+
* @param node
|
|
415
|
+
*/
|
|
416
|
+
mergeWithChild(parent: FibonacciHeapNode<E>, node: FibonacciHeapNode<E>): void {
|
|
417
|
+
if (!parent.child) {
|
|
418
|
+
parent.child = node;
|
|
419
|
+
} else {
|
|
420
|
+
node.right = parent.child.right;
|
|
421
|
+
node.left = parent.child;
|
|
422
|
+
parent.child.right!.left = node;
|
|
423
|
+
parent.child.right = node;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* O(log n) time operation.
|
|
429
|
+
* Remove and return the top element (smallest or largest element) from the heap.
|
|
430
|
+
* @param y
|
|
431
|
+
* @param x
|
|
432
|
+
* @protected
|
|
433
|
+
*/
|
|
434
|
+
protected link(y: FibonacciHeapNode<E>, x: FibonacciHeapNode<E>): void {
|
|
435
|
+
this.removeFromRoot(y);
|
|
436
|
+
y.left = y;
|
|
437
|
+
y.right = y;
|
|
438
|
+
this.mergeWithChild(x, y);
|
|
439
|
+
x.degree++;
|
|
440
|
+
y.parent = x;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* O(log n) time operation.
|
|
445
|
+
* Remove and return the top element (smallest or largest element) from the heap.
|
|
446
|
+
* @protected
|
|
447
|
+
*/
|
|
448
|
+
protected consolidate(): void {
|
|
449
|
+
const A: (FibonacciHeapNode<E> | undefined)[] = new Array(this.size);
|
|
450
|
+
const nodes = this.consumeLinkedList(this.root);
|
|
451
|
+
let x: FibonacciHeapNode<E> | undefined, y: FibonacciHeapNode<E> | undefined, d: number, t: FibonacciHeapNode<E> | undefined;
|
|
452
|
+
|
|
453
|
+
for (const node of nodes) {
|
|
454
|
+
x = node;
|
|
455
|
+
d = x.degree;
|
|
456
|
+
|
|
457
|
+
while (A[d]) {
|
|
458
|
+
y = A[d] as FibonacciHeapNode<E>;
|
|
459
|
+
|
|
460
|
+
if (this.comparator(x.element, y.element) > 0) {
|
|
461
|
+
t = x;
|
|
462
|
+
x = y;
|
|
463
|
+
y = t;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
this.link(y, x);
|
|
467
|
+
A[d] = undefined;
|
|
468
|
+
d++;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
A[d] = x;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
for (let i = 0; i < this.size; i++) {
|
|
475
|
+
if (A[i] && this.comparator(A[i]!.element, this.min!.element) <= 0) {
|
|
476
|
+
this.min = A[i]!;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* O(log n) time operation.
|
|
483
|
+
* Remove and return the top element (smallest or largest element) from the heap.
|
|
484
|
+
* @returns The top element or undefined if the heap is empty.
|
|
485
|
+
*/
|
|
486
|
+
poll(): E | undefined {
|
|
487
|
+
return this.pop();
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* O(log n) time operation.
|
|
492
|
+
* Remove and return the top element (smallest or largest element) from the heap.
|
|
493
|
+
* @returns The top element or undefined if the heap is empty.
|
|
494
|
+
*/
|
|
495
|
+
pop(): E | undefined {
|
|
496
|
+
if (this.size === 0) return undefined;
|
|
497
|
+
|
|
498
|
+
const z = this.min!;
|
|
499
|
+
if (z.child) {
|
|
500
|
+
const nodes = this.consumeLinkedList(z.child);
|
|
501
|
+
for (const node of nodes) {
|
|
502
|
+
this.mergeWithRoot(node);
|
|
503
|
+
node.parent = undefined;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
this.removeFromRoot(z);
|
|
508
|
+
|
|
509
|
+
if (z === z.right) {
|
|
510
|
+
this.min = undefined;
|
|
511
|
+
this.root = undefined;
|
|
512
|
+
} else {
|
|
513
|
+
this.min = z.right;
|
|
514
|
+
this.consolidate();
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
this.size--;
|
|
518
|
+
|
|
519
|
+
return z.element;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* O(log n) time operation.
|
|
524
|
+
* merge two heaps. The heap that is merged will be cleared. The heap that is merged into will remain.
|
|
525
|
+
* @param heapToMerge
|
|
526
|
+
*/
|
|
527
|
+
merge(heapToMerge: FibonacciHeap<E>): void {
|
|
528
|
+
if (heapToMerge.size === 0) {
|
|
529
|
+
return; // Nothing to merge
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// Merge the root lists of the two heaps
|
|
533
|
+
if (this.root && heapToMerge.root) {
|
|
534
|
+
const thisRoot = this.root;
|
|
535
|
+
const otherRoot = heapToMerge.root;
|
|
536
|
+
|
|
537
|
+
const thisRootRight = thisRoot.right!;
|
|
538
|
+
const otherRootLeft = otherRoot.left!;
|
|
539
|
+
|
|
540
|
+
thisRoot.right = otherRoot;
|
|
541
|
+
otherRoot.left = thisRoot;
|
|
542
|
+
|
|
543
|
+
thisRootRight.left = otherRootLeft;
|
|
544
|
+
otherRootLeft.right = thisRootRight;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// Update the minimum node
|
|
548
|
+
if (!this.min || (heapToMerge.min && this.comparator(heapToMerge.min.element, this.min.element) < 0)) {
|
|
549
|
+
this.min = heapToMerge.min;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// Update the size
|
|
553
|
+
this.size += heapToMerge.size;
|
|
554
|
+
|
|
555
|
+
// Clear the heap that was merged
|
|
556
|
+
heapToMerge.clear();
|
|
557
|
+
}
|
|
558
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './utils';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type AnyFunction = (...args: any[]) => any;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './big-o';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {MaxHeap, MinHeap} from '../../../../src';
|
|
1
|
+
import {FibonacciHeap, MaxHeap, MinHeap} from '../../../../src';
|
|
2
|
+
import {logBigOMetricsWrap} from "../../../utils";
|
|
2
3
|
|
|
3
4
|
describe('Heap Operation Test', () => {
|
|
4
5
|
it('should numeric heap work well', function () {
|
|
@@ -60,3 +61,190 @@ describe('Heap Operation Test', () => {
|
|
|
60
61
|
}
|
|
61
62
|
});
|
|
62
63
|
});
|
|
64
|
+
|
|
65
|
+
describe('FibonacciHeap', () => {
|
|
66
|
+
let heap: FibonacciHeap<number>;
|
|
67
|
+
|
|
68
|
+
beforeEach(() => {
|
|
69
|
+
heap = new FibonacciHeap<number>();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test('push & peek', () => {
|
|
73
|
+
heap.push(10);
|
|
74
|
+
heap.push(5);
|
|
75
|
+
expect(heap.peek()).toBe(5);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test('pop', () => {
|
|
79
|
+
heap.push(10);
|
|
80
|
+
heap.push(5);
|
|
81
|
+
heap.push(15);
|
|
82
|
+
expect(heap.pop()).toBe(5);
|
|
83
|
+
expect(heap.pop()).toBe(10);
|
|
84
|
+
expect(heap.pop()).toBe(15);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test('pop on an empty heap', () => {
|
|
88
|
+
expect(heap.pop()).toBeUndefined();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test('size', () => {
|
|
92
|
+
expect(heap.size).toBe(0);
|
|
93
|
+
heap.push(10);
|
|
94
|
+
expect(heap.size).toBe(1);
|
|
95
|
+
heap.pop();
|
|
96
|
+
expect(heap.size).toBe(0);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test('clear', () => {
|
|
100
|
+
heap.push(10);
|
|
101
|
+
heap.push(5);
|
|
102
|
+
heap.clear();
|
|
103
|
+
expect(heap.size).toBe(0);
|
|
104
|
+
expect(heap.peek()).toBeUndefined();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test('custom comparator', () => {
|
|
108
|
+
const maxHeap = new FibonacciHeap<number>((a, b) => b - a);
|
|
109
|
+
maxHeap.push(10);
|
|
110
|
+
maxHeap.push(5);
|
|
111
|
+
expect(maxHeap.peek()).toBe(10);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
describe('FibonacciHeap', () => {
|
|
116
|
+
let heap: FibonacciHeap<number>;
|
|
117
|
+
|
|
118
|
+
beforeEach(() => {
|
|
119
|
+
heap = new FibonacciHeap<number>();
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('should initialize an empty heap', () => {
|
|
123
|
+
expect(heap.size).toBe(0);
|
|
124
|
+
expect(heap.peek()).toBeUndefined();
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('should push items into the heap and update size', () => {
|
|
128
|
+
heap.push(10);
|
|
129
|
+
heap.push(5);
|
|
130
|
+
|
|
131
|
+
expect(heap.size).toBe(2);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('should peek the minimum item', () => {
|
|
135
|
+
heap.push(10);
|
|
136
|
+
heap.push(5);
|
|
137
|
+
heap.push(15);
|
|
138
|
+
|
|
139
|
+
expect(heap.peek()).toBe(5);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('should pop the minimum item and update size', () => {
|
|
143
|
+
heap.push(10);
|
|
144
|
+
heap.push(5);
|
|
145
|
+
heap.push(15);
|
|
146
|
+
|
|
147
|
+
const minItem = heap.pop();
|
|
148
|
+
|
|
149
|
+
expect(minItem).toBe(5);
|
|
150
|
+
expect(heap.size).toBe(2);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('should correctly merge two heaps', () => {
|
|
154
|
+
const heap1 = new FibonacciHeap<number>();
|
|
155
|
+
const heap2 = new FibonacciHeap<number>();
|
|
156
|
+
|
|
157
|
+
heap1.push(10);
|
|
158
|
+
heap2.push(5);
|
|
159
|
+
|
|
160
|
+
heap1.merge(heap2);
|
|
161
|
+
|
|
162
|
+
expect(heap1.size).toBe(2);
|
|
163
|
+
expect(heap1.peek()).toBe(5);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('should clear the heap', () => {
|
|
167
|
+
heap.push(10);
|
|
168
|
+
heap.push(5);
|
|
169
|
+
|
|
170
|
+
heap.clear();
|
|
171
|
+
|
|
172
|
+
expect(heap.size).toBe(0);
|
|
173
|
+
expect(heap.peek()).toBeUndefined();
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('should handle custom comparators', () => {
|
|
177
|
+
const customComparator = (a: number, b: number) => b - a;
|
|
178
|
+
const customHeap = new FibonacciHeap<number>(customComparator);
|
|
179
|
+
|
|
180
|
+
customHeap.push(10);
|
|
181
|
+
customHeap.push(5);
|
|
182
|
+
customHeap.push(15);
|
|
183
|
+
|
|
184
|
+
expect(customHeap.peek()).toBe(15);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
describe('FibonacciHeap Merge', () => {
|
|
188
|
+
it('should merge two Fibonacci heaps correctly', () => {
|
|
189
|
+
const heap1 = new FibonacciHeap<number>();
|
|
190
|
+
heap1.push(5).push(10);
|
|
191
|
+
|
|
192
|
+
const heap2 = new FibonacciHeap<number>();
|
|
193
|
+
heap2.push(3).push(7);
|
|
194
|
+
|
|
195
|
+
heap1.merge(heap2);
|
|
196
|
+
|
|
197
|
+
expect(heap1.size).toBe(4); // Combined size of both heaps
|
|
198
|
+
expect(heap2.size).toBe(0); // Merged heap should be empty
|
|
199
|
+
expect(heap1.peek()).toBe(3); // Minimum element should be 3
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
describe('FibonacciHeap Stress Test', () => {
|
|
206
|
+
it('should handle a large number of elements efficiently', () => {
|
|
207
|
+
|
|
208
|
+
const testByMagnitude = (magnitude: number) => {
|
|
209
|
+
const heap = new FibonacciHeap<number>();
|
|
210
|
+
|
|
211
|
+
// Add 1000 elements to the heap
|
|
212
|
+
for (let i = 1; i <= magnitude; i++) {
|
|
213
|
+
heap.push(i);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Verify that the minimum element is 1 (smallest element)
|
|
217
|
+
expect(heap.peek()).toBe(1);
|
|
218
|
+
|
|
219
|
+
// Remove all 1000 elements from the heap
|
|
220
|
+
const elements = [];
|
|
221
|
+
while (heap.size > 0) {
|
|
222
|
+
elements.push(heap.pop());
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Verify that all elements were removed in ascending order
|
|
226
|
+
for (let i = 1; i <= magnitude; i++) {
|
|
227
|
+
expect(elements[i - 1]).toBe(i);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Verify that the heap is now empty
|
|
231
|
+
expect(heap.size).toBe(0);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
testByMagnitude(1000);
|
|
235
|
+
|
|
236
|
+
// [
|
|
237
|
+
// 10, 100, 1000, 5000, 10000, 20000, 50000, 75000, 100000,
|
|
238
|
+
// 150000, 200000, 250000, 300000, 400000, 500000, 600000, 700000, 800000, 900000, 1000000
|
|
239
|
+
// ].forEach(m => logBigOMetricsWrap<typeof testByMagnitude>(testByMagnitude, [m]));
|
|
240
|
+
[
|
|
241
|
+
10, 100, 1000, 5000, 10000, 20000, 50000, 75000, 100000,
|
|
242
|
+
150000, 200000, 250000, 300000, 400000, 500000, 600000, 700000, 800000, 900000, 1000000
|
|
243
|
+
].forEach(m => logBigOMetricsWrap((c: number) => {
|
|
244
|
+
const result: number[] = [];
|
|
245
|
+
for (let i = 0; i < c; i++) result.push(i);
|
|
246
|
+
return result;
|
|
247
|
+
} , [m], 'loopPush'));
|
|
248
|
+
|
|
249
|
+
});
|
|
250
|
+
});
|