data-structure-typed 1.36.9 → 1.37.0
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/CHANGELOG.md +2 -1
- package/dist/data-structures/binary-tree/binary-tree.d.ts +1 -11
- package/dist/data-structures/binary-tree/binary-tree.js +8 -57
- package/dist/data-structures/binary-tree/binary-tree.js.map +1 -1
- package/dist/data-structures/binary-tree/bst.d.ts +6 -20
- package/dist/data-structures/binary-tree/bst.js +22 -122
- package/dist/data-structures/binary-tree/bst.js.map +1 -1
- package/dist/data-structures/binary-tree/tree-multiset.d.ts +1 -55
- package/dist/data-structures/binary-tree/tree-multiset.js +3 -240
- package/dist/data-structures/binary-tree/tree-multiset.js.map +1 -1
- package/dist/data-structures/graph/abstract-graph.js +4 -3
- package/dist/data-structures/graph/abstract-graph.js.map +1 -1
- package/lib/data-structures/binary-tree/binary-tree.d.ts +1 -11
- package/lib/data-structures/binary-tree/binary-tree.js +8 -57
- package/lib/data-structures/binary-tree/bst.d.ts +6 -20
- package/lib/data-structures/binary-tree/bst.js +22 -122
- package/lib/data-structures/binary-tree/tree-multiset.d.ts +1 -55
- package/lib/data-structures/binary-tree/tree-multiset.js +3 -240
- package/lib/data-structures/graph/abstract-graph.js +4 -3
- package/package.json +9 -7
- package/src/data-structures/binary-tree/binary-tree.ts +8 -62
- package/src/data-structures/binary-tree/bst.ts +22 -106
- package/src/data-structures/binary-tree/tree-multiset.ts +3 -231
- package/src/data-structures/graph/abstract-graph.ts +4 -3
- package/test/unit/data-structures/binary-tree/avl-tree.test.ts +5 -3
- package/test/unit/data-structures/binary-tree/bst.test.ts +44 -7
- package/test/unit/data-structures/binary-tree/overall.test.ts +1 -1
- package/test/unit/data-structures/binary-tree/tree-multiset.test.ts +39 -9
- package/test/unit/data-structures/queue/deque.test.ts +17 -0
- package/test/unit/data-structures/queue/queue.test.ts +42 -0
- package/test/utils/big-o.ts +5 -4
- package/umd/bundle.min.js +1 -1
- package/umd/bundle.min.js.map +1 -1
|
@@ -9,6 +9,7 @@ import type {BinaryTreeNodeKey, TreeMultisetNodeNested, TreeMultisetOptions} fro
|
|
|
9
9
|
import {BinaryTreeDeletedResult, CP, DFSOrderPattern, FamilyPosition, LoopType} from '../../types';
|
|
10
10
|
import {IBinaryTree} from '../../interfaces';
|
|
11
11
|
import {AVLTree, AVLTreeNode} from './avl-tree';
|
|
12
|
+
import {Queue} from '../queue';
|
|
12
13
|
|
|
13
14
|
export class TreeMultisetNode<
|
|
14
15
|
V = any,
|
|
@@ -349,121 +350,6 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
|
|
|
349
350
|
return bstDeletedResult;
|
|
350
351
|
}
|
|
351
352
|
|
|
352
|
-
/**
|
|
353
|
-
* The function `getSubTreeCount` calculates the number of nodes and the sum of their counts in a subtree, using either
|
|
354
|
-
* recursive or iterative traversal.
|
|
355
|
-
* @param {N | null | undefined} subTreeRoot - The `subTreeRoot` parameter represents the root node of a subtree in a
|
|
356
|
-
* binary tree.
|
|
357
|
-
* @returns The function `getSubTreeCount` returns an array `[number, number]`.
|
|
358
|
-
*/
|
|
359
|
-
getSubTreeCount(subTreeRoot: N | null | undefined) {
|
|
360
|
-
const res: [number, number] = [0, 0];
|
|
361
|
-
if (!subTreeRoot) return res;
|
|
362
|
-
|
|
363
|
-
if (this.loopType === LoopType.RECURSIVE) {
|
|
364
|
-
const _traverse = (cur: N) => {
|
|
365
|
-
res[0]++;
|
|
366
|
-
res[1] += cur.count;
|
|
367
|
-
cur.left && _traverse(cur.left);
|
|
368
|
-
cur.right && _traverse(cur.right);
|
|
369
|
-
};
|
|
370
|
-
|
|
371
|
-
_traverse(subTreeRoot);
|
|
372
|
-
return res;
|
|
373
|
-
} else {
|
|
374
|
-
const stack: N[] = [subTreeRoot];
|
|
375
|
-
|
|
376
|
-
while (stack.length > 0) {
|
|
377
|
-
const cur = stack.pop()!;
|
|
378
|
-
res[0]++;
|
|
379
|
-
res[1] += cur.count;
|
|
380
|
-
cur.right && stack.push(cur.right);
|
|
381
|
-
cur.left && stack.push(cur.left);
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
return res;
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
/**
|
|
389
|
-
* The function `subTreeSumCount` calculates the sum of the `count` property of each node in a subtree, either
|
|
390
|
-
* recursively or iteratively.
|
|
391
|
-
* @param {N | BinaryTreeNodeKey | null} subTreeRoot - The `subTreeRoot` parameter represents the root node of a subtree
|
|
392
|
-
* in a binary tree. It can be either a `BinaryTreeNodeKey` (a unique identifier for a node in the binary tree) or
|
|
393
|
-
* `null` if the subtree is empty.
|
|
394
|
-
* @returns the sum of the count values of all nodes in the subtree rooted at `subTreeRoot`.
|
|
395
|
-
*/
|
|
396
|
-
subTreeSumCount(subTreeRoot: N | BinaryTreeNodeKey | null): number {
|
|
397
|
-
if (typeof subTreeRoot === 'number') subTreeRoot = this.get(subTreeRoot, 'key');
|
|
398
|
-
|
|
399
|
-
if (!subTreeRoot) return 0;
|
|
400
|
-
|
|
401
|
-
let sum = 0;
|
|
402
|
-
|
|
403
|
-
if (this.loopType === LoopType.RECURSIVE) {
|
|
404
|
-
const _traverse = (cur: N): void => {
|
|
405
|
-
sum += cur.count;
|
|
406
|
-
cur.left && _traverse(cur.left);
|
|
407
|
-
cur.right && _traverse(cur.right);
|
|
408
|
-
};
|
|
409
|
-
|
|
410
|
-
_traverse(subTreeRoot);
|
|
411
|
-
} else {
|
|
412
|
-
const stack: N[] = [subTreeRoot];
|
|
413
|
-
|
|
414
|
-
while (stack.length > 0) {
|
|
415
|
-
const cur = stack.pop()!;
|
|
416
|
-
sum += cur.count;
|
|
417
|
-
cur.right && stack.push(cur.right);
|
|
418
|
-
cur.left && stack.push(cur.left);
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
return sum;
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
/**
|
|
426
|
-
* The function `subTreeAddCount` recursively or iteratively traverses a binary tree and adds a given delta value to
|
|
427
|
-
* the `count` property of each node.
|
|
428
|
-
* @param {N | BinaryTreeNodeKey | null} subTreeRoot - The `subTreeRoot` parameter represents the root node of a subtree
|
|
429
|
-
* in a binary tree. It can be either a `BinaryTreeNodeKey` (a unique identifier for a node in the binary tree), a
|
|
430
|
-
* `BinaryTreeNode` object, or `null` if the subtree is empty.
|
|
431
|
-
* @param {number} delta - The delta parameter is a number that represents the amount by which the count of each node
|
|
432
|
-
* in the subtree should be increased or decreased.
|
|
433
|
-
* @returns a boolean value.
|
|
434
|
-
*/
|
|
435
|
-
subTreeAddCount(subTreeRoot: N | BinaryTreeNodeKey | null, delta: number): boolean {
|
|
436
|
-
if (typeof subTreeRoot === 'number') subTreeRoot = this.get(subTreeRoot, 'key');
|
|
437
|
-
|
|
438
|
-
if (!subTreeRoot) return false;
|
|
439
|
-
|
|
440
|
-
const _addByProperty = (cur: N) => {
|
|
441
|
-
cur.count += delta;
|
|
442
|
-
this._setCount(this.count + delta);
|
|
443
|
-
};
|
|
444
|
-
|
|
445
|
-
if (this.loopType === LoopType.RECURSIVE) {
|
|
446
|
-
const _traverse = (cur: N) => {
|
|
447
|
-
_addByProperty(cur);
|
|
448
|
-
cur.left && _traverse(cur.left);
|
|
449
|
-
cur.right && _traverse(cur.right);
|
|
450
|
-
};
|
|
451
|
-
|
|
452
|
-
_traverse(subTreeRoot);
|
|
453
|
-
} else {
|
|
454
|
-
const stack: N[] = [subTreeRoot];
|
|
455
|
-
|
|
456
|
-
while (stack.length > 0) {
|
|
457
|
-
const cur = stack.pop()!;
|
|
458
|
-
|
|
459
|
-
_addByProperty(cur);
|
|
460
|
-
cur.right && stack.push(cur.right);
|
|
461
|
-
cur.left && stack.push(cur.left);
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
return true;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
353
|
/**
|
|
468
354
|
* The function `getNodesByCount` returns an array of nodes that have a specific count property, either recursively or
|
|
469
355
|
* using a queue.
|
|
@@ -492,8 +378,8 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
|
|
|
492
378
|
|
|
493
379
|
_traverse(this.root);
|
|
494
380
|
} else {
|
|
495
|
-
const queue
|
|
496
|
-
while (queue.
|
|
381
|
+
const queue = new Queue<N>([this.root]);
|
|
382
|
+
while (queue.size > 0) {
|
|
497
383
|
const cur = queue.shift();
|
|
498
384
|
if (cur) {
|
|
499
385
|
if (cur.count === nodeProperty) {
|
|
@@ -545,120 +431,6 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
|
|
|
545
431
|
return nodes.map(node => node.count);
|
|
546
432
|
}
|
|
547
433
|
|
|
548
|
-
/**
|
|
549
|
-
* The function dfsCountIterative performs an iterative depth-first search and returns an array of node counts based on
|
|
550
|
-
* the specified traversal pattern.
|
|
551
|
-
* @param {'in' | 'pre' | 'post'} [pattern] - The pattern parameter is a string that specifies the traversal order for
|
|
552
|
-
* the Depth-First Search (dfs) algorithm. It can have three possible values: 'in', 'pre', or 'post'.
|
|
553
|
-
* @param loopType - The loopType parameter is a string that specifies the type of loop to use when traversing the
|
|
554
|
-
* @returns The dfsCountIterative function returns an array of numbers, which represents the count property of each node
|
|
555
|
-
* in the dfs traversal.
|
|
556
|
-
*/
|
|
557
|
-
dfsCount(pattern: DFSOrderPattern = 'in', loopType: LoopType = LoopType.ITERATIVE): number[] {
|
|
558
|
-
const nodes = super.dfs(pattern, 'node', loopType);
|
|
559
|
-
return nodes.map(node => node.count);
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
/**
|
|
563
|
-
* The `lesserSumCount` function calculates the sum of the counts of all nodes in a binary tree that have a lesser
|
|
564
|
-
* value than a given node.
|
|
565
|
-
* @param {N | BinaryTreeNodeKey | null} beginNode - The `beginNode` parameter can be one of the following:
|
|
566
|
-
* @returns the sum of the counts of nodes in the binary tree that have a lesser value than the given beginNode.
|
|
567
|
-
*/
|
|
568
|
-
lesserSumCount(beginNode: N | BinaryTreeNodeKey | null): number {
|
|
569
|
-
if (typeof beginNode === 'number') beginNode = this.get(beginNode, 'key');
|
|
570
|
-
if (!beginNode) return 0;
|
|
571
|
-
if (!this.root) return 0;
|
|
572
|
-
const key = beginNode.key;
|
|
573
|
-
|
|
574
|
-
let sum = 0;
|
|
575
|
-
|
|
576
|
-
if (this.loopType === LoopType.RECURSIVE) {
|
|
577
|
-
const _traverse = (cur: N): void => {
|
|
578
|
-
const compared = this._compare(cur.key, key);
|
|
579
|
-
if (compared === CP.eq) {
|
|
580
|
-
if (cur.right) sum += this.subTreeSumCount(cur.right);
|
|
581
|
-
return;
|
|
582
|
-
} else if (compared === CP.lt) {
|
|
583
|
-
if (cur.left) sum += this.subTreeSumCount(cur.left);
|
|
584
|
-
sum += cur.count;
|
|
585
|
-
if (cur.right) _traverse(cur.right);
|
|
586
|
-
else return;
|
|
587
|
-
} else {
|
|
588
|
-
if (cur.left) _traverse(cur.left);
|
|
589
|
-
else return;
|
|
590
|
-
}
|
|
591
|
-
};
|
|
592
|
-
|
|
593
|
-
_traverse(this.root);
|
|
594
|
-
} else {
|
|
595
|
-
const queue: N[] = [this.root];
|
|
596
|
-
while (queue.length > 0) {
|
|
597
|
-
const cur = queue.shift();
|
|
598
|
-
if (cur) {
|
|
599
|
-
const compared = this._compare(cur.key, key);
|
|
600
|
-
if (compared === CP.eq) {
|
|
601
|
-
if (cur.right) sum += this.subTreeSumCount(cur.right);
|
|
602
|
-
return sum;
|
|
603
|
-
} else if (compared === CP.lt) {
|
|
604
|
-
// todo maybe a bug
|
|
605
|
-
if (cur.left) sum += this.subTreeSumCount(cur.left);
|
|
606
|
-
sum += cur.count;
|
|
607
|
-
if (cur.right) queue.push(cur.right);
|
|
608
|
-
else return sum;
|
|
609
|
-
} else {
|
|
610
|
-
if (cur.left) queue.push(cur.left);
|
|
611
|
-
else return sum;
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
return sum;
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
/**
|
|
621
|
-
* The function `allGreaterNodesAddCount` updates the count property of all nodes in a binary tree that have an ID
|
|
622
|
-
* greater than a given ID by a specified delta value.
|
|
623
|
-
* @param {N | BinaryTreeNodeKey | null} node - The `node` parameter can be one of the following:
|
|
624
|
-
* @param {number} delta - The `delta` parameter is a number that represents the amount by which the `count` property
|
|
625
|
-
* of each node should be increased.
|
|
626
|
-
* @returns a boolean value.
|
|
627
|
-
*/
|
|
628
|
-
allGreaterNodesAddCount(node: N | BinaryTreeNodeKey | null, delta: number): boolean {
|
|
629
|
-
if (typeof node === 'number') node = this.get(node, 'key');
|
|
630
|
-
if (!node) return false;
|
|
631
|
-
const key = node.key;
|
|
632
|
-
if (!this.root) return false;
|
|
633
|
-
|
|
634
|
-
if (this.loopType === LoopType.RECURSIVE) {
|
|
635
|
-
const _traverse = (cur: N) => {
|
|
636
|
-
const compared = this._compare(cur.key, key);
|
|
637
|
-
if (compared === CP.gt) cur.count += delta;
|
|
638
|
-
|
|
639
|
-
if (!cur.left && !cur.right) return;
|
|
640
|
-
if (cur.left && this._compare(cur.left.key, key) === CP.gt) _traverse(cur.left);
|
|
641
|
-
if (cur.right && this._compare(cur.right.key, key) === CP.gt) _traverse(cur.right);
|
|
642
|
-
};
|
|
643
|
-
|
|
644
|
-
_traverse(this.root);
|
|
645
|
-
return true;
|
|
646
|
-
} else {
|
|
647
|
-
const queue: N[] = [this.root];
|
|
648
|
-
while (queue.length > 0) {
|
|
649
|
-
const cur = queue.shift();
|
|
650
|
-
if (cur) {
|
|
651
|
-
const compared = this._compare(cur.key, key);
|
|
652
|
-
if (compared === CP.gt) cur.count += delta;
|
|
653
|
-
|
|
654
|
-
if (cur.left && this._compare(cur.left.key, key) === CP.gt) queue.push(cur.left);
|
|
655
|
-
if (cur.right && this._compare(cur.right.key, key) === CP.gt) queue.push(cur.right);
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
return true;
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
|
|
662
434
|
/**
|
|
663
435
|
* The clear() function clears the data and sets the count to 0.
|
|
664
436
|
*/
|
|
@@ -9,6 +9,7 @@ import {arrayRemove, uuidV4} from '../../utils';
|
|
|
9
9
|
import {PriorityQueue} from '../priority-queue';
|
|
10
10
|
import type {DijkstraResult, VertexKey} from '../../types';
|
|
11
11
|
import {IGraph} from '../../interfaces';
|
|
12
|
+
import {Queue} from '../queue';
|
|
12
13
|
|
|
13
14
|
export abstract class AbstractVertex<V = any> {
|
|
14
15
|
/**
|
|
@@ -342,11 +343,11 @@ export abstract class AbstractGraph<
|
|
|
342
343
|
}
|
|
343
344
|
|
|
344
345
|
const visited: Map<V, boolean> = new Map();
|
|
345
|
-
const queue
|
|
346
|
+
const queue = new Queue<V>([vertex1]);
|
|
346
347
|
visited.set(vertex1, true);
|
|
347
348
|
let cost = 0;
|
|
348
|
-
while (queue.
|
|
349
|
-
for (let i = 0; i < queue.
|
|
349
|
+
while (queue.size > 0) {
|
|
350
|
+
for (let i = 0; i < queue.size; i++) {
|
|
350
351
|
const cur = queue.shift();
|
|
351
352
|
if (cur === vertex2) {
|
|
352
353
|
return cost;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {AVLTree} from '../../../../src';
|
|
1
|
+
import {AVLTree, CP} from '../../../../src';
|
|
2
2
|
|
|
3
3
|
describe('AVL Tree Test', () => {
|
|
4
4
|
it('should perform various operations on a AVL Tree', () => {
|
|
@@ -22,10 +22,12 @@ describe('AVL Tree Test', () => {
|
|
|
22
22
|
const getMinNodeBySpecificNode = node15 && tree.getLeftMost(node15);
|
|
23
23
|
expect(getMinNodeBySpecificNode?.key).toBe(12);
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
let subTreeSum = 0;
|
|
26
|
+
node15 && tree.subTreeForeach(node15, node => (subTreeSum += node.key));
|
|
26
27
|
expect(subTreeSum).toBe(70);
|
|
27
28
|
|
|
28
|
-
|
|
29
|
+
let lesserSum = 0;
|
|
30
|
+
tree.lesserOrGreaterForeach(10, CP.lt, node => (lesserSum += node.key));
|
|
29
31
|
expect(lesserSum).toBe(45);
|
|
30
32
|
|
|
31
33
|
// node15 has type problem. After the uniform design, the generics of containers (DirectedGraph, BST) are based on the type of value. However, this design has a drawback: when I attempt to inherit from the Vertex or BSTNode classes, the types of the results obtained by all methods are those of the parent class.
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {BST, BSTNode} from '../../../../src';
|
|
1
|
+
import {BST, BSTNode, CP} from '../../../../src';
|
|
2
|
+
|
|
3
|
+
const isDebug = false;
|
|
2
4
|
|
|
3
5
|
describe('BST operations test', () => {
|
|
4
6
|
it('should perform various operations on a Binary Search Tree with numeric values', () => {
|
|
@@ -7,7 +9,7 @@ describe('BST operations test', () => {
|
|
|
7
9
|
bst.add(11, 11);
|
|
8
10
|
bst.add(3, 3);
|
|
9
11
|
const idsAndValues = [15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5];
|
|
10
|
-
bst.addMany(idsAndValues, idsAndValues);
|
|
12
|
+
bst.addMany(idsAndValues, idsAndValues, false);
|
|
11
13
|
expect(bst.root).toBeInstanceOf(BSTNode);
|
|
12
14
|
|
|
13
15
|
if (bst.root) expect(bst.root.key).toBe(11);
|
|
@@ -33,10 +35,12 @@ describe('BST operations test', () => {
|
|
|
33
35
|
const minNodeBySpecificNode = node15 && bst.getLeftMost(node15);
|
|
34
36
|
expect(minNodeBySpecificNode?.key).toBe(12);
|
|
35
37
|
|
|
36
|
-
|
|
38
|
+
let subTreeSum = 0;
|
|
39
|
+
node15 && bst.subTreeForeach(15, node => (subTreeSum += node.key));
|
|
37
40
|
expect(subTreeSum).toBe(70);
|
|
38
41
|
|
|
39
|
-
|
|
42
|
+
let lesserSum = 0;
|
|
43
|
+
bst.lesserOrGreaterForeach(10, CP.lt, node => (lesserSum += node.key));
|
|
40
44
|
expect(lesserSum).toBe(45);
|
|
41
45
|
|
|
42
46
|
expect(node15).toBeInstanceOf(BSTNode);
|
|
@@ -204,7 +208,8 @@ describe('BST operations test', () => {
|
|
|
204
208
|
|
|
205
209
|
objBST.addMany(
|
|
206
210
|
values.map(item => item.key),
|
|
207
|
-
values
|
|
211
|
+
values,
|
|
212
|
+
false
|
|
208
213
|
);
|
|
209
214
|
|
|
210
215
|
expect(objBST.root).toBeInstanceOf(BSTNode);
|
|
@@ -231,10 +236,12 @@ describe('BST operations test', () => {
|
|
|
231
236
|
const minNodeBySpecificNode = node15 && objBST.getLeftMost(node15);
|
|
232
237
|
expect(minNodeBySpecificNode?.key).toBe(12);
|
|
233
238
|
|
|
234
|
-
|
|
239
|
+
let subTreeSum = 0;
|
|
240
|
+
node15 && objBST.subTreeForeach(node15, node => (subTreeSum += node.key));
|
|
235
241
|
expect(subTreeSum).toBe(70);
|
|
236
242
|
|
|
237
|
-
|
|
243
|
+
let lesserSum = 0;
|
|
244
|
+
objBST.lesserOrGreaterForeach(10, CP.lt, node => (lesserSum += node.key));
|
|
238
245
|
expect(lesserSum).toBe(45);
|
|
239
246
|
|
|
240
247
|
expect(node15).toBeInstanceOf(BSTNode);
|
|
@@ -378,3 +385,33 @@ describe('BST operations test', () => {
|
|
|
378
385
|
expect(bfsNodes[2].key).toBe(16);
|
|
379
386
|
});
|
|
380
387
|
});
|
|
388
|
+
|
|
389
|
+
describe('BST Performance test', function () {
|
|
390
|
+
const bst = new BST<BSTNode<number>>();
|
|
391
|
+
const inputSize = 10000; // Adjust input sizes as needed
|
|
392
|
+
|
|
393
|
+
beforeEach(() => {
|
|
394
|
+
bst.clear();
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
it(`Observe the time consumption of BST.dfs be good`, function () {
|
|
398
|
+
const startDFS = performance.now();
|
|
399
|
+
const dfs = bst.dfs();
|
|
400
|
+
isDebug && console.log('---bfs', performance.now() - startDFS, dfs.length);
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
it('Should the time consumption of lesserOrGreaterForeach fitting O(n log n)', function () {
|
|
404
|
+
const nodes: number[] = [];
|
|
405
|
+
for (let i = 0; i < inputSize; i++) {
|
|
406
|
+
nodes.push(i);
|
|
407
|
+
}
|
|
408
|
+
const start = performance.now();
|
|
409
|
+
bst.addMany(nodes);
|
|
410
|
+
isDebug && console.log('---add', performance.now() - start);
|
|
411
|
+
const startL = performance.now();
|
|
412
|
+
bst.lesserOrGreaterForeach(inputSize / 2, CP.lt, node => {
|
|
413
|
+
return node.key - 1;
|
|
414
|
+
});
|
|
415
|
+
isDebug && console.log('---lesserOrGreaterForeach', performance.now() - startL);
|
|
416
|
+
});
|
|
417
|
+
});
|
|
@@ -5,7 +5,7 @@ describe('Overall BinaryTree Test', () => {
|
|
|
5
5
|
const bst = new BST();
|
|
6
6
|
bst.add(11);
|
|
7
7
|
bst.add(3);
|
|
8
|
-
bst.addMany([15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]);
|
|
8
|
+
bst.addMany([15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5], undefined, false);
|
|
9
9
|
bst.size === 16; // true
|
|
10
10
|
expect(bst.size).toBe(16); // true
|
|
11
11
|
bst.has(6); // true
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {TreeMultiset, TreeMultisetNode} from '../../../../src';
|
|
1
|
+
import {CP, TreeMultiset, TreeMultisetNode} from '../../../../src';
|
|
2
2
|
|
|
3
|
+
const isDebug = false;
|
|
3
4
|
describe('TreeMultiset operations test', () => {
|
|
4
5
|
it('should perform various operations on a Binary Search Tree with numeric values', () => {
|
|
5
6
|
const treeMultiset = new TreeMultiset();
|
|
@@ -39,20 +40,26 @@ describe('TreeMultiset operations test', () => {
|
|
|
39
40
|
const minNodeBySpecificNode = node15 && treeMultiset.getLeftMost(node15);
|
|
40
41
|
expect(minNodeBySpecificNode?.key).toBe(12);
|
|
41
42
|
|
|
42
|
-
|
|
43
|
+
let subTreeSum = 0;
|
|
44
|
+
node15 && treeMultiset.subTreeForeach(15, (node: TreeMultisetNode<number>) => (subTreeSum += node.key));
|
|
43
45
|
expect(subTreeSum).toBe(70);
|
|
44
|
-
|
|
46
|
+
let lesserSum = 0;
|
|
47
|
+
treeMultiset.lesserOrGreaterForeach(10, CP.lt, (node: TreeMultisetNode<number>) => (lesserSum += node.key));
|
|
45
48
|
expect(lesserSum).toBe(45);
|
|
46
49
|
|
|
47
50
|
expect(node15 instanceof TreeMultisetNode);
|
|
48
51
|
if (node15 instanceof TreeMultisetNode) {
|
|
49
|
-
const subTreeAdd = treeMultiset.
|
|
52
|
+
const subTreeAdd = treeMultiset.subTreeForeach(15, (node: TreeMultisetNode<number>) => (node.count += 1));
|
|
50
53
|
expect(subTreeAdd);
|
|
51
54
|
}
|
|
52
55
|
const node11 = treeMultiset.get(11);
|
|
53
56
|
expect(node11 instanceof TreeMultisetNode);
|
|
54
57
|
if (node11 instanceof TreeMultisetNode) {
|
|
55
|
-
const allGreaterNodesAdded = treeMultiset.
|
|
58
|
+
const allGreaterNodesAdded = treeMultiset.lesserOrGreaterForeach(
|
|
59
|
+
11,
|
|
60
|
+
CP.gt,
|
|
61
|
+
(node: TreeMultisetNode<number>) => (node.count += 2)
|
|
62
|
+
);
|
|
56
63
|
expect(allGreaterNodesAdded);
|
|
57
64
|
}
|
|
58
65
|
|
|
@@ -419,13 +426,19 @@ describe('TreeMultiset operations test', () => {
|
|
|
419
426
|
|
|
420
427
|
describe('TreeMultiset Performance test', function () {
|
|
421
428
|
// const treeMS = new TreeMultiset<TreeMultisetNode<number>>();
|
|
422
|
-
// const
|
|
429
|
+
// const inputSize = [100]; // Adjust input sizes as needed
|
|
423
430
|
//
|
|
424
431
|
// // Define a function to calculate the expected O(n log n) time
|
|
425
432
|
// function expectedTime(n: number): number {
|
|
426
433
|
// return n * Math.log(n);
|
|
427
434
|
// }
|
|
428
435
|
|
|
436
|
+
const treeMS = new TreeMultiset<TreeMultisetNode<number>>();
|
|
437
|
+
const inputSize = 100000; // Adjust input sizes as needed
|
|
438
|
+
|
|
439
|
+
beforeEach(() => {
|
|
440
|
+
treeMS.clear();
|
|
441
|
+
});
|
|
429
442
|
it(`Observe the time consumption of TreeMultiset.add fitting O(n log n)`, function () {
|
|
430
443
|
// // Create a benchmark suite
|
|
431
444
|
// const suite = new Benchmark.Suite();
|
|
@@ -437,9 +450,9 @@ describe('TreeMultiset Performance test', function () {
|
|
|
437
450
|
// }
|
|
438
451
|
// return arr;
|
|
439
452
|
// }
|
|
440
|
-
// const inputArray = generateRandomArray(
|
|
453
|
+
// const inputArray = generateRandomArray(inputSize[0]);
|
|
441
454
|
//
|
|
442
|
-
// suite.add(`TreeMultiset addMany (n=${
|
|
455
|
+
// suite.add(`TreeMultiset addMany (n=${inputSize[0]})`, () => {
|
|
443
456
|
// treeMS.addMany([...inputArray]);
|
|
444
457
|
// });
|
|
445
458
|
//
|
|
@@ -453,9 +466,26 @@ describe('TreeMultiset Performance test', function () {
|
|
|
453
466
|
// console.log(`Input size (n): ${n}, Observed time: ${observedTime.toFixed(2)}ms, Expected time: ${expected.toFixed(2)}ms`);
|
|
454
467
|
// })
|
|
455
468
|
// .on('complete', () => {
|
|
456
|
-
// console.log(`Benchmark (n=${
|
|
469
|
+
// console.log(`Benchmark (n=${inputSize[0]}) completed.`);
|
|
457
470
|
// done(); // Call done to indicate the test is complete
|
|
458
471
|
// })
|
|
459
472
|
// .run({async: true});
|
|
460
473
|
});
|
|
474
|
+
|
|
475
|
+
it(`Observe the time consumption of TreeMultiset.dfs be good`, function () {
|
|
476
|
+
const startDFS = performance.now();
|
|
477
|
+
const dfs = treeMS.dfs();
|
|
478
|
+
isDebug && console.log('---bfs', performance.now() - startDFS, dfs.length);
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
it('Should the time consumption of lesserOrGreaterForeach fitting O(n log n)', function () {
|
|
482
|
+
const start = performance.now();
|
|
483
|
+
for (let i = 0; i < inputSize; i++) {
|
|
484
|
+
treeMS.add(i);
|
|
485
|
+
}
|
|
486
|
+
isDebug && console.log('---add', performance.now() - start);
|
|
487
|
+
const startL = performance.now();
|
|
488
|
+
treeMS.lesserOrGreaterForeach(inputSize / 2, CP.lt, (node: TreeMultisetNode<number>) => (node.count += 1));
|
|
489
|
+
isDebug && console.log('---lesserOrGreaterForeach', performance.now() - startL);
|
|
490
|
+
});
|
|
461
491
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {Deque, ArrayDeque, ObjectDeque} from '../../../../src';
|
|
2
|
+
import {bigO} from '../../../utils';
|
|
2
3
|
|
|
3
4
|
describe('Deque Tests', () => {
|
|
4
5
|
// Test cases for the Deque class (DoublyLinkedList-based)
|
|
@@ -128,3 +129,19 @@ describe('Deque Tests', () => {
|
|
|
128
129
|
// Add more test cases as needed
|
|
129
130
|
});
|
|
130
131
|
});
|
|
132
|
+
|
|
133
|
+
describe('Deque Performance Test', () => {
|
|
134
|
+
const dataSize = 10000;
|
|
135
|
+
it('should numeric queue be efficient', function () {
|
|
136
|
+
const startTime = performance.now();
|
|
137
|
+
const queue = new Deque<number>();
|
|
138
|
+
for (let i = 0; i < dataSize; i++) {
|
|
139
|
+
queue.unshift(i);
|
|
140
|
+
}
|
|
141
|
+
for (let i = 0; i < dataSize; i++) {
|
|
142
|
+
queue.pop();
|
|
143
|
+
}
|
|
144
|
+
console.log(`Queue Deque Test: ${performance.now() - startTime} ms`);
|
|
145
|
+
expect(performance.now() - startTime).toBeLessThan(bigO.LINEAR * 100);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
@@ -197,3 +197,45 @@ describe('LinkedListQueue', () => {
|
|
|
197
197
|
|
|
198
198
|
// Add more test cases for other methods of LinkedListQueue.
|
|
199
199
|
});
|
|
200
|
+
|
|
201
|
+
describe('Queue Performance Test', () => {
|
|
202
|
+
const dataSize = 10000;
|
|
203
|
+
it('should numeric queue be efficient', function () {
|
|
204
|
+
const startTime = performance.now();
|
|
205
|
+
const queue = new Queue<number>();
|
|
206
|
+
for (let i = 0; i < dataSize; i++) {
|
|
207
|
+
queue.enqueue(i);
|
|
208
|
+
}
|
|
209
|
+
for (let i = 0; i < dataSize; i++) {
|
|
210
|
+
queue.dequeue();
|
|
211
|
+
}
|
|
212
|
+
console.log(`Queue Performance Test: ${performance.now() - startTime} ms`);
|
|
213
|
+
expect(performance.now() - startTime).toBeLessThan(bigO.LINEAR * 100);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it('should numeric Array be more efficient than Queue when the data size is 10000', function () {
|
|
217
|
+
const startTime2 = performance.now();
|
|
218
|
+
const queue2: number[] = [];
|
|
219
|
+
for (let i = 0; i < dataSize; i++) {
|
|
220
|
+
queue2.push(i);
|
|
221
|
+
}
|
|
222
|
+
for (let i = 0; i < dataSize; i++) {
|
|
223
|
+
queue2.shift();
|
|
224
|
+
}
|
|
225
|
+
console.log(`Array Performance Test: ${performance.now() - startTime2} ms`);
|
|
226
|
+
expect(performance.now() - startTime2).toBeLessThan(bigO.CUBED * 100);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it('should numeric LinkedListQueue be efficient', function () {
|
|
230
|
+
const startTime = performance.now();
|
|
231
|
+
const queue = new LinkedListQueue<number>();
|
|
232
|
+
for (let i = 0; i < dataSize; i++) {
|
|
233
|
+
queue.enqueue(i);
|
|
234
|
+
}
|
|
235
|
+
for (let i = 0; i < dataSize; i++) {
|
|
236
|
+
queue.dequeue();
|
|
237
|
+
}
|
|
238
|
+
console.log(`LinkedListQueue Performance Test: ${performance.now() - startTime} ms`);
|
|
239
|
+
expect(performance.now() - startTime).toBeLessThan(bigO.LINEAR * 100);
|
|
240
|
+
});
|
|
241
|
+
});
|
package/test/utils/big-o.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {AnyFunction} from '../types';
|
|
2
2
|
|
|
3
|
+
const isDebug = false;
|
|
3
4
|
const orderReducedBy = 2; // reduction of bigO's order compared to the baseline bigO
|
|
4
5
|
|
|
5
6
|
export const magnitude = {
|
|
@@ -148,12 +149,12 @@ export function logBigOMetricsWrap<F extends AnyFunction>(fn: F, args: Parameter
|
|
|
148
149
|
methodLog.push([runTime, maxDataSize]);
|
|
149
150
|
|
|
150
151
|
if (methodLog.length >= 20) {
|
|
151
|
-
console.log('triggered', methodName, methodLog);
|
|
152
|
+
isDebug && console.log('triggered', methodName, methodLog);
|
|
152
153
|
const bigO = estimateBigO(
|
|
153
154
|
methodLog.map(([runTime]) => runTime),
|
|
154
155
|
methodLog.map(([runTime]) => runTime)
|
|
155
156
|
);
|
|
156
|
-
console.log(`Estimated Big O: ${bigO}`);
|
|
157
|
+
isDebug && console.log(`Estimated Big O: ${bigO}`);
|
|
157
158
|
methodLogs.delete(methodName);
|
|
158
159
|
}
|
|
159
160
|
}
|
|
@@ -182,12 +183,12 @@ export function logBigOMetrics(target: any, propertyKey: string, descriptor: Pro
|
|
|
182
183
|
methodLog.push([runTime, maxDataSize]);
|
|
183
184
|
|
|
184
185
|
if (methodLog.length >= 20) {
|
|
185
|
-
console.log('triggered', methodName, methodLog);
|
|
186
|
+
isDebug && console.log('triggered', methodName, methodLog);
|
|
186
187
|
const bigO = estimateBigO(
|
|
187
188
|
methodLog.map(([runTime]) => runTime),
|
|
188
189
|
methodLog.map(([runTime]) => runTime)
|
|
189
190
|
);
|
|
190
|
-
console.log(`Estimated Big O: ${bigO}`);
|
|
191
|
+
isDebug && console.log(`Estimated Big O: ${bigO}`);
|
|
191
192
|
methodLogs.delete(methodName);
|
|
192
193
|
}
|
|
193
194
|
}
|