From d57d6072c24a874a2282fac1d13e7034447073aa Mon Sep 17 00:00:00 2001 From: Revone Date: Sat, 23 Dec 2023 11:53:18 +0800 Subject: [PATCH] fix: Fix bug in BST.isBST to make it compatible with inverse BST. refactor: Use KeyOrNodeOrEntry as the parameter type consistently in the binary tree data structure. test: Remove unnecessary performance reports and refactor loop code to use single lines wherever possible. --- README.md | 36 +- src/data-structures/binary-tree/avl-tree.ts | 111 ++--- .../binary-tree/binary-tree.ts | 399 ++++++++++-------- src/data-structures/binary-tree/bst.ts | 221 +++++----- src/data-structures/binary-tree/rb-tree.ts | 142 ++++--- .../binary-tree/tree-multimap.ts | 118 +++--- src/interfaces/binary-tree.ts | 6 +- src/types/common.ts | 2 +- .../binary-tree/avl-tree.test.ts | 16 +- .../binary-tree/binary-tree-overall.test.ts | 37 ++ .../binary-tree/binary-tree.test.ts | 22 +- .../data-structures/binary-tree/bst.test.ts | 18 +- .../binary-tree/overall.test.ts | 0 .../binary-tree/rb-tree.test.ts | 20 +- .../comparison/comparison.test.ts | 49 +-- .../graph/directed-graph.test.ts | 17 +- .../data-structures/hash/hash-map.test.ts | 45 +- .../data-structures/heap/heap.test.ts | 23 +- .../linked-list/doubly-linked-list.test.ts | 1 - .../linked-list/singly-linked-list.test.ts | 2 - .../data-structures/matrix/matrix2d.test.ts | 0 .../data-structures/matrix/vector2d.test.ts | 0 .../priority-queue/max-priority-queue.test.ts | 6 +- .../priority-queue/priority-queue.test.ts | 18 +- .../data-structures/queue/queue.test.ts | 33 +- .../data-structures/stack/stack.test.ts | 24 +- .../data-structures/trie/trie.test.ts | 8 +- .../binary-tree/binary-tree.test.ts | 3 +- 28 files changed, 672 insertions(+), 705 deletions(-) create mode 100644 test/performance/data-structures/binary-tree/binary-tree-overall.test.ts delete mode 100644 test/performance/data-structures/binary-tree/overall.test.ts delete mode 100644 test/performance/data-structures/matrix/matrix2d.test.ts delete mode 100644 test/performance/data-structures/matrix/vector2d.test.ts diff --git a/README.md b/README.md index b3d976f..f79e615 100644 --- a/README.md +++ b/README.md @@ -984,52 +984,40 @@ avl2.print(); [//]: # (No deletion!!! Start of Replace Section)
avl-tree
-
test nametime taken (ms)executions per secsample deviation
10,000 add randomly48.4220.650.00
10,000 add & delete randomly107.729.280.02
10,000 addMany55.4018.056.22e-4
10,000 get53.8918.560.02
-
-
binary-tree
-
test nametime taken (ms)executions per secsample deviation
1,000 add randomly17.7556.352.23e-4
1,000 add & delete randomly25.5839.100.01
1,000 addMany19.6550.890.00
1,000 get21.0347.550.01
1,000 has19.8150.480.01
1,000 dfs183.375.450.03
1,000 bfs65.6115.240.02
1,000 morris231.004.330.06
-
-
bst
-
test nametime taken (ms)executions per secsample deviation
10,000 add randomly49.9620.027.65e-4
10,000 add & delete randomly116.778.560.02
10,000 addMany49.0620.380.01
10,000 get49.0620.387.13e-4
+
test nametime taken (ms)executions per secsample deviation
10,000 add randomly118.628.430.00
10,000 add & delete randomly179.745.560.00
10,000 addMany154.346.480.04
10,000 get50.5319.790.00
rb-tree
-
test nametime taken (ms)executions per secsample deviation
100,000 add83.4211.990.01
100,000 add & delete randomly243.054.110.07
100,000 getNode218.874.570.05
100,000 add & iterator124.228.050.01
-
-
comparison
-
test nametime taken (ms)executions per secsample deviation
SRC PQ 10,000 add0.156710.401.90e-5
CJS PQ 10,000 add0.166407.424.25e-5
MJS PQ 10,000 add0.621602.371.51e-4
SRC PQ 10,000 add & poll3.67272.420.00
CJS PQ 10,000 add & poll3.95252.900.00
MJS PQ 10,000 add & poll3.33300.288.65e-5
+
test nametime taken (ms)executions per secsample deviation
100,000 add90.6311.030.01
100,000 add & delete randomly225.644.430.01
100,000 getNode174.395.730.00
100,000 add & iterator120.948.270.02
directed-graph
-
test nametime taken (ms)executions per secsample deviation
1,000 addVertex0.118958.103.30e-5
1,000 addEdge6.37156.981.96e-4
1,000 getVertex0.052.04e+48.22e-6
1,000 getEdge24.4940.830.00
tarjan235.544.250.04
tarjan all6766.740.150.32
topologicalSort197.525.060.04
+
test nametime taken (ms)executions per secsample deviation
1,000 addVertex0.109850.831.41e-6
1,000 addEdge6.21160.972.65e-4
1,000 getVertex0.051.91e+42.18e-5
1,000 getEdge26.3837.900.00
tarjan233.904.280.02
tarjan all7008.220.140.34
topologicalSort206.124.850.02
hash-map
-
test nametime taken (ms)executions per secsample deviation
1,000,000 set117.828.490.05
Native Map 1,000,000 set220.924.530.03
Native Set 1,000,000 add187.445.340.02
1,000,000 set & get125.447.970.04
Native Map 1,000,000 set & get300.103.330.06
Native Set 1,000,000 add & has200.884.980.02
1,000,000 ObjKey set & get361.002.770.06
Native Map 1,000,000 ObjKey set & get335.342.980.09
Native Set 1,000,000 ObjKey add & has261.283.830.07
+
test nametime taken (ms)executions per secsample deviation
1,000,000 set129.167.740.05
Native Map 1,000,000 set230.984.330.05
Native Set 1,000,000 add201.944.950.05
1,000,000 set & get132.137.570.03
Native Map 1,000,000 set & get317.163.150.06
Native Set 1,000,000 add & has229.564.360.06
1,000,000 ObjKey set & get323.023.100.04
Native Map 1,000,000 ObjKey set & get301.073.320.04
Native Set 1,000,000 ObjKey add & has282.013.550.04
heap
-
test nametime taken (ms)executions per secsample deviation
100,000 add & poll80.4312.430.00
100,000 add & dfs36.9527.070.00
10,000 fib add & pop386.632.590.05
+
test nametime taken (ms)executions per secsample deviation
100,000 add & poll27.3236.619.27e-4
100,000 add & dfs33.8329.563.94e-4
10,000 fib add & pop353.372.830.00
doubly-linked-list
-
test nametime taken (ms)executions per secsample deviation
1,000,000 push235.154.250.07
1,000,000 unshift245.364.080.08
1,000,000 unshift & shift175.535.700.03
1,000,000 addBefore319.213.130.06
+
test nametime taken (ms)executions per secsample deviation
1,000,000 push220.804.530.02
1,000,000 unshift235.944.240.06
1,000,000 unshift & shift180.115.550.04
1,000,000 addBefore335.722.980.11
singly-linked-list
-
test nametime taken (ms)executions per secsample deviation
1,000,000 push & shift202.024.950.04
10,000 push & pop228.774.370.04
10,000 addBefore274.253.650.05
-
-
max-priority-queue
-
test nametime taken (ms)executions per secsample deviation
10,000 refill & poll9.39106.510.00
+
test nametime taken (ms)executions per secsample deviation
1,000,000 push & shift217.294.600.06
10,000 push & pop223.414.480.02
10,000 addBefore253.793.940.01
priority-queue
-
test nametime taken (ms)executions per secsample deviation
100,000 add & poll114.368.740.02
+
test nametime taken (ms)executions per secsample deviation
100,000 add & poll81.5512.260.01
deque
-
test nametime taken (ms)executions per secsample deviation
1,000,000 push14.8167.510.00
1,000,000 push & pop25.3439.470.01
100,000 push & shift2.49400.867.97e-4
Native Array 100,000 push & shift2390.920.420.17
100,000 unshift & shift2.48403.146.46e-4
Native Array 100,000 unshift & shift4462.410.220.34
+
test nametime taken (ms)executions per secsample deviation
1,000,000 push14.1470.714.71e-4
1,000,000 push & pop29.7533.610.01
100,000 push & shift3.06326.930.00
Native Array 100,000 push & shift2211.020.450.05
100,000 unshift & shift2.23447.633.63e-4
Native Array 100,000 unshift & shift4586.530.220.86
queue
-
test nametime taken (ms)executions per secsample deviation
1,000,000 push51.9919.240.03
100,000 push & shift5.23191.347.00e-4
Native Array 100,000 push & shift2400.960.420.28
Native Array 100,000 push & pop4.36229.521.14e-4
+
test nametime taken (ms)executions per secsample deviation
1,000,000 push48.4420.650.01
100,000 push & shift5.28189.276.59e-4
Native Array 100,000 push & shift2335.960.430.14
Native Array 100,000 push & pop4.48223.085.56e-4
stack
-
test nametime taken (ms)executions per secsample deviation
1,000,000 push43.5522.960.01
1,000,000 push & pop55.2918.090.01
+
test nametime taken (ms)executions per secsample deviation
1,000,000 push45.6121.930.01
1,000,000 push & pop50.9619.620.01
trie
-
test nametime taken (ms)executions per secsample deviation
100,000 push48.6620.550.00
100,000 getWords95.0910.520.01
+
test nametime taken (ms)executions per secsample deviation
100,000 push58.4017.120.02
100,000 getWords99.7010.030.01
[//]: # (No deletion!!! End of Replace Section) diff --git a/src/data-structures/binary-tree/avl-tree.ts b/src/data-structures/binary-tree/avl-tree.ts index fee02e6..487c5e2 100644 --- a/src/data-structures/binary-tree/avl-tree.ts +++ b/src/data-structures/binary-tree/avl-tree.ts @@ -13,8 +13,7 @@ import type { BinaryTreeDeleteResult, BSTNKeyOrNode, BTNCallback, - BTNExemplar, - BTNKeyOrNode + KeyOrNodeOrEntry } from '../../types'; import { IBinaryTree } from '../../interfaces'; @@ -49,17 +48,17 @@ export class AVLTree< extends BST implements IBinaryTree { /** - * The constructor function initializes an AVLTree object with optional elements and options. - * @param [elements] - The `elements` parameter is an optional iterable of `BTNExemplar` - * objects. It represents a collection of elements that will be added to the AVL tree during + * The constructor function initializes an AVLTree object with optional nodes and options. + * @param [nodes] - The `nodes` parameter is an optional iterable of `KeyOrNodeOrEntry` + * objects. It represents a collection of nodes that will be added to the AVL tree during * initialization. * @param [options] - The `options` parameter is an optional object that allows you to customize the * behavior of the AVL tree. It is of type `Partial`, which means that you can * provide only a subset of the properties defined in the `AVLTreeOptions` interface. */ - constructor(elements?: Iterable>, options?: Partial>) { + constructor(nodes?: Iterable>, options?: Partial>) { super([], options); - if (elements) super.addMany(elements); + if (nodes) super.addMany(nodes); } /** @@ -91,12 +90,12 @@ export class AVLTree< } /** - * The function checks if an exemplar is an instance of AVLTreeNode. - * @param exemplar - The `exemplar` parameter is of type `BTNExemplar`. - * @returns a boolean value indicating whether the exemplar is an instance of the AVLTreeNode class. + * The function checks if an keyOrNodeOrEntry is an instance of AVLTreeNode. + * @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter is of type `KeyOrNodeOrEntry`. + * @returns a boolean value indicating whether the keyOrNodeOrEntry is an instance of the AVLTreeNode class. */ - override isNode(exemplar: BTNExemplar): exemplar is N { - return exemplar instanceof AVLTreeNode; + override isNode(keyOrNodeOrEntry: KeyOrNodeOrEntry): keyOrNodeOrEntry is N { + return keyOrNodeOrEntry instanceof AVLTreeNode; } /** @@ -105,18 +104,19 @@ export class AVLTree< * data type. * @returns a boolean value indicating whether the potentialKey is of type number or not. */ - override isNotNodeInstance(potentialKey: BTNKeyOrNode): potentialKey is K { + override isNotNodeInstance(potentialKey: KeyOrNodeOrEntry): potentialKey is K { return !(potentialKey instanceof AVLTreeNode); } /** - * Time Complexity: O(log n) - logarithmic time, where "n" is the number of nodes in the tree. The add method of the superclass (BST) has logarithmic time complexity. - * Space Complexity: O(1) - constant space, as it doesn't use additional data structures that scale with input size. + * Time Complexity: O(log n) + * Space Complexity: O(1) + * logarithmic time, where "n" is the number of nodes in the tree. The add method of the superclass (BST) has logarithmic time complexity. constant space, as it doesn't use additional data structures that scale with input size. */ /** - * Time Complexity: O(log n) - logarithmic time, where "n" is the number of nodes in the tree. The add method of the superclass (BST) has logarithmic time complexity. - * Space Complexity: O(1) - constant space, as it doesn't use additional data structures that scale with input size. + * Time Complexity: O(log n) + * Space Complexity: O(1) * * The function overrides the add method of a binary tree node and balances the tree after inserting * a new node. @@ -126,21 +126,21 @@ export class AVLTree< * being added to the binary tree. * @returns The method is returning either the inserted node or undefined. */ - override add(keyOrNodeOrEntry: BTNExemplar, value?: V): N | undefined { - if (keyOrNodeOrEntry === null) return undefined; + override add(keyOrNodeOrEntry: KeyOrNodeOrEntry, value?: V): boolean { + if (keyOrNodeOrEntry === null) return false; const inserted = super.add(keyOrNodeOrEntry, value); - if (inserted) this._balancePath(inserted); + if (inserted) this._balancePath(keyOrNodeOrEntry); return inserted; } /** - * Time Complexity: O(log n) - logarithmic time, where "n" is the number of nodes in the tree. The add method of the superclass (BST) has logarithmic time complexity. - * Space Complexity: O(1) - constant space, as it doesn't use additional data structures that scale with input size. + * Time Complexity: O(log n) + * Space Complexity: O(1) */ /** - * Time Complexity: O(log n) - logarithmic time, where "n" is the number of nodes in the tree. The delete method of the superclass (BST) has logarithmic time complexity. - * Space Complexity: O(1) - constant space, as it doesn't use additional data structures that scale with input size. + * Time Complexity: O(log n) + * Space Complexity: O(1) * * The function overrides the delete method of a binary tree, performs the deletion, and then * balances the tree if necessary. @@ -203,13 +203,14 @@ export class AVLTree< } /** - * Time Complexity: O(1) - constant time, as it performs a fixed number of operations. - * Space Complexity: O(1) - constant space, as it only uses a constant amount of memory. + * Time Complexity: O(1) + * Space Complexity: O(1) + * constant time, as it performs a fixed number of operations. constant space, as it only uses a constant amount of memory. */ /** - * Time Complexity: O(1) - constant time, as it performs a fixed number of operations. - * Space Complexity: O(1) - constant space, as it only uses a constant amount of memory. + * Time Complexity: O(1) + * Space Complexity: O(1) * * The function calculates the balance factor of a node in a binary tree. * @param {N} node - The parameter "node" represents a node in a binary tree data structure. @@ -227,13 +228,14 @@ export class AVLTree< } /** - * Time Complexity: O(1) - constant time, as it performs a fixed number of operations. - * Space Complexity: O(1) - constant space, as it only uses a constant amount of memory. + * Time Complexity: O(1) + * Space Complexity: O(1) + * constant time, as it performs a fixed number of operations. constant space, as it only uses a constant amount of memory. */ /** - * Time Complexity: O(1) - constant time, as it performs a fixed number of operations. - * Space Complexity: O(1) - constant space, as it only uses a constant amount of memory. + * Time Complexity: O(1) + * Space Complexity: O(1) * * The function updates the height of a node in a binary tree based on the heights of its left and * right children. @@ -249,20 +251,22 @@ export class AVLTree< } /** - * Time Complexity: O(log n) - logarithmic time, where "n" is the number of nodes in the tree. The method traverses the path from the inserted node to the root. - * Space Complexity: O(1) - constant space, as it doesn't use additional data structures that scale with input size. + * Time Complexity: O(log n) + * Space Complexity: O(1) + * logarithmic time, where "n" is the number of nodes in the tree. The method traverses the path from the inserted node to the root. constant space, as it doesn't use additional data structures that scale with input size. */ /** - * Time Complexity: O(log n) - logarithmic time, where "n" is the number of nodes in the tree. The method traverses the path from the inserted node to the root. - * Space Complexity: O(1) - constant space, as it doesn't use additional data structures that scale with input size. + * Time Complexity: O(log n) + * Space Complexity: O(1) * * The `_balancePath` function is used to update the heights of nodes and perform rotation operations * to restore balance in an AVL tree after inserting a node. * @param {N} node - The `node` parameter in the `_balancePath` function represents the node in the * AVL tree that needs to be balanced. */ - protected _balancePath(node: N): void { + protected _balancePath(node: KeyOrNodeOrEntry): void { + node = this.ensureNode(node); const path = this.getPathToRoot(node, false); // first O(log n) + O(log n) for (let i = 0; i < path.length; i++) { // second O(log n) @@ -302,13 +306,14 @@ export class AVLTree< } /** - * Time Complexity: O(1) - constant time, as these methods perform a fixed number of operations. - * Space Complexity: O(1) - constant space, as they only use a constant amount of memory. + * Time Complexity: O(1) + * Space Complexity: O(1) + * constant time, as these methods perform a fixed number of operations. constant space, as they only use a constant amount of memory. */ /** - * Time Complexity: O(1) - constant time, as these methods perform a fixed number of operations. - * Space Complexity: O(1) - constant space, as they only use a constant amount of memory. + * Time Complexity: O(1) + * Space Complexity: O(1) * * The function `_balanceLL` performs a left-left rotation to balance a binary tree. * @param {N} A - A is a node in a binary tree. @@ -340,13 +345,13 @@ export class AVLTree< } /** - * Time Complexity: O(1) - constant time, as these methods perform a fixed number of operations. - * Space Complexity: O(1) - constant space, as they only use a constant amount of memory. + * Time Complexity: O(1) + * Space Complexity: O(1) */ /** - * Time Complexity: O(1) - constant time, as these methods perform a fixed number of operations. - * Space Complexity: O(1) - constant space, as they only use a constant amount of memory. + * Time Complexity: O(1) + * Space Complexity: O(1) * * The `_balanceLR` function performs a left-right rotation to balance a binary tree. * @param {N} A - A is a node in a binary tree. @@ -396,13 +401,13 @@ export class AVLTree< } /** - * Time Complexity: O(1) - constant time, as these methods perform a fixed number of operations. - * Space Complexity: O(1) - constant space, as they only use a constant amount of memory. + * Time Complexity: O(1) + * Space Complexity: O(1) */ /** - * Time Complexity: O(1) - constant time, as these methods perform a fixed number of operations. - * Space Complexity: O(1) - constant space, as they only use a constant amount of memory. + * Time Complexity: O(1) + * Space Complexity: O(1) * * The function `_balanceRR` performs a right-right rotation to balance a binary tree. * @param {N} A - A is a node in a binary tree. @@ -439,13 +444,13 @@ export class AVLTree< } /** - * Time Complexity: O(1) - constant time, as these methods perform a fixed number of operations. - * Space Complexity: O(1) - constant space, as they only use a constant amount of memory. + * Time Complexity: O(1) + * Space Complexity: O(1) */ /** - * Time Complexity: O(1) - constant time, as these methods perform a fixed number of operations. - * Space Complexity: O(1) - constant space, as they only use a constant amount of memory. + * Time Complexity: O(1) + * Space Complexity: O(1) * * The function `_balanceRL` performs a right-left rotation to balance a binary tree. * @param {N} A - A is a node in a binary tree. diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index b26f4a4..d1d720a 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -14,10 +14,9 @@ import type { BinaryTreePrintOptions, BTNCallback, BTNEntry, - BTNExemplar, - BTNKeyOrNode, DFSOrderPattern, EntryCallback, + KeyOrNodeOrEntry, NodeDisplayLayout } from '../../types'; import { FamilyPosition, IterationType } from '../../types'; @@ -112,15 +111,15 @@ export class BinaryTree< iterationType = IterationType.ITERATIVE; /** - * The constructor function initializes a binary tree object with optional elements and options. - * @param [elements] - An optional iterable of BTNExemplar objects. These objects represent the - * elements to be added to the binary tree. + * The constructor function initializes a binary tree object with optional nodes and options. + * @param [nodes] - An optional iterable of KeyOrNodeOrEntry objects. These objects represent the + * nodes to be added to the binary tree. * @param [options] - The `options` parameter is an optional object that can contain additional * configuration options for the binary tree. In this case, it is of type * `Partial`, which means that not all properties of `BinaryTreeOptions` are * required. */ - constructor(elements?: Iterable>, options?: Partial>) { + constructor(nodes?: Iterable>, options?: Partial>) { super(); if (options) { const { iterationType, extractor } = options; @@ -134,7 +133,7 @@ export class BinaryTree< this._size = 0; - if (elements) this.addMany(elements); + if (nodes) this.addMany(nodes); } protected _extractor = (key: K) => Number(key); @@ -177,30 +176,21 @@ export class BinaryTree< } /** - * The function "isNode" checks if an exemplar is an instance of the BinaryTreeNode class. - * @param exemplar - The `exemplar` parameter is a variable of type `BTNExemplar`. - * @returns a boolean value indicating whether the exemplar is an instance of the class N. - */ - isNode(exemplar: BTNExemplar): exemplar is N { - return exemplar instanceof BinaryTreeNode; - } - - /** - * The function `exemplarToNode` converts an exemplar object into a node object. - * @param exemplar - The `exemplar` parameter is of type `BTNExemplar`. + * The function `exemplarToNode` converts an keyOrNodeOrEntry object into a node object. + * @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter is of type `KeyOrNodeOrEntry`. * @param {V} [value] - The `value` parameter is an optional value that can be passed to the - * `exemplarToNode` function. It represents the value associated with the exemplar node. If no value + * `exemplarToNode` function. It represents the value associated with the keyOrNodeOrEntry node. If no value * is provided, it will be `undefined`. * @returns a value of type N (node), or null, or undefined. */ - exemplarToNode(exemplar: BTNExemplar, value?: V): N | null | undefined { - if (exemplar === undefined) return; + exemplarToNode(keyOrNodeOrEntry: KeyOrNodeOrEntry, value?: V): N | null | undefined { + if (keyOrNodeOrEntry === undefined) return; let node: N | null | undefined; - if (exemplar === null) { + if (keyOrNodeOrEntry === null) { node = null; - } else if (this.isEntry(exemplar)) { - const [key, value] = exemplar; + } else if (this.isEntry(keyOrNodeOrEntry)) { + const [key, value] = keyOrNodeOrEntry; if (key === undefined) { return; } else if (key === null) { @@ -208,24 +198,112 @@ export class BinaryTree< } else { node = this.createNode(key, value); } - } else if (this.isNode(exemplar)) { - node = exemplar; - } else if (this.isNotNodeInstance(exemplar)) { - node = this.createNode(exemplar, value); + } else if (this.isNode(keyOrNodeOrEntry)) { + node = keyOrNodeOrEntry; + } else if (this.isNotNodeInstance(keyOrNodeOrEntry)) { + node = this.createNode(keyOrNodeOrEntry, value); } else { return; } return node; } + /** + * Time Complexity: O(n) + * Space Complexity: O(log n) + */ + + /** + * Time Complexity: O(n) + * Space Complexity: O(log n) + * + * The function `ensureNode` returns the node corresponding to the given key if it is a valid node + * key, otherwise it returns the key itself. + * @param {K | N | null | undefined} keyOrNodeOrEntry - The `key` parameter can be of type `K`, `N`, + * `null`, or `undefined`. It represents a key used to identify a node in a binary tree. + * @param iterationType - The `iterationType` parameter is an optional parameter that specifies the + * type of iteration to be used when searching for a node by key. It has a default value of + * `IterationType.ITERATIVE`. + * @returns either the node corresponding to the given key if it is a valid node key, or the key + * itself if it is not a valid node key. + */ + ensureNode( + keyOrNodeOrEntry: KeyOrNodeOrEntry, + iterationType = IterationType.ITERATIVE + ): N | null | undefined { + let res: N | null | undefined; + if (this.isRealNode(keyOrNodeOrEntry)) { + res = keyOrNodeOrEntry; + } else if (this.isEntry(keyOrNodeOrEntry)) { + if (keyOrNodeOrEntry[0] === null) res = null; + else if (keyOrNodeOrEntry[0] !== undefined) res = this.getNodeByKey(keyOrNodeOrEntry[0], iterationType); + } else { + if (keyOrNodeOrEntry === null) res = null; + else if (keyOrNodeOrEntry !== undefined) res = this.getNodeByKey(keyOrNodeOrEntry, iterationType); + } + return res; + } + + /** + * The function "isNode" checks if an keyOrNodeOrEntry is an instance of the BinaryTreeNode class. + * @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter is a variable of type `KeyOrNodeOrEntry`. + * @returns a boolean value indicating whether the keyOrNodeOrEntry is an instance of the class N. + */ + isNode(keyOrNodeOrEntry: KeyOrNodeOrEntry): keyOrNodeOrEntry is N { + return keyOrNodeOrEntry instanceof BinaryTreeNode; + } + /** * The function checks if a given value is an entry in a binary tree node. - * @param kne - BTNExemplar - A generic type representing a node in a binary tree. It has + * @param keyOrNodeOrEntry - KeyOrNodeOrEntry - A generic type representing a node in a binary tree. It has * two type parameters V and N, representing the value and node type respectively. * @returns a boolean value. */ - isEntry(kne: BTNExemplar): kne is BTNEntry { - return Array.isArray(kne) && kne.length === 2; + isEntry(keyOrNodeOrEntry: KeyOrNodeOrEntry): keyOrNodeOrEntry is BTNEntry { + return Array.isArray(keyOrNodeOrEntry) && keyOrNodeOrEntry.length === 2; + } + + /** + * Time complexity: O(n) + * Space complexity: O(log n) + */ + + /** + * The function checks if a given node is a real node by verifying if it is an instance of + * BinaryTreeNode and its key is not NaN. + * @param {any} node - The parameter `node` is of type `any`, which means it can be any data type. + * @returns a boolean value. + */ + isRealNode(node: KeyOrNodeOrEntry): node is N { + return node instanceof BinaryTreeNode && String(node.key) !== 'NaN'; + } + + /** + * The function checks if a given node is a BinaryTreeNode instance and has a key value of NaN. + * @param {any} node - The parameter `node` is of type `any`, which means it can be any data type. + * @returns a boolean value. + */ + isNIL(node: KeyOrNodeOrEntry) { + return node instanceof BinaryTreeNode && String(node.key) === 'NaN'; + } + + /** + * The function checks if a given node is a real node or null. + * @param {any} node - The parameter `node` is of type `any`, which means it can be any data type. + * @returns a boolean value. + */ + isNodeOrNull(node: KeyOrNodeOrEntry): node is N | null { + return this.isRealNode(node) || node === null; + } + + /** + * The function "isNotNodeInstance" checks if a potential key is a K. + * @param {any} potentialKey - The potentialKey parameter is of type any, which means it can be any + * data type. + * @returns a boolean value indicating whether the potentialKey is of type number or not. + */ + isNotNodeInstance(potentialKey: KeyOrNodeOrEntry): potentialKey is K { + return !(potentialKey instanceof BinaryTreeNode); } /** @@ -243,15 +321,15 @@ export class BinaryTree< * @param {V} [value] - The value to be inserted into the binary tree. * @returns The function `add` returns either a node (`N`), `null`, or `undefined`. */ - add(keyOrNodeOrEntry: BTNExemplar, value?: V): N | null | undefined { + add(keyOrNodeOrEntry: KeyOrNodeOrEntry, value?: V): boolean { const newNode = this.exemplarToNode(keyOrNodeOrEntry, value); - if (newNode === undefined) return; + if (newNode === undefined) return false; // If the tree is empty, directly set the new node as the root node if (!this.root) { this._root = newNode; this._size = 1; - return newNode; + return true; } const queue = new Queue([this.root]); @@ -265,7 +343,7 @@ export class BinaryTree< // Check for duplicate keys when newNode is not null if (newNode !== null && cur.key === newNode.key) { this._replaceNode(cur, newNode); - return newNode; // If duplicate keys are found, no insertion is performed + return true; // If duplicate keys are found, no insertion is performed } // Record the first possible insertion location found @@ -290,10 +368,10 @@ export class BinaryTree< potentialParent.right = newNode; } this._size++; - return newNode; + return true; } - return undefined; // If the insertion position cannot be found, return undefined + return false; // If the insertion position cannot be found, return undefined } /** @@ -306,22 +384,22 @@ export class BinaryTree< * Time Complexity: O(k log n) - O(k * n) * Space Complexity: O(1) * - * The `addMany` function takes in a collection of nodes and an optional collection of values, and + * The `addMany` function takes in a collection of keysOrNodesOrEntries and an optional collection of values, and * adds each node with its corresponding value to the data structure. - * @param nodes - An iterable collection of BTNExemplar objects. + * @param keysOrNodesOrEntries - An iterable collection of KeyOrNodeOrEntry objects. * @param [values] - An optional iterable of values that will be assigned to each node being added. * @returns The function `addMany` returns an array of `N`, `null`, or `undefined` values. */ - addMany(nodes: Iterable>, values?: Iterable): (N | null | undefined)[] { + addMany(keysOrNodesOrEntries: Iterable>, values?: Iterable): boolean[] { // TODO not sure addMany not be run multi times - const inserted: (N | null | undefined)[] = []; + const inserted: boolean[] = []; let valuesIterator: Iterator | undefined; if (values) { valuesIterator = values[Symbol.iterator](); } - for (const kne of nodes) { + for (const keyOrNodeOrEntry of keysOrNodesOrEntries) { let value: V | undefined | null = undefined; if (valuesIterator) { @@ -331,25 +409,39 @@ export class BinaryTree< } } - inserted.push(this.add(kne, value)); + inserted.push(this.add(keyOrNodeOrEntry, value)); } return inserted; } /** - * Time Complexity: O(k * n) "n" is the number of nodes in the tree, and "k" is the number of keys to be inserted. + * Time Complexity: O(k * n) * Space Complexity: O(1) + * "n" is the number of nodes in the tree, and "k" is the number of keys to be inserted. */ - refill(nodesOrKeysOrEntries: Iterable>, values?: Iterable): void { + /** + * Time Complexity: O(k * n) + * Space Complexity: O(1) + * + * The `refill` function clears the current data and adds new key-value pairs to the data structure. + * @param keysOrNodesOrEntries - An iterable containing keys, nodes, or entries. These can be of type + * KeyOrNodeOrEntry. + * @param [values] - The `values` parameter is an optional iterable that contains the values to be + * associated with the keys or nodes or entries in the `keysOrNodesOrEntries` parameter. If provided, + * the values will be associated with the corresponding keys or nodes or entries in the + * `keysOrNodesOrEntries` iterable + */ + refill(keysOrNodesOrEntries: Iterable>, values?: Iterable): void { this.clear(); - this.addMany(nodesOrKeysOrEntries, values); + this.addMany(keysOrNodesOrEntries, values); } /** - * Time Complexity: O(k * n) "n" is the number of nodes in the tree, and "k" is the number of keys to be inserted. + * Time Complexity: O(k * n) * Space Complexity: O(1) + * "n" is the number of nodes in the tree, and "k" is the number of keys to be inserted. */ delete>(identifier: K, callback?: C): BinaryTreeDeleteResult[]; @@ -433,24 +525,24 @@ export class BinaryTree< * Space Complexity: O(1) * * The function calculates the depth of a given node in a binary tree. - * @param {K | N | null | undefined} distNode - The `distNode` parameter represents the node in + * @param {K | N | null | undefined} dist - The `dist` parameter represents the node in * the binary tree whose depth we want to find. It can be of type `K`, `N`, `null`, or * `undefined`. * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting node * from which we want to calculate the depth. It can be either a `K` (binary tree node key) or * `N` (binary tree node) or `null` or `undefined`. If no value is provided for `beginRoot - * @returns the depth of the `distNode` relative to the `beginRoot`. + * @returns the depth of the `dist` relative to the `beginRoot`. */ - getDepth(distNode: BTNKeyOrNode, beginRoot: BTNKeyOrNode = this.root): number { - distNode = this.ensureNode(distNode); + getDepth(dist: KeyOrNodeOrEntry, beginRoot: KeyOrNodeOrEntry = this.root): number { + dist = this.ensureNode(dist); beginRoot = this.ensureNode(beginRoot); let depth = 0; - while (distNode?.parent) { - if (distNode === beginRoot) { + while (dist?.parent) { + if (dist === beginRoot) { return depth; } depth++; - distNode = distNode.parent; + dist = dist.parent; } return depth; } @@ -474,7 +566,7 @@ export class BinaryTree< * values: * @returns the height of the binary tree. */ - getHeight(beginRoot: BTNKeyOrNode = this.root, iterationType = this.iterationType): number { + getHeight(beginRoot: KeyOrNodeOrEntry = this.root, iterationType = this.iterationType): number { beginRoot = this.ensureNode(beginRoot); if (!beginRoot) return -1; @@ -523,7 +615,7 @@ export class BinaryTree< * to calculate the minimum height of a binary tree. It can have two possible values: * @returns The function `getMinHeight` returns the minimum height of a binary tree. */ - getMinHeight(beginRoot: BTNKeyOrNode = this.root, iterationType = this.iterationType): number { + getMinHeight(beginRoot: KeyOrNodeOrEntry = this.root, iterationType = this.iterationType): number { beginRoot = this.ensureNode(beginRoot); if (!beginRoot) return -1; @@ -583,7 +675,7 @@ export class BinaryTree< * value of a binary tree node), `N` (a node of a binary tree), `null`, or `undefined`. If * @returns a boolean value. */ - isPerfectlyBalanced(beginRoot: BTNKeyOrNode = this.root): boolean { + isPerfectlyBalanced(beginRoot: KeyOrNodeOrEntry = this.root): boolean { return this.getMinHeight(beginRoot) + 1 >= this.getHeight(beginRoot); } @@ -596,7 +688,7 @@ export class BinaryTree< identifier: K, callback?: C, onlyOne?: boolean, - beginRoot?: BTNKeyOrNode, + beginRoot?: KeyOrNodeOrEntry, iterationType?: IterationType ): N[]; @@ -604,7 +696,7 @@ export class BinaryTree< identifier: N | null | undefined, callback?: C, onlyOne?: boolean, - beginRoot?: BTNKeyOrNode, + beginRoot?: KeyOrNodeOrEntry, iterationType?: IterationType ): N[]; @@ -612,7 +704,7 @@ export class BinaryTree< identifier: ReturnType, callback: C, onlyOne?: boolean, - beginRoot?: BTNKeyOrNode, + beginRoot?: KeyOrNodeOrEntry, iterationType?: IterationType ): N[]; @@ -645,7 +737,7 @@ export class BinaryTree< identifier: ReturnType | null | undefined, callback: C = this._defaultOneParamCallback as C, onlyOne = false, - beginRoot: BTNKeyOrNode = this.root, + beginRoot: KeyOrNodeOrEntry = this.root, iterationType = this.iterationType ): N[] { if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode) @@ -693,26 +785,27 @@ export class BinaryTree< has>( identifier: K, callback?: C, - beginRoot?: BTNKeyOrNode, + beginRoot?: KeyOrNodeOrEntry, iterationType?: IterationType ): boolean; has>( identifier: N | null | undefined, callback?: C, - beginRoot?: BTNKeyOrNode, + beginRoot?: KeyOrNodeOrEntry, iterationType?: IterationType ): boolean; has>( identifier: ReturnType | null | undefined, callback: C, - beginRoot?: BTNKeyOrNode, + beginRoot?: KeyOrNodeOrEntry, iterationType?: IterationType ): boolean; /** * Time Complexity: O(n) + * Space Complexity: O(log n). * * The function checks if a Binary Tree Node with a specific identifier exists in the tree. * @param {ReturnType | null | undefined} identifier - The `identifier` parameter is the value @@ -734,7 +827,7 @@ export class BinaryTree< has>( identifier: ReturnType | null | undefined, callback: C = this._defaultOneParamCallback as C, - beginRoot: BTNKeyOrNode = this.root, + beginRoot: KeyOrNodeOrEntry = this.root, iterationType = this.iterationType ): boolean { if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode) @@ -751,21 +844,21 @@ export class BinaryTree< getNode>( identifier: K, callback?: C, - beginRoot?: BTNKeyOrNode, + beginRoot?: KeyOrNodeOrEntry, iterationType?: IterationType ): N | null | undefined; getNode>( identifier: N | null | undefined, callback?: C, - beginRoot?: BTNKeyOrNode, + beginRoot?: KeyOrNodeOrEntry, iterationType?: IterationType ): N | null | undefined; getNode>( identifier: ReturnType, callback: C, - beginRoot?: BTNKeyOrNode, + beginRoot?: KeyOrNodeOrEntry, iterationType?: IterationType ): N | null | undefined; @@ -793,7 +886,7 @@ export class BinaryTree< getNode>( identifier: ReturnType | null | undefined, callback: C = this._defaultOneParamCallback as C, - beginRoot: BTNKeyOrNode = this.root, + beginRoot: KeyOrNodeOrEntry = this.root, iterationType = this.iterationType ): N | null | undefined { if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode) @@ -846,44 +939,24 @@ export class BinaryTree< } } - /** - * Time Complexity: O(n) - * Space Complexity: O(log n) - */ - - /** - * The function `ensureNode` returns the node corresponding to the given key if it is a valid node - * key, otherwise it returns the key itself. - * @param {K | N | null | undefined} key - The `key` parameter can be of type `K`, `N`, - * `null`, or `undefined`. It represents a key used to identify a node in a binary tree. - * @param iterationType - The `iterationType` parameter is an optional parameter that specifies the - * type of iteration to be used when searching for a node by key. It has a default value of - * `IterationType.ITERATIVE`. - * @returns either the node corresponding to the given key if it is a valid node key, or the key - * itself if it is not a valid node key. - */ - ensureNode(key: BTNKeyOrNode, iterationType = IterationType.ITERATIVE): N | null | undefined { - return this.isNotNodeInstance(key) ? this.getNodeByKey(key, iterationType) : key; - } - get>( identifier: K, callback?: C, - beginRoot?: BTNKeyOrNode, + beginRoot?: KeyOrNodeOrEntry, iterationType?: IterationType ): V | undefined; get>( identifier: N | null | undefined, callback?: C, - beginRoot?: BTNKeyOrNode, + beginRoot?: KeyOrNodeOrEntry, iterationType?: IterationType ): V | undefined; get>( identifier: ReturnType, callback: C, - beginRoot?: BTNKeyOrNode, + beginRoot?: KeyOrNodeOrEntry, iterationType?: IterationType ): V | undefined; @@ -912,7 +985,7 @@ export class BinaryTree< get>( identifier: ReturnType | null | undefined, callback: C = this._defaultOneParamCallback as C, - beginRoot: BTNKeyOrNode = this.root, + beginRoot: KeyOrNodeOrEntry = this.root, iterationType = this.iterationType ): V | undefined { if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode) @@ -922,11 +995,14 @@ export class BinaryTree< } /** - * Time Complexity: O(n) - * Space Complexity: O(log n) + * Time Complexity: O(1) + * Space Complexity: O(1) */ /** + * Time Complexity: O(1) + * Space Complexity: O(1) + * * Clear the binary tree, removing all nodes. */ clear() { @@ -935,6 +1011,14 @@ export class BinaryTree< } /** + * Time Complexity: O(1) + * Space Complexity: O(1) + */ + + /** + * Time Complexity: O(1) + * Space Complexity: O(1) + * * Check if the binary tree is empty. * @returns {boolean} - True if the binary tree is empty, false otherwise. */ @@ -956,7 +1040,7 @@ export class BinaryTree< * reversed before returning it. If `isReverse` is set to `false`, the path will be returned as is * @returns The function `getPathToRoot` returns an array of nodes (`N[]`). */ - getPathToRoot(beginRoot: BTNKeyOrNode, isReverse = true): N[] { + getPathToRoot(beginRoot: KeyOrNodeOrEntry, isReverse = true): N[] { // TODO to support get path through passing key const result: N[] = []; beginRoot = this.ensureNode(beginRoot); @@ -975,7 +1059,7 @@ export class BinaryTree< /** * Time Complexity: O(log n) - * Space Complexity: O(log n) + * Space Complexity: O(1) */ /** @@ -992,7 +1076,10 @@ export class BinaryTree< * @returns The function `getLeftMost` returns the leftmost node (`N`) in the binary tree. If there * is no leftmost node, it returns `null` or `undefined` depending on the input. */ - getLeftMost(beginRoot: BTNKeyOrNode = this.root, iterationType = this.iterationType): N | null | undefined { + getLeftMost( + beginRoot: KeyOrNodeOrEntry = this.root, + iterationType = this.iterationType + ): N | null | undefined { beginRoot = this.ensureNode(beginRoot); if (!beginRoot) return beginRoot; @@ -1035,7 +1122,10 @@ export class BinaryTree< * @returns The function `getRightMost` returns the rightmost node (`N`) in a binary tree. If there * is no rightmost node, it returns `null` or `undefined`, depending on the input. */ - getRightMost(beginRoot: BTNKeyOrNode = this.root, iterationType = this.iterationType): N | null | undefined { + getRightMost( + beginRoot: KeyOrNodeOrEntry = this.root, + iterationType = this.iterationType + ): N | null | undefined { // TODO support get right most by passing key in beginRoot = this.ensureNode(beginRoot); if (!beginRoot) return beginRoot; @@ -1075,7 +1165,7 @@ export class BinaryTree< * possible values: * @returns a boolean value. */ - isBST(beginRoot: BTNKeyOrNode = this.root, iterationType = this.iterationType): boolean { + isBST(beginRoot: KeyOrNodeOrEntry = this.root, iterationType = this.iterationType): boolean { // TODO there is a bug beginRoot = this.ensureNode(beginRoot); if (!beginRoot) return true; @@ -1117,27 +1207,27 @@ export class BinaryTree< } /** - * Time Complexity: O(n) - * Space Complexity: O(1) + * Time complexity: O(n) + * Space complexity: O(log n) */ subTreeTraverse>( callback?: C, - beginRoot?: BTNKeyOrNode, + beginRoot?: KeyOrNodeOrEntry, iterationType?: IterationType, includeNull?: false ): ReturnType[]; subTreeTraverse>( callback?: C, - beginRoot?: BTNKeyOrNode, + beginRoot?: KeyOrNodeOrEntry, iterationType?: IterationType, includeNull?: undefined ): ReturnType[]; subTreeTraverse>( callback?: C, - beginRoot?: BTNKeyOrNode, + beginRoot?: KeyOrNodeOrEntry, iterationType?: IterationType, includeNull?: true ): ReturnType[]; @@ -1161,12 +1251,12 @@ export class BinaryTree< * whether to include null values in the traversal. If `includeNull` is set to `true`, the * traversal will include null values, otherwise it will skip them. * @returns The function `subTreeTraverse` returns an array of values that are the result of invoking - * the `callback` function on each node in the subtree. The type of the array elements is determined + * the `callback` function on each node in the subtree. The type of the array nodes is determined * by the return type of the `callback` function. */ subTreeTraverse>( callback: C = this._defaultOneParamCallback as C, - beginRoot: BTNKeyOrNode = this.root, + beginRoot: KeyOrNodeOrEntry = this.root, iterationType = this.iterationType, includeNull = false ): ReturnType[] { @@ -1210,53 +1300,10 @@ export class BinaryTree< return ans; } - /** - * Time complexity: O(n) - * Space complexity: O(log n) - */ - - /** - * The function checks if a given node is a real node by verifying if it is an instance of - * BinaryTreeNode and its key is not NaN. - * @param {any} node - The parameter `node` is of type `any`, which means it can be any data type. - * @returns a boolean value. - */ - isRealNode(node: BTNExemplar): node is N { - return node instanceof BinaryTreeNode && String(node.key) !== 'NaN'; - } - - /** - * The function checks if a given node is a BinaryTreeNode instance and has a key value of NaN. - * @param {any} node - The parameter `node` is of type `any`, which means it can be any data type. - * @returns a boolean value. - */ - isNIL(node: BTNExemplar) { - return node instanceof BinaryTreeNode && String(node.key) === 'NaN'; - } - - /** - * The function checks if a given node is a real node or null. - * @param {any} node - The parameter `node` is of type `any`, which means it can be any data type. - * @returns a boolean value. - */ - isNodeOrNull(node: BTNExemplar): node is N | null { - return this.isRealNode(node) || node === null; - } - - /** - * The function "isNotNodeInstance" checks if a potential key is a K. - * @param {any} potentialKey - The potentialKey parameter is of type any, which means it can be any - * data type. - * @returns a boolean value indicating whether the potentialKey is of type number or not. - */ - isNotNodeInstance(potentialKey: BTNKeyOrNode): potentialKey is K { - return !(potentialKey instanceof BinaryTreeNode); - } - dfs>( callback?: C, pattern?: DFSOrderPattern, - beginRoot?: BTNKeyOrNode, + beginRoot?: KeyOrNodeOrEntry, iterationType?: IterationType, includeNull?: false ): ReturnType[]; @@ -1264,7 +1311,7 @@ export class BinaryTree< dfs>( callback?: C, pattern?: DFSOrderPattern, - beginRoot?: BTNKeyOrNode, + beginRoot?: KeyOrNodeOrEntry, iterationType?: IterationType, includeNull?: undefined ): ReturnType[]; @@ -1272,7 +1319,7 @@ export class BinaryTree< dfs>( callback?: C, pattern?: DFSOrderPattern, - beginRoot?: BTNKeyOrNode, + beginRoot?: KeyOrNodeOrEntry, iterationType?: IterationType, includeNull?: true ): ReturnType[]; @@ -1303,7 +1350,7 @@ export class BinaryTree< dfs>( callback: C = this._defaultOneParamCallback as C, pattern: DFSOrderPattern = 'in', - beginRoot: BTNKeyOrNode = this.root, + beginRoot: KeyOrNodeOrEntry = this.root, iterationType: IterationType = IterationType.ITERATIVE, includeNull = false ): ReturnType[] { @@ -1402,21 +1449,21 @@ export class BinaryTree< bfs>( callback?: C, - beginRoot?: BTNKeyOrNode, + beginRoot?: KeyOrNodeOrEntry, iterationType?: IterationType, includeNull?: false ): ReturnType[]; bfs>( callback?: C, - beginRoot?: BTNKeyOrNode, + beginRoot?: KeyOrNodeOrEntry, iterationType?: IterationType, includeNull?: undefined ): ReturnType[]; bfs>( callback?: C, - beginRoot?: BTNKeyOrNode, + beginRoot?: KeyOrNodeOrEntry, iterationType?: IterationType, includeNull?: true ): ReturnType[]; @@ -1444,7 +1491,7 @@ export class BinaryTree< */ bfs>( callback: C = this._defaultOneParamCallback as C, - beginRoot: BTNKeyOrNode = this.root, + beginRoot: KeyOrNodeOrEntry = this.root, iterationType = this.iterationType, includeNull = false ): ReturnType[] { @@ -1503,21 +1550,21 @@ export class BinaryTree< listLevels>( callback?: C, - beginRoot?: BTNKeyOrNode, + beginRoot?: KeyOrNodeOrEntry, iterationType?: IterationType, includeNull?: false ): ReturnType[][]; listLevels>( callback?: C, - beginRoot?: BTNKeyOrNode, + beginRoot?: KeyOrNodeOrEntry, iterationType?: IterationType, includeNull?: undefined ): ReturnType[][]; listLevels>( callback?: C, - beginRoot?: BTNKeyOrNode, + beginRoot?: KeyOrNodeOrEntry, iterationType?: IterationType, includeNull?: true ): ReturnType[][]; @@ -1545,7 +1592,7 @@ export class BinaryTree< */ listLevels>( callback: C = this._defaultOneParamCallback as C, - beginRoot: BTNKeyOrNode = this.root, + beginRoot: KeyOrNodeOrEntry = this.root, iterationType = this.iterationType, includeNull = false ): ReturnType[][] { @@ -1642,7 +1689,13 @@ export class BinaryTree< /** * Time complexity: O(n) - * Space complexity: O(1) + * Space complexity: O(n) + */ + + /** + * Time complexity: O(n) + * Space complexity: O(n) + * * The `morris` function performs a depth-first traversal on a binary tree using the Morris traversal * algorithm. * @param {C} callback - The `callback` parameter is a function that will be called for each node in @@ -1655,13 +1708,13 @@ export class BinaryTree< * for the traversal. It can be specified as a key, a node object, or `null`/`undefined` to indicate * the root of the tree. If no value is provided, the default value is the root of the tree. * @returns The function `morris` returns an array of values that are the result of invoking the - * `callback` function on each node in the binary tree. The type of the array elements is determined + * `callback` function on each node in the binary tree. The type of the array nodes is determined * by the return type of the `callback` function. */ morris>( callback: C = this._defaultOneParamCallback as C, pattern: DFSOrderPattern = 'in', - beginRoot: BTNKeyOrNode = this.root + beginRoot: KeyOrNodeOrEntry = this.root ): ReturnType[] { beginRoot = this.ensureNode(beginRoot); if (beginRoot === null) return []; @@ -1772,8 +1825,8 @@ export class BinaryTree< * Time Complexity: O(n) * Space Complexity: O(n) * - * The `filter` function creates a new tree by iterating over the elements of the current tree and - * adding only the elements that satisfy the given predicate function. + * The `filter` function creates a new tree by iterating over the nodes of the current tree and + * adding only the nodes that satisfy the given predicate function. * @param predicate - The `predicate` parameter is a function that takes three arguments: `value`, * `key`, and `index`. It should return a boolean value indicating whether the pair should be * included in the filtered tree or not. @@ -1834,13 +1887,21 @@ export class BinaryTree< // /** + * Time Complexity: O(n) + * Space Complexity: O(n) + */ + + /** + * Time Complexity: O(n) + * Space Complexity: O(n) + * * The `print` function is used to display a binary tree structure in a visually appealing way. * @param {K | N | null | undefined} [beginRoot=this.root] - The `root` parameter is of type `K | N | null | * undefined`. It represents the root node of a binary tree. The root node can have one of the * following types: * @param {BinaryTreePrintOptions} [options={ isShowUndefined: false, isShowNull: false, isShowRedBlackNIL: false}] - Options object that controls printing behavior. You can specify whether to display undefined, null, or sentinel nodes. */ - print(beginRoot: BTNKeyOrNode = this.root, options?: BinaryTreePrintOptions): void { + print(beginRoot: KeyOrNodeOrEntry = this.root, options?: BinaryTreePrintOptions): void { const opts = { isShowUndefined: false, isShowNull: false, isShowRedBlackNIL: false, ...options }; beginRoot = this.ensureNode(beginRoot); if (!beginRoot) return; @@ -1972,7 +2033,7 @@ export class BinaryTree< * @param {N} destNode - The destination node to swap. * @returns {N} - The destination node after the swap. */ - protected _swapProperties(srcNode: BTNKeyOrNode, destNode: BTNKeyOrNode): N | undefined { + protected _swapProperties(srcNode: KeyOrNodeOrEntry, destNode: KeyOrNodeOrEntry): N | undefined { srcNode = this.ensureNode(srcNode); destNode = this.ensureNode(destNode); diff --git a/src/data-structures/binary-tree/bst.ts b/src/data-structures/binary-tree/bst.ts index b1656a3..77a058f 100644 --- a/src/data-structures/binary-tree/bst.ts +++ b/src/data-structures/binary-tree/bst.ts @@ -7,13 +7,11 @@ */ import type { BSTNested, - BSTNKeyOrNode, BSTNodeNested, BSTOptions, BTNCallback, - BTNExemplar, - BTNKeyOrNode, - BTNodePureExemplar + BTNodePureExemplar, + KeyOrNodeOrEntry } from '../../types'; import { BSTVariant, CP, IterationType } from '../../types'; import { BinaryTree, BinaryTreeNode } from './binary-tree'; @@ -94,13 +92,13 @@ export class BST< implements IBinaryTree { /** * This is the constructor function for a binary search tree class in TypeScript, which initializes - * the tree with optional elements and options. - * @param [elements] - An optional iterable of BTNExemplar objects that will be added to the + * the tree with optional nodes and options. + * @param [nodes] - An optional iterable of KeyOrNodeOrEntry objects that will be added to the * binary search tree. * @param [options] - The `options` parameter is an optional object that can contain additional * configuration options for the binary search tree. It can have the following properties: */ - constructor(elements?: Iterable>, options?: Partial>) { + constructor(nodes?: Iterable>, options?: Partial>) { super([], options); if (options) { @@ -112,7 +110,7 @@ export class BST< this._root = undefined; - if (elements) this.addMany(elements); + if (nodes) this.addMany(nodes); } protected override _root?: N; @@ -155,37 +153,28 @@ export class BST< } /** - * The function checks if an exemplar is an instance of BSTNode. - * @param exemplar - The `exemplar` parameter is a variable of type `BTNExemplar`. - * @returns a boolean value indicating whether the exemplar is an instance of the BSTNode class. - */ - override isNode(exemplar: BTNExemplar): exemplar is N { - return exemplar instanceof BSTNode; - } - - /** - * The function `exemplarToNode` takes an exemplar and returns a node if the exemplar is valid, + * The function `exemplarToNode` takes an keyOrNodeOrEntry and returns a node if the keyOrNodeOrEntry is valid, * otherwise it returns undefined. - * @param exemplar - The `exemplar` parameter is of type `BTNExemplar`, where: + * @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter is of type `KeyOrNodeOrEntry`, where: * @param {V} [value] - The `value` parameter is an optional value that can be passed to the - * `exemplarToNode` function. It represents the value associated with the exemplar node. + * `exemplarToNode` function. It represents the value associated with the keyOrNodeOrEntry node. * @returns a node of type N or undefined. */ - override exemplarToNode(exemplar: BTNExemplar, value?: V): N | undefined { + override exemplarToNode(keyOrNodeOrEntry: KeyOrNodeOrEntry, value?: V): N | undefined { let node: N | undefined; - if (exemplar === null || exemplar === undefined) { + if (keyOrNodeOrEntry === null || keyOrNodeOrEntry === undefined) { return; - } else if (this.isNode(exemplar)) { - node = exemplar; - } else if (this.isEntry(exemplar)) { - const [key, value] = exemplar; + } else if (this.isNode(keyOrNodeOrEntry)) { + node = keyOrNodeOrEntry; + } else if (this.isEntry(keyOrNodeOrEntry)) { + const [key, value] = keyOrNodeOrEntry; if (key === undefined || key === null) { return; } else { node = this.createNode(key, value); } - } else if (this.isNotNodeInstance(exemplar)) { - node = this.createNode(exemplar, value); + } else if (this.isNotNodeInstance(keyOrNodeOrEntry)) { + node = this.createNode(keyOrNodeOrEntry, value); } else { return; } @@ -193,13 +182,66 @@ export class BST< } /** - * Time Complexity: O(log n) - Average case for a balanced tree. In the worst case (unbalanced tree), it can be O(n). - * Space Complexity: O(1) - Constant space is used. + * Time Complexity: O(log n) + * Space Complexity: O(log n) + * Average case for a balanced tree. Space for the recursive call stack in the worst case. */ /** - * Time Complexity: O(log n) - Average case for a balanced tree. In the worst case (unbalanced tree), it can be O(n). - * Space Complexity: O(1) - Constant space is used. + * Time Complexity: O(log n) + * Space Complexity: O(log n) + * + * The function `ensureNode` returns the node corresponding to the given key if it is a node key, + * otherwise it returns the key itself. + * @param {K | N | undefined} keyOrNodeOrEntry - The `key` parameter can be of type `K`, `N`, or + * `undefined`. + * @param iterationType - The `iterationType` parameter is an optional parameter that specifies the + * type of iteration to be performed. It has a default value of `IterationType.ITERATIVE`. + * @returns either a node object (N) or undefined. + */ + override ensureNode( + keyOrNodeOrEntry: KeyOrNodeOrEntry, + iterationType = IterationType.ITERATIVE + ): N | undefined { + let res: N | undefined; + if (this.isRealNode(keyOrNodeOrEntry)) { + res = keyOrNodeOrEntry; + } else if (this.isEntry(keyOrNodeOrEntry)) { + if (keyOrNodeOrEntry[0]) res = this.getNodeByKey(keyOrNodeOrEntry[0], iterationType); + } else { + if (keyOrNodeOrEntry) res = this.getNodeByKey(keyOrNodeOrEntry, iterationType); + } + return res; + } + + /** + * The function "isNotNodeInstance" checks if a potential key is a K. + * @param {any} potentialKey - The potentialKey parameter is of type any, which means it can be any + * data type. + * @returns a boolean value indicating whether the potentialKey is of type number or not. + */ + override isNotNodeInstance(potentialKey: KeyOrNodeOrEntry): potentialKey is K { + return !(potentialKey instanceof BSTNode); + } + + /** + * The function checks if an keyOrNodeOrEntry is an instance of BSTNode. + * @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter is a variable of type `KeyOrNodeOrEntry`. + * @returns a boolean value indicating whether the keyOrNodeOrEntry is an instance of the BSTNode class. + */ + override isNode(keyOrNodeOrEntry: KeyOrNodeOrEntry): keyOrNodeOrEntry is N { + return keyOrNodeOrEntry instanceof BSTNode; + } + + /** + * Time Complexity: O(log n) + * Space Complexity: O(1) + * - Average case for a balanced tree. In the worst case (unbalanced tree), it can be O(n). + */ + + /** + * Time Complexity: O(log n) + * Space Complexity: O(1) * * The `add` function adds a new node to a binary tree, updating the value if the key already exists * or inserting a new node if the key is unique. @@ -209,14 +251,14 @@ export class BST< * @returns The method `add` returns either the newly added node (`newNode`) or `undefined` if the * node was not added. */ - override add(keyOrNodeOrEntry: BTNExemplar, value?: V): N | undefined { + override add(keyOrNodeOrEntry: KeyOrNodeOrEntry, value?: V): boolean { const newNode = this.exemplarToNode(keyOrNodeOrEntry, value); - if (newNode === undefined) return; + if (newNode === undefined) return false; if (this.root === undefined) { this._setRoot(newNode); this._size++; - return this.root; + return true; } let current = this.root; @@ -225,7 +267,7 @@ export class BST< // if (current !== newNode) { // The key value is the same but the reference is different, update the value of the existing node this._replaceNode(current, newNode); - return newNode; + return true; // } else { // The key value is the same and the reference is the same, replace the entire node @@ -238,7 +280,7 @@ export class BST< current.left = newNode; newNode.parent = current; this._size++; - return newNode; + return true; } current = current.left; } else { @@ -246,23 +288,24 @@ export class BST< current.right = newNode; newNode.parent = current; this._size++; - return newNode; + return true; } current = current.right; } } - return undefined; + return false; } /** - * Time Complexity: O(k log n) - Adding each element individually in a balanced tree. - * Space Complexity: O(k) - Additional space is required for the sorted array. + * Time Complexity: O(k log n) + * Space Complexity: O(k) + * Adding each element individually in a balanced tree. Additional space is required for the sorted array. */ /** - * Time Complexity: O(k log n) - Adding each element individually in a balanced tree. - * Space Complexity: O(k) - Additional space is required for the sorted array. + * Time Complexity: O(k log n) + * Space Complexity: O(k) * * The `addMany` function in TypeScript adds multiple keys or nodes to a binary tree, optionally * balancing the tree after each addition. @@ -273,7 +316,7 @@ export class BST< * order. If not provided, undefined will be assigned as the value for each key or node. * @param [isBalanceAdd=true] - A boolean flag indicating whether the add operation should be * balanced or not. If set to true, the add operation will be balanced using a binary search tree - * algorithm. If set to false, the add operation will not be balanced and the elements will be added + * algorithm. If set to false, the add operation will not be balanced and the nodes will be added * in the order they appear in the input. * @param iterationType - The `iterationType` parameter is an optional parameter that specifies the * type of iteration to use when adding multiple keys or nodes. It has a default value of @@ -281,12 +324,12 @@ export class BST< * @returns The function `addMany` returns an array of nodes (`N`) or `undefined` values. */ override addMany( - keysOrNodesOrEntries: Iterable>, + keysOrNodesOrEntries: Iterable>, values?: Iterable, isBalanceAdd = true, iterationType = this.iterationType - ): (N | undefined)[] { - const inserted: (N | undefined)[] = []; + ): boolean[] { + const inserted: boolean[] = []; let valuesIterator: Iterator | undefined; @@ -305,7 +348,7 @@ export class BST< const realBTNExemplars: BTNodePureExemplar[] = []; - const isRealBTNExemplar = (kve: BTNExemplar): kve is BTNodePureExemplar => { + const isRealBTNExemplar = (kve: KeyOrNodeOrEntry): kve is BTNodePureExemplar => { if (kve === undefined || kve === null) return false; return !(this.isEntry(kve) && (kve[0] === undefined || kve[0] === null)); }; @@ -367,26 +410,25 @@ export class BST< } /** - * Time Complexity: O(n log n) - Adding each element individually in a balanced tree. - * Space Complexity: O(n) - Additional space is required for the sorted array. + * Time Complexity: O(n log n) + * Space Complexity: O(n) + * Adding each element individually in a balanced tree. Additional space is required for the sorted array. */ /** - * Time Complexity: O(log n) - Average case for a balanced tree. - * Space Complexity: O(1) - Constant space is used. + * Time Complexity: O(n log n) + * Space Complexity: O(n) * * The `lastKey` function returns the key of the rightmost node in a binary tree, or the key of the * leftmost node if the comparison result is greater than. * @param {K | N | undefined} beginRoot - The `beginRoot` parameter is optional and can be of * type `K`, `N`, or `undefined`. It represents the starting point for finding the last key in * the binary tree. If not provided, it defaults to the root of the binary tree (`this.root`). - * @param iterationType - The `iterationType` parameter is used to specify the type of iteration to - * be performed. It can have one of the following values: * @returns the key of the rightmost node in the binary tree if the comparison result is less than, * the key of the leftmost node if the comparison result is greater than, and the key of the * rightmost node otherwise. If no node is found, it returns 0. */ - lastKey(beginRoot: BSTNKeyOrNode = this.root): K | undefined { + lastKey(beginRoot: KeyOrNodeOrEntry = this.root): K | undefined { let current = this.ensureNode(beginRoot); if (!current) return undefined; @@ -405,13 +447,13 @@ export class BST< } /** - * Time Complexity: O(log n) - Average case for a balanced tree. - * Space Complexity: O(1) - Constant space is used. + * Time Complexity: O(log n) + * Space Complexity: O(1) */ /** - * Time Complexity: O(log n) - Average case for a balanced tree. - * Space Complexity: O(log n) - Space for the recursive call stack in the worst case. + * Time Complexity: O(log n) + * Space Complexity: O(1) * * The function `getNodeByKey` searches for a node in a binary tree based on a given key, using * either recursive or iterative methods. @@ -449,36 +491,14 @@ export class BST< } /** - * The function "isNotNodeInstance" checks if a potential key is a K. - * @param {any} potentialKey - The potentialKey parameter is of type any, which means it can be any - * data type. - * @returns a boolean value indicating whether the potentialKey is of type number or not. - */ - override isNotNodeInstance(potentialKey: BTNKeyOrNode): potentialKey is K { - return !(potentialKey instanceof BSTNode); - } + * Time Complexity: O(log n) + * Space Complexity: O(log n) + * Average case for a balanced tree. O(n) - Visiting each node once when identifier is not node's key. Space for the recursive call stack in the worst case. + * / - /** - * Time Complexity: O(log n) - Average case for a balanced tree. - * Space Complexity: O(log n) - Space for the recursive call stack in the worst case. - */ - - /** - * The function `ensureNode` returns the node corresponding to the given key if it is a node key, - * otherwise it returns the key itself. - * @param {K | N | undefined} key - The `key` parameter can be of type `K`, `N`, or - * `undefined`. - * @param iterationType - The `iterationType` parameter is an optional parameter that specifies the - * type of iteration to be performed. It has a default value of `IterationType.ITERATIVE`. - * @returns either a node object (N) or undefined. - */ - override ensureNode(key: BSTNKeyOrNode, iterationType = IterationType.ITERATIVE): N | undefined { - return this.isNotNodeInstance(key) ? this.getNodeByKey(key, iterationType) : key; - } - - /** - * Time Complexity: O(log n) - Average case for a balanced tree. O(n) - Visiting each node once when identifier is not node's key. - * Space Complexity: O(log n) - Space for the recursive call stack in the worst case. + /** + * Time Complexity: O(log n) + * Space Complexity: O(log n) * * The function `getNodes` returns an array of nodes that match a given identifier, using either a * recursive or iterative approach. @@ -503,7 +523,7 @@ export class BST< identifier: ReturnType | undefined, callback: C = this._defaultOneParamCallback as C, onlyOne = false, - beginRoot: BSTNKeyOrNode = this.root, + beginRoot: KeyOrNodeOrEntry = this.root, iterationType = this.iterationType ): N[] { beginRoot = this.ensureNode(beginRoot); @@ -556,13 +576,14 @@ export class BST< } /** - * Time Complexity: O(log n) - Average case for a balanced tree. O(n) - Visiting each node once when identifier is not node's key. - * Space Complexity: O(log n) - Space for the recursive call stack in the worst case. + * Time Complexity: O(log n) + * Space Complexity: O(log n) + * Average case for a balanced tree. O(n) - Visiting each node once when identifier is not node's key. Space for the recursive call stack in the worst case. */ /** - * Time Complexity: O(log n) - Average case for a balanced tree. O(n) - Visiting each node once when identifier is not node's key. - * Space Complexity: O(log n) - Space for the recursive call stack in the worst case. + * Time Complexity: O(log n) + * Space Complexity: O(log n) * * The `lesserOrGreaterTraverse` function traverses a binary tree and returns an array of nodes that * are either lesser or greater than a target node, depending on the specified comparison type. @@ -584,7 +605,7 @@ export class BST< lesserOrGreaterTraverse>( callback: C = this._defaultOneParamCallback as C, lesserOrGreater: CP = CP.lt, - targetNode: BSTNKeyOrNode = this.root, + targetNode: KeyOrNodeOrEntry = this.root, iterationType = this.iterationType ): ReturnType[] { targetNode = this.ensureNode(targetNode); @@ -623,13 +644,13 @@ export class BST< } /** - * Time Complexity: O(log n) - Average case for a balanced tree. O(n) - Visiting each node once when identifier is not node's key. - * Space Complexity: O(log n) - Space for the recursive call stack in the worst case. + * Time Complexity: O(log n) + * Space Complexity: O(log n) */ /** - * Time Complexity: O(n) - Building a balanced tree from a sorted array. - * Space Complexity: O(n) - Additional space is required for the sorted array. + * Time Complexity: O(log n) + * Space Complexity: O(log n) * * The `perfectlyBalance` function balances a binary search tree by adding nodes in a way that * ensures the tree is perfectly balanced. @@ -691,8 +712,8 @@ export class BST< */ /** - * Time Complexity: O(n) - Visiting each node once. - * Space Complexity: O(log n) - Space for the recursive call stack in the worst case. + * Time Complexity: O(n) + * Space Complexity: O(log n) * * The function checks if a binary tree is AVL balanced using either recursive or iterative approach. * @param iterationType - The `iterationType` parameter is used to determine the method of iteration diff --git a/src/data-structures/binary-tree/rb-tree.ts b/src/data-structures/binary-tree/rb-tree.ts index 1089ea5..7b06226 100644 --- a/src/data-structures/binary-tree/rb-tree.ts +++ b/src/data-structures/binary-tree/rb-tree.ts @@ -10,9 +10,8 @@ import { BinaryTreeDeleteResult, BSTNKeyOrNode, BTNCallback, - BTNExemplar, - BTNKeyOrNode, IterationType, + KeyOrNodeOrEntry, RBTNColor, RBTreeOptions, RedBlackTreeNested, @@ -53,20 +52,20 @@ export class RedBlackTree< /** * This is the constructor function for a Red-Black Tree data structure in TypeScript, which - * initializes the tree with optional elements and options. - * @param [elements] - The `elements` parameter is an optional iterable of `BTNExemplar` - * objects. It represents the initial elements that will be added to the RBTree during its + * initializes the tree with optional nodes and options. + * @param [nodes] - The `nodes` parameter is an optional iterable of `KeyOrNodeOrEntry` + * objects. It represents the initial nodes that will be added to the RBTree during its * construction. If this parameter is provided, the `addMany` method is called to add all the - * elements to the + * nodes to the * @param [options] - The `options` parameter is an optional object that allows you to customize the * behavior of the RBTree. It is of type `Partial`, which means that you can provide * only a subset of the properties defined in the `RBTreeOptions` interface. */ - constructor(elements?: Iterable>, options?: Partial>) { + constructor(nodes?: Iterable>, options?: Partial>) { super([], options); this._root = this.Sentinel; - if (elements) super.addMany(elements); + if (nodes) super.addMany(nodes); } protected _root: N; @@ -113,13 +112,53 @@ export class RedBlackTree< } /** - * The function checks if an exemplar is an instance of the RedBlackTreeNode class. - * @param exemplar - The `exemplar` parameter is of type `BTNExemplar`. - * @returns a boolean value indicating whether the exemplar is an instance of the RedBlackTreeNode + * The function `exemplarToNode` takes an keyOrNodeOrEntry and converts it into a node object if possible. + * @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter is of type `KeyOrNodeOrEntry`, where: + * @param {V} [value] - The `value` parameter is an optional value that can be passed to the + * `exemplarToNode` function. It represents the value associated with the keyOrNodeOrEntry node. If a value + * is provided, it will be used when creating the new node. If no value is provided, the new node + * @returns a node of type N or undefined. + */ + override exemplarToNode(keyOrNodeOrEntry: KeyOrNodeOrEntry, value?: V): N | undefined { + let node: N | undefined; + + if (keyOrNodeOrEntry === null || keyOrNodeOrEntry === undefined) { + return; + } else if (this.isNode(keyOrNodeOrEntry)) { + node = keyOrNodeOrEntry; + } else if (this.isEntry(keyOrNodeOrEntry)) { + const [key, value] = keyOrNodeOrEntry; + if (key === undefined || key === null) { + return; + } else { + node = this.createNode(key, value, RBTNColor.RED); + } + } else if (this.isNotNodeInstance(keyOrNodeOrEntry)) { + node = this.createNode(keyOrNodeOrEntry, value, RBTNColor.RED); + } else { + return; + } + return node; + } + + /** + * The function checks if an keyOrNodeOrEntry is an instance of the RedBlackTreeNode class. + * @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter is of type `KeyOrNodeOrEntry`. + * @returns a boolean value indicating whether the keyOrNodeOrEntry is an instance of the RedBlackTreeNode * class. */ - override isNode(exemplar: BTNExemplar): exemplar is N { - return exemplar instanceof RedBlackTreeNode; + override isNode(keyOrNodeOrEntry: KeyOrNodeOrEntry): keyOrNodeOrEntry is N { + return keyOrNodeOrEntry instanceof RedBlackTreeNode; + } + + /** + * Time Complexity: O(log n) on average (where n is the number of nodes in the tree) + * Space Complexity: O(1) + */ + + override isRealNode(node: N | undefined): node is N { + if (node === this.Sentinel || node === undefined) return false; + return node instanceof RedBlackTreeNode; } /** @@ -128,47 +167,18 @@ export class RedBlackTree< * data type. * @returns a boolean value indicating whether the potentialKey is of type number or not. */ - override isNotNodeInstance(potentialKey: BTNKeyOrNode): potentialKey is K { + override isNotNodeInstance(potentialKey: KeyOrNodeOrEntry): potentialKey is K { return !(potentialKey instanceof RedBlackTreeNode); } /** - * The function `exemplarToNode` takes an exemplar and converts it into a node object if possible. - * @param exemplar - The `exemplar` parameter is of type `BTNExemplar`, where: - * @param {V} [value] - The `value` parameter is an optional value that can be passed to the - * `exemplarToNode` function. It represents the value associated with the exemplar node. If a value - * is provided, it will be used when creating the new node. If no value is provided, the new node - * @returns a node of type N or undefined. - */ - override exemplarToNode(exemplar: BTNExemplar, value?: V): N | undefined { - let node: N | undefined; - - if (exemplar === null || exemplar === undefined) { - return; - } else if (this.isNode(exemplar)) { - node = exemplar; - } else if (this.isEntry(exemplar)) { - const [key, value] = exemplar; - if (key === undefined || key === null) { - return; - } else { - node = this.createNode(key, value, RBTNColor.RED); - } - } else if (this.isNotNodeInstance(exemplar)) { - node = this.createNode(exemplar, value, RBTNColor.RED); - } else { - return; - } - return node; - } - - /** - * Time Complexity: O(log n) on average (where n is the number of nodes in the tree) + * Time Complexity: O(log n) * Space Complexity: O(1) + * on average (where n is the number of nodes in the tree) */ /** - * Time Complexity: O(log n) on average (where n is the number of nodes in the tree) + * Time Complexity: O(log n) * Space Complexity: O(1) * * The `add` function adds a new node to a binary search tree and performs necessary rotations and @@ -179,9 +189,9 @@ export class RedBlackTree< * being added to the binary search tree. * @returns The method `add` returns either the newly added node (`N`) or `undefined`. */ - override add(keyOrNodeOrEntry: BTNExemplar, value?: V): N | undefined { + override add(keyOrNodeOrEntry: KeyOrNodeOrEntry, value?: V): boolean { const newNode = this.exemplarToNode(keyOrNodeOrEntry, value); - if (newNode === undefined) return; + if (newNode === undefined) return false; newNode.left = this.Sentinel; newNode.right = this.Sentinel; @@ -200,7 +210,7 @@ export class RedBlackTree< if (newNode !== x) { this._replaceNode(x, newNode); } - return; + return false; } } } @@ -217,25 +227,27 @@ export class RedBlackTree< if (newNode.parent === undefined) { newNode.color = RBTNColor.BLACK; this._size++; - return; + return false; } if (newNode.parent.parent === undefined) { this._size++; - return; + return false; } this._fixInsert(newNode); this._size++; + return true; } /** - * Time Complexity: O(log n) on average (where n is the number of nodes in the tree) + * Time Complexity: O(log n) * Space Complexity: O(1) + * on average (where n is the number of nodes in the tree) */ /** - * Time Complexity: O(log n) on average (where n is the number of nodes in the tree) + * Time Complexity: O(log n) * Space Complexity: O(1) * * The `delete` function removes a node from a binary tree based on a given identifier and updates @@ -310,16 +322,6 @@ export class RedBlackTree< return ans; } - /** - * Time Complexity: O(log n) on average (where n is the number of nodes in the tree) - * Space Complexity: O(1) - */ - - override isRealNode(node: N | undefined): node is N { - if (node === this.Sentinel || node === undefined) return false; - return node instanceof RedBlackTreeNode; - } - getNode>( identifier: K, callback?: C, @@ -342,12 +344,12 @@ export class RedBlackTree< ): N | undefined; /** - * Time Complexity: O(log n) on average (where n is the number of nodes in the tree) + * Time Complexity: O(log n) * Space Complexity: O(1) */ /** - * Time Complexity: O(log n) on average (where n is the number of nodes in the tree) + * Time Complexity: O(log n) * Space Complexity: O(1) * * The function `getNode` retrieves a single node from a binary tree based on a given identifier and @@ -407,7 +409,7 @@ export class RedBlackTree< } /** - * Time Complexity: O(log n) on average (where n is the number of nodes in the tree) + * Time Complexity: O(1) * Space Complexity: O(1) */ @@ -489,12 +491,12 @@ export class RedBlackTree< } /** - * Time Complexity: O(log n) on average (where n is the number of nodes in the tree) + * Time Complexity: O(log n) * Space Complexity: O(1) */ /** - * Time Complexity: O(log n) on average (where n is the number of nodes in the tree) + * Time Complexity: O(log n) * Space Complexity: O(1) * * The function `_fixDelete` is used to fix the red-black tree after a node deletion. @@ -585,12 +587,12 @@ export class RedBlackTree< } /** - * Time Complexity: O(log n) on average (where n is the number of nodes in the tree) + * Time Complexity: O(log n) * Space Complexity: O(1) */ /** - * Time Complexity: O(log n) on average (where n is the number of nodes in the tree) + * Time Complexity: O(log n) * Space Complexity: O(1) * * The `_fixInsert` function is used to fix the red-black tree after an insertion operation. diff --git a/src/data-structures/binary-tree/tree-multimap.ts b/src/data-structures/binary-tree/tree-multimap.ts index 2254e13..4a7ddba 100644 --- a/src/data-structures/binary-tree/tree-multimap.ts +++ b/src/data-structures/binary-tree/tree-multimap.ts @@ -9,8 +9,7 @@ import type { BinaryTreeDeleteResult, BSTNKeyOrNode, BTNCallback, - BTNExemplar, - BTNKeyOrNode, + KeyOrNodeOrEntry, TreeMultimapNested, TreeMultimapNodeNested, TreeMultimapOptions @@ -53,9 +52,9 @@ export class TreeMultimap< > extends AVLTree implements IBinaryTree { - constructor(elements?: Iterable>, options?: Partial>) { + constructor(nodes?: Iterable>, options?: Partial>) { super([], options); - if (elements) this.addMany(elements); + if (nodes) this.addMany(nodes); } private _count = 0; @@ -89,28 +88,8 @@ export class TreeMultimap< } /** - * The function checks if an exemplar is an instance of the TreeMultimapNode class. - * @param exemplar - The `exemplar` parameter is of type `BTNExemplar`. - * @returns a boolean value indicating whether the exemplar is an instance of the TreeMultimapNode - * class. - */ - override isNode(exemplar: BTNExemplar): exemplar is N { - return exemplar instanceof TreeMultimapNode; - } - - /** - * The function "isNotNodeInstance" checks if a potential key is a K. - * @param {any} potentialKey - The potentialKey parameter is of type any, which means it can be any - * data type. - * @returns a boolean value indicating whether the potentialKey is of type number or not. - */ - override isNotNodeInstance(potentialKey: BTNKeyOrNode): potentialKey is K { - return !(potentialKey instanceof TreeMultimapNode); - } - - /** - * The function `exemplarToNode` converts an exemplar object into a node object. - * @param exemplar - The `exemplar` parameter is of type `BTNExemplar`, which means it + * The function `exemplarToNode` converts an keyOrNodeOrEntry object into a node object. + * @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter is of type `KeyOrNodeOrEntry`, which means it * can be one of the following: * @param {V} [value] - The `value` parameter is an optional argument that represents the value * associated with the node. It is of type `V`, which can be any data type. If no value is provided, @@ -119,21 +98,21 @@ export class TreeMultimap< * times the value should be added to the node. If not provided, it defaults to 1. * @returns a node of type `N` or `undefined`. */ - override exemplarToNode(exemplar: BTNExemplar, value?: V, count = 1): N | undefined { + override exemplarToNode(keyOrNodeOrEntry: KeyOrNodeOrEntry, value?: V, count = 1): N | undefined { let node: N | undefined; - if (exemplar === undefined || exemplar === null) { + if (keyOrNodeOrEntry === undefined || keyOrNodeOrEntry === null) { return; - } else if (this.isNode(exemplar)) { - node = exemplar; - } else if (this.isEntry(exemplar)) { - const [key, value] = exemplar; + } else if (this.isNode(keyOrNodeOrEntry)) { + node = keyOrNodeOrEntry; + } else if (this.isEntry(keyOrNodeOrEntry)) { + const [key, value] = keyOrNodeOrEntry; if (key === undefined || key === null) { return; } else { node = this.createNode(key, value, count); } - } else if (this.isNotNodeInstance(exemplar)) { - node = this.createNode(exemplar, value, count); + } else if (this.isNotNodeInstance(keyOrNodeOrEntry)) { + node = this.createNode(keyOrNodeOrEntry, value, count); } else { return; } @@ -141,13 +120,34 @@ export class TreeMultimap< } /** - * Time Complexity: O(log n) - logarithmic time, where "n" is the number of nodes in the tree. The add method of the superclass (AVLTree) has logarithmic time complexity. - * Space Complexity: O(1) - constant space, as it doesn't use additional data structures that scale with input size. + * The function checks if an keyOrNodeOrEntry is an instance of the TreeMultimapNode class. + * @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter is of type `KeyOrNodeOrEntry`. + * @returns a boolean value indicating whether the keyOrNodeOrEntry is an instance of the TreeMultimapNode + * class. + */ + override isNode(keyOrNodeOrEntry: KeyOrNodeOrEntry): keyOrNodeOrEntry is N { + return keyOrNodeOrEntry instanceof TreeMultimapNode; + } + + /** + * The function "isNotNodeInstance" checks if a potential key is a K. + * @param {any} potentialKey - The potentialKey parameter is of type any, which means it can be any + * data type. + * @returns a boolean value indicating whether the potentialKey is of type number or not. + */ + override isNotNodeInstance(potentialKey: KeyOrNodeOrEntry): potentialKey is K { + return !(potentialKey instanceof TreeMultimapNode); + } + + /** + * Time Complexity: O(log n) + * Space Complexity: O(1) + * logarithmic time, where "n" is the number of nodes in the tree. The add method of the superclass (AVLTree) has logarithmic time complexity. constant space, as it doesn't use additional data structures that scale with input size. */ /** - * Time Complexity: O(log n) - logarithmic time, where "n" is the number of nodes in the tree. The add method of the superclass (AVLTree) has logarithmic time complexity. - * Space Complexity: O(1) - constant space, as it doesn't use additional data structures that scale with input size. + * Time Complexity: O(log n) + * Space Complexity: O(1) * * The function overrides the add method of a binary tree node and adds a new node to the tree. * @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter can be either a key, a node, or an @@ -161,26 +161,27 @@ export class TreeMultimap< * @returns The method is returning either the newly inserted node or `undefined` if the insertion * was not successful. */ - override add(keyOrNodeOrEntry: BTNExemplar, value?: V, count = 1): N | undefined { + override add(keyOrNodeOrEntry: KeyOrNodeOrEntry, value?: V, count = 1): boolean { const newNode = this.exemplarToNode(keyOrNodeOrEntry, value, count); - if (newNode === undefined) return; + if (newNode === undefined) return false; const orgNodeCount = newNode?.count || 0; const inserted = super.add(newNode); if (inserted) { this._count += orgNodeCount; } - return inserted; + return true; } /** - * Time Complexity: O(k log n) - logarithmic time, where "n" is the number of nodes in the tree. The add method of the superclass (AVLTree) has logarithmic time complexity. - * Space Complexity: O(1) - constant space, as it doesn't use additional data structures that scale with input size. + * Time Complexity: O(k log n) + * Space Complexity: O(1) + * logarithmic time, where "n" is the number of nodes in the tree. The add method of the superclass (AVLTree) has logarithmic time complexity. constant space, as it doesn't use additional data structures that scale with input size. */ /** - * Time Complexity: O(k log n) - logarithmic time, where "n" is the number of nodes in the tree. The add method of the superclass (AVLTree) has logarithmic time complexity. - * Space Complexity: O(1) - constant space, as it doesn't use additional data structures that scale with input size. + * Time Complexity: O(k log n) + * Space Complexity: O(1) * * The function overrides the addMany method to add multiple keys, nodes, or entries to a data * structure. @@ -188,18 +189,19 @@ export class TreeMultimap< * either keys, nodes, or entries. * @returns The method is returning an array of type `N | undefined`. */ - override addMany(keysOrNodesOrEntries: Iterable>): (N | undefined)[] { + override addMany(keysOrNodesOrEntries: Iterable>): boolean[] { return super.addMany(keysOrNodesOrEntries); } /** - * Time Complexity: O(1) - constant time, as it performs basic pointer assignments. - * Space Complexity: O(1) - constant space, as it only uses a constant amount of memory. + * Time Complexity: O(n log n) + * Space Complexity: O(n) + * logarithmic time for each insertion, where "n" is the number of nodes in the tree. This is because the method calls the add method for each node. linear space, as it creates an array to store the sorted nodes. */ /** - * Time Complexity: O(n log n) - logarithmic time for each insertion, where "n" is the number of nodes in the tree. This is because the method calls the add method for each node. - * Space Complexity: O(n) - linear space, as it creates an array to store the sorted nodes. + * Time Complexity: O(n log n) + * Space Complexity: O(n) * * The `perfectlyBalance` function takes a sorted array of nodes and builds a balanced binary search * tree using either a recursive or iterative approach. @@ -247,13 +249,14 @@ export class TreeMultimap< } /** - * Time Complexity: O(k log n) - logarithmic time for each insertion, where "n" is the number of nodes in the tree, and "k" is the number of keys to be inserted. This is because the method iterates through the keys and calls the add method for each. - * Space Complexity: O(1) - constant space, as it doesn't use additional data structures that scale with input size. + * Time Complexity: O(k log n) + * Space Complexity: O(1) + * logarithmic time for each insertion, where "n" is the number of nodes in the tree, and "k" is the number of keys to be inserted. This is because the method iterates through the keys and calls the add method for each. constant space, as it doesn't use additional data structures that scale with input size. */ /** - * Time Complexity: O(log n) - logarithmic time, where "n" is the number of nodes in the tree. The delete method of the superclass (AVLTree) has logarithmic time complexity. - * Space Complexity: O(1) - constant space, as it doesn't use additional data structures that scale with input size. + * Time Complexity: O(k log n) + * Space Complexity: O(1) * * The `delete` function in TypeScript is used to remove a node from a binary tree, taking into * account the count of the node and balancing the tree if necessary. @@ -331,11 +334,14 @@ export class TreeMultimap< } /** - * Time Complexity: O(n log n) - logarithmic time for each insertion, where "n" is the number of nodes in the tree. This is because the method calls the add method for each node. - * Space Complexity: O(n) - linear space, as it creates an array to store the sorted nodes. + * Time Complexity: O(1) + * Space Complexity: O(1) */ /** + * Time Complexity: O(1) + * Space Complexity: O(1) + * * The clear() function clears the contents of a data structure and sets the count to zero. */ override clear() { diff --git a/src/interfaces/binary-tree.ts b/src/interfaces/binary-tree.ts index bf565c0..d6c9caf 100644 --- a/src/interfaces/binary-tree.ts +++ b/src/interfaces/binary-tree.ts @@ -5,7 +5,7 @@ import { BinaryTreeNodeNested, BinaryTreeOptions, BTNCallback, - BTNExemplar + KeyOrNodeOrEntry } from '../types'; export interface IBinaryTree< @@ -18,9 +18,9 @@ export interface IBinaryTree< createTree(options?: Partial>): TREE; - add(keyOrNodeOrEntry: BTNExemplar, value?: V, count?: number): N | null | undefined; + add(keyOrNodeOrEntry: KeyOrNodeOrEntry, value?: V, count?: number): boolean; - addMany(nodes: Iterable>, values?: Iterable): (N | null | undefined)[]; + addMany(nodes: Iterable>, values?: Iterable): boolean[]; delete>(identifier: ReturnType | null, callback: C): BinaryTreeDeleteResult[]; } diff --git a/src/types/common.ts b/src/types/common.ts index d7c9cf4..2b42235 100644 --- a/src/types/common.ts +++ b/src/types/common.ts @@ -54,7 +54,7 @@ export type BTNEntry = [K | null | undefined, V | undefined]; export type BTNKeyOrNode = K | null | undefined | N; -export type BTNExemplar = BTNEntry | BTNKeyOrNode; +export type KeyOrNodeOrEntry = BTNEntry | BTNKeyOrNode; export type BTNodePureKeyOrNode = K | N; diff --git a/test/performance/data-structures/binary-tree/avl-tree.test.ts b/test/performance/data-structures/binary-tree/avl-tree.test.ts index 4abbe5f..21c2608 100644 --- a/test/performance/data-structures/binary-tree/avl-tree.test.ts +++ b/test/performance/data-structures/binary-tree/avl-tree.test.ts @@ -10,27 +10,19 @@ const arr = getRandomIntArray(TEN_THOUSAND, 0, TEN_THOUSAND, true); suite .add(`${TEN_THOUSAND.toLocaleString()} add randomly`, () => { avl.clear(); - for (let i = 0; i < arr.length; i++) { - avl.add(arr[i]); - } + for (let i = 0; i < arr.length; i++) avl.add(arr[i]); }) .add(`${TEN_THOUSAND.toLocaleString()} add & delete randomly`, () => { avl.clear(); - for (let i = 0; i < arr.length; i++) { - avl.add(arr[i]); - } - for (let i = 0; i < arr.length; i++) { - avl.delete(arr[i]); - } + for (let i = 0; i < arr.length; i++) avl.add(arr[i]); + for (let i = 0; i < arr.length; i++) avl.delete(arr[i]); }) .add(`${TEN_THOUSAND.toLocaleString()} addMany`, () => { avl.clear(); avl.addMany(arr); }) .add(`${TEN_THOUSAND.toLocaleString()} get`, () => { - for (let i = 0; i < arr.length; i++) { - avl.get(arr[i]); - } + for (let i = 0; i < arr.length; i++) avl.get(arr[i]); }); export { suite }; diff --git a/test/performance/data-structures/binary-tree/binary-tree-overall.test.ts b/test/performance/data-structures/binary-tree/binary-tree-overall.test.ts new file mode 100644 index 0000000..36d89c2 --- /dev/null +++ b/test/performance/data-structures/binary-tree/binary-tree-overall.test.ts @@ -0,0 +1,37 @@ +import { AVLTree, RedBlackTree } from '../../../../src'; +import * as Benchmark from 'benchmark'; +import { getRandomIntArray, magnitude } from '../../../utils'; + +const suite = new Benchmark.Suite(); +const rbTree = new RedBlackTree(); +const avlTree = new AVLTree(); +const { TEN_THOUSAND } = magnitude; +const arr = getRandomIntArray(TEN_THOUSAND, 0, TEN_THOUSAND, true); + +suite + .add(`${TEN_THOUSAND.toLocaleString()} RBTree add`, () => { + rbTree.clear(); + for (let i = 0; i < arr.length; i++) rbTree.add(arr[i]); + }) + .add(`${TEN_THOUSAND.toLocaleString()} RBTree add & delete randomly`, () => { + rbTree.clear(); + for (let i = 0; i < arr.length; i++) rbTree.add(arr[i]); + for (let i = 0; i < arr.length; i++) rbTree.delete(arr[i]); + }) + .add(`${TEN_THOUSAND.toLocaleString()} RBTree get`, () => { + for (let i = 0; i < arr.length; i++) rbTree.get(arr[i]); + }) + .add(`${TEN_THOUSAND.toLocaleString()} AVLTree add`, () => { + avlTree.clear(); + for (let i = 0; i < arr.length; i++) avlTree.add(arr[i]); + }) + .add(`${TEN_THOUSAND.toLocaleString()} AVLTree add & delete randomly`, () => { + avlTree.clear(); + for (let i = 0; i < arr.length; i++) avlTree.add(arr[i]); + for (let i = 0; i < arr.length; i++) avlTree.delete(arr[i]); + }) + .add(`${TEN_THOUSAND.toLocaleString()} AVLTree get`, () => { + for (let i = 0; i < arr.length; i++) avlTree.get(arr[i]); + }); + +export { suite }; diff --git a/test/performance/data-structures/binary-tree/binary-tree.test.ts b/test/performance/data-structures/binary-tree/binary-tree.test.ts index b417079..5d12881 100644 --- a/test/performance/data-structures/binary-tree/binary-tree.test.ts +++ b/test/performance/data-structures/binary-tree/binary-tree.test.ts @@ -10,32 +10,22 @@ const arr = getRandomIntArray(THOUSAND, 0, THOUSAND, true); suite .add(`${THOUSAND.toLocaleString()} add randomly`, () => { biTree.clear(); - for (let i = 0; i < arr.length; i++) { - biTree.add(arr[i]); - } + for (let i = 0; i < arr.length; i++) biTree.add(arr[i]); }) .add(`${THOUSAND.toLocaleString()} add & delete randomly`, () => { biTree.clear(); - for (let i = 0; i < arr.length; i++) { - biTree.add(arr[i]); - } - for (let i = 0; i < arr.length; i++) { - biTree.delete(arr[i]); - } + for (let i = 0; i < arr.length; i++) biTree.add(arr[i]); + for (let i = 0; i < arr.length; i++) biTree.delete(arr[i]); }) .add(`${THOUSAND.toLocaleString()} addMany`, () => { biTree.clear(); biTree.addMany(arr); }) .add(`${THOUSAND.toLocaleString()} get`, () => { - for (let i = 0; i < arr.length; i++) { - biTree.get(arr[i]); - } + for (let i = 0; i < arr.length; i++) biTree.get(arr[i]); }) .add(`${THOUSAND.toLocaleString()} has`, () => { - for (let i = 0; i < arr.length; i++) { - biTree.get(arr[i]); - } + for (let i = 0; i < arr.length; i++) biTree.get(arr[i]); }) .add(`${THOUSAND.toLocaleString()} dfs`, () => { for (let i = 0; i < THOUSAND; i++) biTree.dfs(); @@ -47,4 +37,4 @@ suite for (let i = 0; i < THOUSAND; i++) biTree.morris(n => n, 'pre'); }); -export { suite }; +// export { suite }; diff --git a/test/performance/data-structures/binary-tree/bst.test.ts b/test/performance/data-structures/binary-tree/bst.test.ts index 8c156c9..a00db81 100644 --- a/test/performance/data-structures/binary-tree/bst.test.ts +++ b/test/performance/data-structures/binary-tree/bst.test.ts @@ -10,27 +10,19 @@ const arr = getRandomIntArray(TEN_THOUSAND, 0, TEN_THOUSAND, true); suite .add(`${TEN_THOUSAND.toLocaleString()} add randomly`, () => { bst.clear(); - for (let i = 0; i < arr.length; i++) { - bst.add(arr[i]); - } + for (let i = 0; i < arr.length; i++) bst.add(arr[i]); }) .add(`${TEN_THOUSAND.toLocaleString()} add & delete randomly`, () => { bst.clear(); - for (let i = 0; i < arr.length; i++) { - bst.add(arr[i]); - } - for (let i = 0; i < arr.length; i++) { - bst.delete(arr[i]); - } + for (let i = 0; i < arr.length; i++) bst.add(arr[i]); + for (let i = 0; i < arr.length; i++) bst.delete(arr[i]); }) .add(`${TEN_THOUSAND.toLocaleString()} addMany`, () => { bst.clear(); bst.addMany(arr); }) .add(`${TEN_THOUSAND.toLocaleString()} get`, () => { - for (let i = 0; i < arr.length; i++) { - bst.get(arr[i]); - } + for (let i = 0; i < arr.length; i++) bst.get(arr[i]); }); -export { suite }; +// export { suite }; diff --git a/test/performance/data-structures/binary-tree/overall.test.ts b/test/performance/data-structures/binary-tree/overall.test.ts deleted file mode 100644 index e69de29..0000000 diff --git a/test/performance/data-structures/binary-tree/rb-tree.test.ts b/test/performance/data-structures/binary-tree/rb-tree.test.ts index 681efd8..5dacb60 100644 --- a/test/performance/data-structures/binary-tree/rb-tree.test.ts +++ b/test/performance/data-structures/binary-tree/rb-tree.test.ts @@ -12,33 +12,23 @@ const cOrderedMap = new OrderedMap(); suite.add(`${HUNDRED_THOUSAND.toLocaleString()} add`, () => { rbTree.clear(); - for (let i = 0; i < arr.length; i++) { - rbTree.add(arr[i]); - } + for (let i = 0; i < arr.length; i++) rbTree.add(arr[i]); }); if (isCompetitor) { suite.add(`CPT ${HUNDRED_THOUSAND.toLocaleString()} add`, () => { - for (let i = 0; i < arr.length; i++) { - cOrderedMap.setElement(arr[i], arr[i]); - } + for (let i = 0; i < arr.length; i++) cOrderedMap.setElement(arr[i], arr[i]); }); } suite .add(`${HUNDRED_THOUSAND.toLocaleString()} add & delete randomly`, () => { rbTree.clear(); - for (let i = 0; i < arr.length; i++) { - rbTree.add(arr[i]); - } - for (let i = 0; i < arr.length; i++) { - rbTree.delete(arr[i]); - } + for (let i = 0; i < arr.length; i++) rbTree.add(arr[i]); + for (let i = 0; i < arr.length; i++) rbTree.delete(arr[i]); }) .add(`${HUNDRED_THOUSAND.toLocaleString()} getNode`, () => { - for (let i = 0; i < arr.length; i++) { - rbTree.getNode(arr[i]); - } + for (let i = 0; i < arr.length; i++) rbTree.getNode(arr[i]); }); suite.add(`${HUNDRED_THOUSAND.toLocaleString()} add & iterator`, () => { diff --git a/test/performance/data-structures/comparison/comparison.test.ts b/test/performance/data-structures/comparison/comparison.test.ts index 12a1cfd..f376515 100644 --- a/test/performance/data-structures/comparison/comparison.test.ts +++ b/test/performance/data-structures/comparison/comparison.test.ts @@ -70,75 +70,52 @@ if (isCompetitor) { for (let i = 0; i < TEN_THOUSAND; i++) pq.pop(); }) .add(`CPT OM ${HUNDRED_THOUSAND.toLocaleString()} add`, () => { - for (let i = 0; i < arrHundredThousand.length; i++) { + for (let i = 0; i < arrHundredThousand.length; i++) cOrderedMap.setElement(arrHundredThousand[i], arrHundredThousand[i]); - } }) .add(`CPT HM ${TEN_THOUSAND.toLocaleString()} set`, () => { const hm = new CHashMap(); - for (let i = 0; i < TEN_THOUSAND; i++) { - hm.setElement(i, i); - } + for (let i = 0; i < TEN_THOUSAND; i++) hm.setElement(i, i); }) .add(`CPT HM ${TEN_THOUSAND.toLocaleString()} set & get`, () => { const hm = new CHashMap(); - for (let i = 0; i < TEN_THOUSAND; i++) { - hm.setElement(i, i); - } - for (let i = 0; i < TEN_THOUSAND; i++) { - hm.getElementByKey(i); - } + for (let i = 0; i < TEN_THOUSAND; i++) hm.setElement(i, i); + for (let i = 0; i < TEN_THOUSAND; i++) hm.getElementByKey(i); }) .add(`CPT LL ${MILLION.toLocaleString()} unshift`, () => { const list = new CLinkedList(); - for (let i = 0; i < MILLION; i++) { - list.pushFront(i); - } + for (let i = 0; i < MILLION; i++) list.pushFront(i); }) .add(`CPT PQ ${TEN_THOUSAND.toLocaleString()} add & pop`, () => { const pq = new CPriorityQueue(); - for (let i = 0; i < TEN_THOUSAND; i++) { - pq.push(i); - } + for (let i = 0; i < TEN_THOUSAND; i++) pq.push(i); - for (let i = 0; i < TEN_THOUSAND; i++) { - pq.pop(); - } + for (let i = 0; i < TEN_THOUSAND; i++) pq.pop(); }) .add(`CPT DQ ${MILLION.toLocaleString()} push`, () => { const deque = new CDeque(); - for (let i = 0; i < MILLION; i++) { - deque.pushBack(i); - } + for (let i = 0; i < MILLION; i++) deque.pushBack(i); }) .add(`CPT Q ${MILLION.toLocaleString()} push`, () => { const queue = new CQueue(); - for (let i = 0; i < MILLION; i++) { - queue.push(i); - } + for (let i = 0; i < MILLION; i++) queue.push(i); }) .add(`CPT ST ${MILLION.toLocaleString()} push`, () => { const queue = new CStack(); - for (let i = 0; i < MILLION; i++) { - queue.push(i); - } + for (let i = 0; i < MILLION; i++) queue.push(i); }) .add(`CPT ST ${MILLION.toLocaleString()} push & pop`, () => { const queue = new CStack(); - for (let i = 0; i < MILLION; i++) { - queue.push(i); - } - for (let i = 0; i < MILLION; i++) { - queue.pop(); - } + for (let i = 0; i < MILLION; i++) queue.push(i); + for (let i = 0; i < MILLION; i++) queue.pop(); }); } -export { suite }; +// export { suite }; diff --git a/test/performance/data-structures/graph/directed-graph.test.ts b/test/performance/data-structures/graph/directed-graph.test.ts index 78a38d5..9fadef3 100644 --- a/test/performance/data-structures/graph/directed-graph.test.ts +++ b/test/performance/data-structures/graph/directed-graph.test.ts @@ -9,9 +9,7 @@ const vertexes = getRandomWords(THOUSAND); suite .add(`${THOUSAND.toLocaleString()} addVertex`, () => { - for (const v of vertexes) { - graph.addVertex(v); - } + for (const v of vertexes) graph.addVertex(v); }) .add(`${THOUSAND.toLocaleString()} addEdge`, () => { for (let i = 0; i < THOUSAND; i++) { @@ -21,29 +19,20 @@ suite } }) .add(`${THOUSAND.toLocaleString()} getVertex`, () => { - for (let i = 0; i < THOUSAND; i++) { - graph.getVertex(vertexes[getRandomIndex(vertexes)]); - } + for (let i = 0; i < THOUSAND; i++) graph.getVertex(vertexes[getRandomIndex(vertexes)]); }) .add(`${THOUSAND.toLocaleString()} getEdge`, () => { - for (let i = 0; i < THOUSAND; i++) { + for (let i = 0; i < THOUSAND; i++) graph.getEdge(vertexes[getRandomIndex(vertexes)], vertexes[getRandomIndex(vertexes)]); - } }) .add(`tarjan`, () => { - // for (let i = 0; i < THOUSAND; i++) { graph.tarjan(true); - // } }) .add(`tarjan all`, () => { - // for (let i = 0; i < THOUSAND; i++) { graph.tarjan(true, true, true, true); - // } }) .add(`topologicalSort`, () => { - // for (let i = 0; i < THOUSAND; i++) { graph.topologicalSort('key'); - // } }); export { suite }; diff --git a/test/performance/data-structures/hash/hash-map.test.ts b/test/performance/data-structures/hash/hash-map.test.ts index 67c605b..c37c3d2 100644 --- a/test/performance/data-structures/hash/hash-map.test.ts +++ b/test/performance/data-structures/hash/hash-map.test.ts @@ -10,18 +10,14 @@ const { MILLION } = magnitude; suite.add(`${MILLION.toLocaleString()} set`, () => { const hm = new HashMap(); - for (let i = 0; i < MILLION; i++) { - hm.set(i, i); - } + for (let i = 0; i < MILLION; i++) hm.set(i, i); }); if (isCompetitor) { suite.add(`CPT ${MILLION.toLocaleString()} set`, () => { const hm = new CHashMap(); - for (let i = 0; i < MILLION; i++) { - hm.setElement(i, i); - } + for (let i = 0; i < MILLION; i++) hm.setElement(i, i); }); } @@ -40,43 +36,30 @@ suite.add(`Native Set ${MILLION.toLocaleString()} add`, () => { suite.add(`${MILLION.toLocaleString()} set & get`, () => { const hm = new HashMap(); - for (let i = 0; i < MILLION; i++) { - hm.set(i, i); - } - for (let i = 0; i < MILLION; i++) { - hm.get(i); - } + for (let i = 0; i < MILLION; i++) hm.set(i, i); + for (let i = 0; i < MILLION; i++) hm.get(i); }); if (isCompetitor) { suite.add(`CPT ${MILLION.toLocaleString()} set & get`, () => { const hm = new CHashMap(); - for (let i = 0; i < MILLION; i++) { - hm.setElement(i, i); - } - for (let i = 0; i < MILLION; i++) { - hm.getElementByKey(i); - } + for (let i = 0; i < MILLION; i++) hm.setElement(i, i); + for (let i = 0; i < MILLION; i++) hm.getElementByKey(i); }); } suite.add(`Native Map ${MILLION.toLocaleString()} set & get`, () => { const hm = new Map(); - for (let i = 0; i < MILLION; i++) { - hm.set(i, i); - } - for (let i = 0; i < MILLION; i++) { - hm.get(i); - } + for (let i = 0; i < MILLION; i++) hm.set(i, i); + for (let i = 0; i < MILLION; i++) hm.get(i); }); suite.add(`Native Set ${MILLION.toLocaleString()} add & has`, () => { const hs = new Set(); for (let i = 0; i < MILLION; i++) hs.add(i); - for (let i = 0; i < MILLION; i++) hs.has(i); }); @@ -88,9 +71,7 @@ suite.add(`${MILLION.toLocaleString()} ObjKey set & get`, () => { objKeys.push(obj); hm.set(obj, i); } - for (let i = 0; i < MILLION; i++) { - hm.get(objKeys[i]); - } + for (let i = 0; i < MILLION; i++) hm.get(objKeys[i]); }); suite.add(`Native Map ${MILLION.toLocaleString()} ObjKey set & get`, () => { @@ -101,9 +82,7 @@ suite.add(`Native Map ${MILLION.toLocaleString()} ObjKey set & get`, () => { objs.push(obj); hm.set(obj, i); } - for (let i = 0; i < MILLION; i++) { - hm.get(objs[i]); - } + for (let i = 0; i < MILLION; i++) hm.get(objs[i]); }); suite.add(`Native Set ${MILLION.toLocaleString()} ObjKey add & has`, () => { @@ -114,9 +93,7 @@ suite.add(`Native Set ${MILLION.toLocaleString()} ObjKey add & has`, () => { objs.push(obj); hs.add(obj); } - for (let i = 0; i < MILLION; i++) { - hs.has(objs[i]); - } + for (let i = 0; i < MILLION; i++) hs.has(objs[i]); }); export { suite }; diff --git a/test/performance/data-structures/heap/heap.test.ts b/test/performance/data-structures/heap/heap.test.ts index bef5f3b..ef0632b 100644 --- a/test/performance/data-structures/heap/heap.test.ts +++ b/test/performance/data-structures/heap/heap.test.ts @@ -9,31 +9,18 @@ suite .add(`${HUNDRED_THOUSAND.toLocaleString()} add & poll`, () => { const heap = new Heap([], { comparator: (a, b) => b - a }); - for (let i = 0; i < HUNDRED_THOUSAND; i++) { - heap.add(i); - } - - for (let i = 0; i < HUNDRED_THOUSAND; i++) { - heap.poll(); - } + for (let i = 0; i < HUNDRED_THOUSAND; i++) heap.add(i); + for (let i = 0; i < HUNDRED_THOUSAND; i++) heap.poll(); }) .add(`${HUNDRED_THOUSAND.toLocaleString()} add & dfs`, () => { const heap = new Heap([], { comparator: (a, b) => b - a }); - - for (let i = 0; i < HUNDRED_THOUSAND; i++) { - heap.add(i); - } - + for (let i = 0; i < HUNDRED_THOUSAND; i++) heap.add(i); heap.dfs(); }) .add(`${TEN_THOUSAND.toLocaleString()} fib add & pop`, () => { const fbHeap = new FibonacciHeap(); - for (let i = 1; i <= TEN_THOUSAND; i++) { - fbHeap.push(i); - } - for (let i = 1; i <= TEN_THOUSAND; i++) { - fbHeap.pop(); - } + for (let i = 1; i <= TEN_THOUSAND; i++) fbHeap.push(i); + for (let i = 1; i <= TEN_THOUSAND; i++) fbHeap.pop(); }); export { suite }; diff --git a/test/performance/data-structures/linked-list/doubly-linked-list.test.ts b/test/performance/data-structures/linked-list/doubly-linked-list.test.ts index 14802c7..5e4cb94 100644 --- a/test/performance/data-structures/linked-list/doubly-linked-list.test.ts +++ b/test/performance/data-structures/linked-list/doubly-linked-list.test.ts @@ -40,7 +40,6 @@ suite const list = new DoublyLinkedList(); for (let i = 0; i < MILLION; i++) list.unshift(i); - for (let i = 0; i < MILLION; i++) list.shift(); }) .add(`${MILLION.toLocaleString()} addBefore`, () => { diff --git a/test/performance/data-structures/linked-list/singly-linked-list.test.ts b/test/performance/data-structures/linked-list/singly-linked-list.test.ts index 32518bf..1e5018f 100644 --- a/test/performance/data-structures/linked-list/singly-linked-list.test.ts +++ b/test/performance/data-structures/linked-list/singly-linked-list.test.ts @@ -10,14 +10,12 @@ suite const list = new SinglyLinkedList(); for (let i = 0; i < MILLION; i++) list.push(i); - for (let i = 0; i < MILLION; i++) list.shift(); }) .add(`${TEN_THOUSAND.toLocaleString()} push & pop`, () => { const list = new SinglyLinkedList(); for (let i = 0; i < TEN_THOUSAND; i++) list.push(i); - for (let i = 0; i < TEN_THOUSAND; i++) list.pop(); }) .add(`${TEN_THOUSAND.toLocaleString()} addBefore`, () => { diff --git a/test/performance/data-structures/matrix/matrix2d.test.ts b/test/performance/data-structures/matrix/matrix2d.test.ts deleted file mode 100644 index e69de29..0000000 diff --git a/test/performance/data-structures/matrix/vector2d.test.ts b/test/performance/data-structures/matrix/vector2d.test.ts deleted file mode 100644 index e69de29..0000000 diff --git a/test/performance/data-structures/priority-queue/max-priority-queue.test.ts b/test/performance/data-structures/priority-queue/max-priority-queue.test.ts index 3b5ec5d..68a7377 100644 --- a/test/performance/data-structures/priority-queue/max-priority-queue.test.ts +++ b/test/performance/data-structures/priority-queue/max-priority-queue.test.ts @@ -11,9 +11,7 @@ suite.add(`${TEN_THOUSAND.toLocaleString()} refill & poll`, () => { ); const maxPQ = new MaxPriorityQueue(); maxPQ.refill(nodes); - while (maxPQ.size > 0) { - maxPQ.poll(); - } + while (maxPQ.size > 0) maxPQ.poll(); }); -export { suite }; +// export { suite }; diff --git a/test/performance/data-structures/priority-queue/priority-queue.test.ts b/test/performance/data-structures/priority-queue/priority-queue.test.ts index 9b490cc..bfcd760 100644 --- a/test/performance/data-structures/priority-queue/priority-queue.test.ts +++ b/test/performance/data-structures/priority-queue/priority-queue.test.ts @@ -10,25 +10,15 @@ const { HUNDRED_THOUSAND } = magnitude; suite.add(`${HUNDRED_THOUSAND.toLocaleString()} add & poll`, () => { const pq = new PriorityQueue([], { comparator: (a, b) => b - a }); - for (let i = 0; i < HUNDRED_THOUSAND; i++) { - pq.add(i); - } - - for (let i = 0; i < HUNDRED_THOUSAND; i++) { - pq.poll(); - } + for (let i = 0; i < HUNDRED_THOUSAND; i++) pq.add(i); + for (let i = 0; i < HUNDRED_THOUSAND; i++) pq.poll(); }); if (isCompetitor) { suite.add(`CPT ${HUNDRED_THOUSAND.toLocaleString()} add & pop`, () => { const pq = new CPriorityQueue(); - for (let i = 0; i < HUNDRED_THOUSAND; i++) { - pq.push(i); - } - - for (let i = 0; i < HUNDRED_THOUSAND; i++) { - pq.pop(); - } + for (let i = 0; i < HUNDRED_THOUSAND; i++) pq.push(i); + for (let i = 0; i < HUNDRED_THOUSAND; i++) pq.pop(); }); } diff --git a/test/performance/data-structures/queue/queue.test.ts b/test/performance/data-structures/queue/queue.test.ts index 3d5f117..2347087 100644 --- a/test/performance/data-structures/queue/queue.test.ts +++ b/test/performance/data-structures/queue/queue.test.ts @@ -10,50 +10,33 @@ const { MILLION, HUNDRED_THOUSAND } = magnitude; suite.add(`${MILLION.toLocaleString()} push`, () => { const queue = new Queue(); - for (let i = 0; i < MILLION; i++) { - queue.push(i); - } + for (let i = 0; i < MILLION; i++) queue.push(i); }); if (isCompetitor) { suite.add(`CPT ${MILLION.toLocaleString()} push`, () => { const queue = new CQueue(); - for (let i = 0; i < MILLION; i++) { - queue.push(i); - } + for (let i = 0; i < MILLION; i++) queue.push(i); }); } suite.add(`${HUNDRED_THOUSAND.toLocaleString()} push & shift`, () => { const queue = new Queue(); - for (let i = 0; i < HUNDRED_THOUSAND; i++) { - queue.push(i); - } - for (let i = 0; i < HUNDRED_THOUSAND; i++) { - queue.shift(); - } + for (let i = 0; i < HUNDRED_THOUSAND; i++) queue.push(i); + for (let i = 0; i < HUNDRED_THOUSAND; i++) queue.shift(); }); suite .add(`Native Array ${HUNDRED_THOUSAND.toLocaleString()} push & shift`, () => { const arr = new Array(); - for (let i = 0; i < HUNDRED_THOUSAND; i++) { - arr.push(i); - } - for (let i = 0; i < HUNDRED_THOUSAND; i++) { - arr.shift(); - } + for (let i = 0; i < HUNDRED_THOUSAND; i++) arr.push(i); + for (let i = 0; i < HUNDRED_THOUSAND; i++) arr.shift(); }) .add(`Native Array ${HUNDRED_THOUSAND.toLocaleString()} push & pop`, () => { const arr = new Array(); - for (let i = 0; i < HUNDRED_THOUSAND; i++) { - arr.push(i); - } - - for (let i = 0; i < HUNDRED_THOUSAND; i++) { - arr.pop(); - } + for (let i = 0; i < HUNDRED_THOUSAND; i++) arr.push(i); + for (let i = 0; i < HUNDRED_THOUSAND; i++) arr.pop(); }); export { suite }; diff --git a/test/performance/data-structures/stack/stack.test.ts b/test/performance/data-structures/stack/stack.test.ts index 186d6c8..6096ef9 100644 --- a/test/performance/data-structures/stack/stack.test.ts +++ b/test/performance/data-structures/stack/stack.test.ts @@ -10,39 +10,27 @@ const { MILLION } = magnitude; suite.add(`${MILLION.toLocaleString()} push`, () => { const stack = new Stack(); - for (let i = 0; i < MILLION; i++) { - stack.push(i); - } + for (let i = 0; i < MILLION; i++) stack.push(i); }); if (isCompetitor) { suite.add(`CPT ${MILLION.toLocaleString()} push`, () => { const queue = new CStack(); - for (let i = 0; i < MILLION; i++) { - queue.push(i); - } + for (let i = 0; i < MILLION; i++) queue.push(i); }); } suite.add(`${MILLION.toLocaleString()} push & pop`, () => { const queue = new Stack(); - for (let i = 0; i < MILLION; i++) { - queue.push(i); - } - for (let i = 0; i < MILLION; i++) { - queue.pop(); - } + for (let i = 0; i < MILLION; i++) queue.push(i); + for (let i = 0; i < MILLION; i++) queue.pop(); }); if (isCompetitor) { suite.add(`CPT ${MILLION.toLocaleString()} push & pop`, () => { const queue = new CStack(); - for (let i = 0; i < MILLION; i++) { - queue.push(i); - } - for (let i = 0; i < MILLION; i++) { - queue.pop(); - } + for (let i = 0; i < MILLION; i++) queue.push(i); + for (let i = 0; i < MILLION; i++) queue.pop(); }); } diff --git a/test/performance/data-structures/trie/trie.test.ts b/test/performance/data-structures/trie/trie.test.ts index 0f39402..7ff1f74 100644 --- a/test/performance/data-structures/trie/trie.test.ts +++ b/test/performance/data-structures/trie/trie.test.ts @@ -9,14 +9,10 @@ const randomWords = getRandomWords(HUNDRED_THOUSAND, false); suite .add(`${HUNDRED_THOUSAND.toLocaleString()} push`, () => { - for (let i = 0; i < randomWords.length; i++) { - trie.add(randomWords[i]); - } + for (let i = 0; i < randomWords.length; i++) trie.add(randomWords[i]); }) .add(`${HUNDRED_THOUSAND.toLocaleString()} getWords`, () => { - for (let i = 0; i < randomWords.length; i++) { - trie.getWords(randomWords[i]); - } + for (let i = 0; i < randomWords.length; i++) trie.getWords(randomWords[i]); }); export { suite }; diff --git a/test/unit/data-structures/binary-tree/binary-tree.test.ts b/test/unit/data-structures/binary-tree/binary-tree.test.ts index 895b8c8..e56ad69 100644 --- a/test/unit/data-structures/binary-tree/binary-tree.test.ts +++ b/test/unit/data-structures/binary-tree/binary-tree.test.ts @@ -106,7 +106,8 @@ describe('BinaryTree', () => { it('should delete nodes', () => { expect(tree.getHeight(tree.root, IterationType.ITERATIVE)).toBe(-1); expect(tree.getMinHeight()).toBe(-1); - const node1 = tree.add(1); + const node1 = tree.createNode(1); + tree.add(node1); expect(tree.size).toBe(1); const leftChild = new BinaryTreeNode(2);