From 02d71a23ba61fba1eb655372cb3c487c11136410 Mon Sep 17 00:00:00 2001 From: Revone Date: Fri, 26 Jan 2024 18:20:15 +0800 Subject: [PATCH] Refactor: All binary tree data structures now support the toEntryFn for extracting key and value from raw data at once, avoiding users from having to traverse data multiple times, thus improving performance. Chore: Explicitly use the override keyword. --- README.md | 26 +- .../binary-tree/avl-tree-multi-map.ts | 238 +++-- src/data-structures/binary-tree/avl-tree.ts | 160 +-- .../binary-tree/binary-tree.ts | 926 ++++++++++-------- src/data-structures/binary-tree/bst.ts | 513 +++++----- src/data-structures/binary-tree/rb-tree.ts | 221 +++-- .../binary-tree/tree-multi-map.ts | 228 +++-- src/data-structures/graph/abstract-graph.ts | 20 +- src/data-structures/hash/hash-map.ts | 91 +- src/data-structures/queue/deque.ts | 4 +- src/data-structures/queue/queue.ts | 2 +- src/data-structures/trie/trie.ts | 4 +- src/interfaces/binary-tree.ts | 15 +- src/types/common.ts | 3 +- .../binary-tree/avl-tree-multi-map.ts | 4 +- .../data-structures/binary-tree/avl-tree.ts | 4 +- .../binary-tree/binary-tree.ts | 9 +- src/types/data-structures/binary-tree/bst.ts | 8 +- .../data-structures/binary-tree/rb-tree.ts | 4 +- .../binary-tree/tree-multi-map.ts | 6 +- src/utils/utils.ts | 6 +- test/integration/index.html | 36 +- .../binary-tree/avl-tree-multi-map.test.ts | 68 ++ .../binary-tree/binary-tree.test.ts | 56 ++ .../graph/directed-graph.test.ts | 4 +- test/utils/big-o.ts | 18 +- tsconfig-base.json | 1 + 27 files changed, 1526 insertions(+), 1149 deletions(-) diff --git a/README.md b/README.md index 5b46716..c6aeb2b 100644 --- a/README.md +++ b/README.md @@ -736,43 +736,43 @@ Version 11.7.9 [//]: # (No deletion!!! Start of Replace Section)
heap
-
test nametime taken (ms)executions per secsample deviation
100,000 add6.34157.781.90e-4
100,000 add & poll31.3931.868.18e-4
+
test nametime taken (ms)executions per secsample deviation
100,000 add6.38156.712.05e-4
100,000 add & poll31.5331.718.78e-4
rb-tree
-
test nametime taken (ms)executions per secsample deviation
100,000 add59.6416.770.00
100,000 add randomly73.6713.570.00
100,000 get89.9111.120.00
100,000 iterator26.0838.340.00
100,000 add & delete orderly145.446.880.00
100,000 add & delete randomly204.814.880.00
+
test nametime taken (ms)executions per secsample deviation
100,000 add58.6817.049.39e-4
100,000 add randomly75.4913.250.00
100,000 get90.4811.050.00
100,000 iterator29.7133.660.01
100,000 add & delete orderly122.028.200.00
100,000 add & delete randomly214.394.660.02
queue
-
test nametime taken (ms)executions per secsample deviation
1,000,000 push40.8424.480.00
100,000 push & shift4.83207.165.59e-4
Native JS Array 100,000 push & shift2376.780.420.34
+
test nametime taken (ms)executions per secsample deviation
1,000,000 push42.6723.440.01
100,000 push & shift4.92203.057.10e-4
Native JS Array 100,000 push & shift2380.400.420.24
deque
-
test nametime taken (ms)executions per secsample deviation
1,000,000 push24.7340.440.00
1,000,000 push & pop30.0833.240.00
1,000,000 push & shift30.5332.750.00
100,000 push & shift3.19313.763.01e-4
Native JS Array 100,000 push & shift2184.780.460.19
100,000 unshift & shift2.94339.723.66e-4
Native JS Array 100,000 unshift & shift4196.690.240.37
+
test nametime taken (ms)executions per secsample deviation
1,000,000 push24.9740.040.00
1,000,000 push & pop30.7532.520.00
1,000,000 push & shift30.6032.670.00
100,000 push & shift3.22310.212.47e-4
Native JS Array 100,000 push & shift2153.500.460.13
100,000 unshift & shift2.89345.712.85e-4
Native JS Array 100,000 unshift & shift4177.840.240.28
hash-map
-
test nametime taken (ms)executions per secsample deviation
1,000,000 set117.778.490.03
Native JS Map 1,000,000 set200.534.990.00
Native JS Set 1,000,000 add172.755.790.03
1,000,000 set & get117.618.500.02
Native JS Map 1,000,000 set & get265.243.770.01
Native JS Set 1,000,000 add & has168.615.930.01
1,000,000 ObjKey set & get325.913.070.04
Native JS Map 1,000,000 ObjKey set & get301.513.320.03
Native JS Set 1,000,000 ObjKey add & has274.473.640.04
+
test nametime taken (ms)executions per secsample deviation
1,000,000 set116.958.550.03
Native JS Map 1,000,000 set206.874.830.01
Native JS Set 1,000,000 add167.655.960.01
1,000,000 set & get122.708.150.03
Native JS Map 1,000,000 set & get263.263.800.01
Native JS Set 1,000,000 add & has167.725.960.01
1,000,000 ObjKey set & get320.173.120.03
Native JS Map 1,000,000 ObjKey set & get292.053.420.02
Native JS Set 1,000,000 ObjKey add & has267.273.740.02
trie
-
test nametime taken (ms)executions per secsample deviation
100,000 push42.9323.298.30e-4
100,000 getWords82.1412.170.00
+
test nametime taken (ms)executions per secsample deviation
100,000 push43.9322.765.85e-4
100,000 getWords83.4211.990.00
avl-tree
-
test nametime taken (ms)executions per secsample deviation
100,000 add231.624.320.00
100,000 add randomly304.233.290.00
100,000 get113.938.780.00
100,000 iterator30.3732.920.00
100,000 add & delete orderly395.022.530.02
100,000 add & delete randomly542.161.840.00
+
test nametime taken (ms)executions per secsample deviation
100,000 add232.604.300.00
100,000 add randomly306.923.260.00
100,000 get113.288.830.00
100,000 iterator33.2030.120.01
100,000 add & delete orderly399.102.510.00
100,000 add & delete randomly551.571.810.00
binary-tree-overall
-
test nametime taken (ms)executions per secsample deviation
10,000 RBTree add randomly6.02166.109.19e-5
10,000 RBTree get randomly7.96125.617.80e-5
10,000 RBTree add & delete randomly16.6660.021.52e-4
10,000 AVLTree add randomly21.6446.211.93e-4
10,000 AVLTree get randomly8.40119.091.34e-4
10,000 AVLTree add & delete randomly40.8424.492.56e-4
+
test nametime taken (ms)executions per secsample deviation
10,000 RBTree add randomly6.24160.311.80e-4
10,000 RBTree get randomly7.93126.098.91e-5
10,000 RBTree add & delete randomly17.0558.651.66e-4
10,000 AVLTree add randomly21.9045.662.09e-4
10,000 AVLTree get randomly8.68115.150.00
10,000 AVLTree add & delete randomly41.6624.006.11e-4
directed-graph
-
test nametime taken (ms)executions per secsample deviation
1,000 addVertex0.109892.748.38e-7
1,000 addEdge6.07164.741.70e-4
1,000 getVertex0.052.13e+42.16e-6
1,000 getEdge38.6625.870.02
tarjan208.114.810.01
topologicalSort184.455.420.02
+
test nametime taken (ms)executions per secsample deviation
1,000 addVertex0.109614.917.24e-6
1,000 addEdge6.68149.815.43e-4
1,000 getVertex0.052.18e+43.02e-7
1,000 getEdge21.4646.600.00
tarjan204.994.880.03
topologicalSort166.176.020.00
doubly-linked-list
-
test nametime taken (ms)executions per secsample deviation
1,000,000 push218.494.580.04
1,000,000 unshift213.524.680.06
1,000,000 unshift & shift155.826.420.02
1,000,000 addBefore325.793.070.08
+
test nametime taken (ms)executions per secsample deviation
1,000,000 push217.484.600.04
1,000,000 unshift221.644.510.02
1,000,000 unshift & shift175.585.700.03
1,000,000 addBefore311.893.210.04
singly-linked-list
-
test nametime taken (ms)executions per secsample deviation
1,000,000 push & shift191.945.210.04
10,000 push & pop214.824.660.01
10,000 addBefore247.534.040.00
+
test nametime taken (ms)executions per secsample deviation
1,000,000 push & shift211.024.740.04
10,000 push & pop216.294.620.01
10,000 addBefore248.754.020.01
priority-queue
-
test nametime taken (ms)executions per secsample deviation
100,000 add26.6337.561.30e-4
100,000 add & poll76.8213.020.00
+
test nametime taken (ms)executions per secsample deviation
100,000 add27.5336.320.00
100,000 add & poll76.9513.000.00
stack
-
test nametime taken (ms)executions per secsample deviation
1,000,000 push38.5825.920.00
1,000,000 push & pop46.0621.710.00
+
test nametime taken (ms)executions per secsample deviation
1,000,000 push39.3925.390.01
1,000,000 push & pop47.7220.960.01
[//]: # (No deletion!!! End of Replace Section) diff --git a/src/data-structures/binary-tree/avl-tree-multi-map.ts b/src/data-structures/binary-tree/avl-tree-multi-map.ts index 1fcb512..e90f4a1 100644 --- a/src/data-structures/binary-tree/avl-tree-multi-map.ts +++ b/src/data-structures/binary-tree/avl-tree-multi-map.ts @@ -16,6 +16,7 @@ import type { IterationType, KeyOrNodeOrEntry } from '../../types'; +import { BTNEntry } from '../../types'; import { IBinaryTree } from '../../interfaces'; import { AVLTree, AVLTreeNode } from './avl-tree'; @@ -65,19 +66,36 @@ export class AVLTreeMultiMapNode< export class AVLTreeMultiMap< K extends Comparable, V = any, + R = BTNEntry, NODE extends AVLTreeMultiMapNode = AVLTreeMultiMapNode>, - TREE extends AVLTreeMultiMap = AVLTreeMultiMap> + TREE extends AVLTreeMultiMap = AVLTreeMultiMap< + K, + V, + R, + NODE, + AVLTreeMultiMapNested + > > - extends AVLTree - implements IBinaryTree { - constructor(keysOrNodesOrEntries: Iterable> = [], options?: AVLTreeMultiMapOptions) { + extends AVLTree + implements IBinaryTree { + /** + * The constructor initializes a new AVLTreeMultiMap object with optional initial elements. + * @param keysOrNodesOrEntriesOrRawElements - The `keysOrNodesOrEntriesOrRawElements` parameter is an + * iterable object that can contain either keys, nodes, entries, or raw elements. + * @param [options] - The `options` parameter is an optional object that can be used to customize the + * behavior of the AVLTreeMultiMap. It can include properties such as `compareKeys` and + * `compareValues` functions to define custom comparison logic for keys and values, respectively. + */ + constructor( + keysOrNodesOrEntriesOrRawElements: Iterable> = [], + options?: AVLTreeMultiMapOptions + ) { super([], options); - if (keysOrNodesOrEntries) this.addMany(keysOrNodesOrEntries); + if (keysOrNodesOrEntriesOrRawElements) this.addMany(keysOrNodesOrEntriesOrRawElements); } protected _count = 0; - // TODO the _count is not accurate after nodes count modified /** * The function calculates the sum of the count property of all nodes in a tree using depth-first * search. @@ -107,20 +125,29 @@ export class AVLTreeMultiMap< } /** - * The function creates a new BSTNode with the given key, value, and count. - * @param {K} key - The key parameter is the unique identifier for the binary tree node. It is used to - * distinguish one node from another in the tree. - * @param {NODE} value - The `value` parameter represents the value that will be stored in the binary search tree node. - * @param {number} [count] - The "count" parameter is an optional parameter of type number. It represents the number of - * occurrences of the value in the binary search tree node. If not provided, the count will default to 1. - * @returns A new instance of the BSTNode class with the specified key, value, and count (if provided). + * The function creates a new AVLTreeMultiMapNode with the specified key, value, and count. + * @param {K} key - The key parameter represents the key of the node being created. It is of type K, + * which is a generic type that can be replaced with any specific type when using the function. + * @param {V} [value] - The `value` parameter is an optional parameter that represents the value + * associated with the key in the node. It is of type `V`, which can be any data type. + * @param {number} [count] - The `count` parameter represents the number of occurrences of a + * key-value pair in the AVLTreeMultiMapNode. It is an optional parameter, so it can be omitted when + * calling the `createNode` method. If provided, it specifies the initial count for the node. + * @returns a new instance of the AVLTreeMultiMapNode class, casted as NODE. */ override createNode(key: K, value?: V, count?: number): NODE { return new AVLTreeMultiMapNode(key, value, count) as NODE; } - override createTree(options?: AVLTreeMultiMapOptions): TREE { - return new AVLTreeMultiMap([], { + /** + * The function creates a new AVLTreeMultiMap object with the specified options and returns it. + * @param [options] - The `options` parameter is an optional object that contains additional + * configuration options for creating the AVLTreeMultiMap. It can have the following properties: + * @returns a new instance of the AVLTreeMultiMap class, with the specified options, as a TREE + * object. + */ + override createTree(options?: AVLTreeMultiMapOptions): TREE { + return new AVLTreeMultiMap([], { iterationType: this.iterationType, comparator: this.comparator, ...options @@ -128,49 +155,52 @@ export class AVLTreeMultiMap< } /** - * The function `keyValueOrEntryToNode` 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, - * it defaults to `undefined`. - * @param [count=1] - The `count` parameter is an optional parameter that specifies the number of - * times the value should be added to the node. If not provided, it defaults to 1. - * @returns a node of type `NODE` or `undefined`. + * The function checks if the input is an instance of AVLTreeMultiMapNode. + * @param {R | KeyOrNodeOrEntry} keyOrNodeOrEntryOrRawElement - The parameter + * `keyOrNodeOrEntryOrRawElement` can be of type `R` or `KeyOrNodeOrEntry`. + * @returns a boolean value indicating whether the input parameter `keyOrNodeOrEntryOrRawElement` is + * an instance of the `AVLTreeMultiMapNode` class. */ - override keyValueOrEntryToNode( - keyOrNodeOrEntry: KeyOrNodeOrEntry, - value?: V, - count = 1 - ): NODE | undefined { - let node: NODE | undefined; - if (keyOrNodeOrEntry === undefined || keyOrNodeOrEntry === null) { - 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, count); - } - } else if (!this.isNode(keyOrNodeOrEntry)) { - node = this.createNode(keyOrNodeOrEntry, value, count); - } else { - return; - } - return node; + override isNode( + keyOrNodeOrEntryOrRawElement: R | KeyOrNodeOrEntry + ): keyOrNodeOrEntryOrRawElement is NODE { + return keyOrNodeOrEntryOrRawElement instanceof AVLTreeMultiMapNode; } /** - * The function checks if an keyOrNodeOrEntry is an instance of the AVLTreeMultiMapNode class. - * @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter is of type `KeyOrNodeOrEntry`. - * @returns a boolean value indicating whether the keyOrNodeOrEntry is an instance of the AVLTreeMultiMapNode - * class. + * The function `keyValueOrEntryOrRawElementToNode` converts a key, value, entry, or raw element into + * a node object. + * @param {R | KeyOrNodeOrEntry} keyOrNodeOrEntryOrRawElement - The + * `keyOrNodeOrEntryOrRawElement` parameter can be of type `R` or `KeyOrNodeOrEntry`. + * @param {V} [value] - The `value` parameter is an optional value that can be passed to the + * `override` function. It represents the value associated with the key in the data structure. If no + * value is provided, it will default to `undefined`. + * @param [count=1] - The `count` parameter is an optional parameter that specifies the number of + * times the key-value pair should be added to the data structure. If not provided, it defaults to 1. + * @returns either a NODE object or undefined. */ - override isNode(keyOrNodeOrEntry: KeyOrNodeOrEntry): keyOrNodeOrEntry is NODE { - return keyOrNodeOrEntry instanceof AVLTreeMultiMapNode; + override keyValueOrEntryOrRawElementToNode( + keyOrNodeOrEntryOrRawElement: R | KeyOrNodeOrEntry, + value?: V, + count = 1 + ): NODE | undefined { + if (keyOrNodeOrEntryOrRawElement === undefined || keyOrNodeOrEntryOrRawElement === null) return; + if (this.isNode(keyOrNodeOrEntryOrRawElement)) return keyOrNodeOrEntryOrRawElement; + + if (this.toEntryFn) { + const [key, entryValue] = this.toEntryFn(keyOrNodeOrEntryOrRawElement as R); + if (key) return this.createNode(key, entryValue ?? value, count); + } + + if (this.isEntry(keyOrNodeOrEntryOrRawElement)) { + const [key, value] = keyOrNodeOrEntryOrRawElement; + if (key === undefined || key === null) return; + else return this.createNode(key, value, count); + } + + if (this.isKey(keyOrNodeOrEntryOrRawElement)) return this.createNode(keyOrNodeOrEntryOrRawElement, value, count); + + return; } /** @@ -182,20 +212,21 @@ export class AVLTreeMultiMap< * 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 - * entry. It represents the key, node, or entry that you want to add to the binary tree. + * The function overrides the add method of a TypeScript class to add a new node to a data structure + * and update the count. + * @param {R | KeyOrNodeOrEntry} keyOrNodeOrEntryOrRawElement - The + * `keyOrNodeOrEntryOrRawElement` parameter can accept a value of type `R`, which can be any type. It + * can also accept a value of type `KeyOrNodeOrEntry`, which represents a key, node, + * entry, or raw element * @param {V} [value] - The `value` parameter represents the value associated with the key in the - * binary tree node. It is an optional parameter, meaning it can be omitted when calling the `add` - * method. + * data structure. It is an optional parameter, so it can be omitted if not needed. * @param [count=1] - The `count` parameter represents the number of times the key-value pair should - * be added to the binary tree. By default, it is set to 1, meaning that the key-value pair will be - * added once. However, you can specify a different value for `count` if you want to add - * @returns The method is returning either the newly inserted node or `undefined` if the insertion - * was not successful. + * be added to the data structure. By default, it is set to 1, meaning that the key-value pair will + * be added once. However, you can specify a different value for `count` if you want to add + * @returns a boolean value. */ - override add(keyOrNodeOrEntry: KeyOrNodeOrEntry, value?: V, count = 1): boolean { - const newNode = this.keyValueOrEntryToNode(keyOrNodeOrEntry, value, count); + override add(keyOrNodeOrEntryOrRawElement: R | KeyOrNodeOrEntry, value?: V, count = 1): boolean { + const newNode = this.keyValueOrEntryOrRawElementToNode(keyOrNodeOrEntryOrRawElement, value, count); if (newNode === undefined) return false; const orgNodeCount = newNode?.count || 0; @@ -215,19 +246,19 @@ export class AVLTreeMultiMap< * Time Complexity: O(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. - * @param identifier - The identifier is the value or key that is used to identify the node that - * needs to be deleted from the binary tree. It can be of any type that is returned by the callback + * The `delete` function in a binary tree data structure deletes a node based on its identifier and + * returns the deleted node along with the parent node that needs to be balanced. + * @param identifier - The identifier parameter is the value used to identify the node that needs to + * be deleted from the binary tree. It can be of any type and is the return type of the callback * function. - * @param {C} callback - The `callback` parameter is a function that is used to determine if a node - * should be deleted. It is optional and defaults to a default callback function. The `callback` - * function takes one parameter, which is the identifier of the node, and returns a value that is - * used to identify the node to + * @param {C} callback - The `callback` parameter is a function that is used to determine the + * equality of nodes in the binary tree. It is optional and has a default value of + * `this._DEFAULT_CALLBACK`. The `callback` function takes a single argument, which is the identifier + * of a node, and returns a value that * @param [ignoreCount=false] - A boolean flag indicating whether to ignore the count of the node * being deleted. If set to true, the count of the node will not be considered and the node will be - * deleted regardless of its count. If set to false (default), the count of the node will be - * decremented by 1 and + * deleted regardless of its count. If set to false (default), the count of the node will be taken + * into account and the node * @returns an array of `BinaryTreeDeleteResult`. */ override delete>( @@ -300,7 +331,8 @@ export class AVLTreeMultiMap< * Time Complexity: O(1) * Space Complexity: O(1) * - * The clear() function clears the contents of a data structure and sets the count to zero. + * The "clear" function overrides the parent class's "clear" function and also resets the count to + * zero. */ override clear() { super.clear(); @@ -315,13 +347,14 @@ export class AVLTreeMultiMap< /** * Time Complexity: O(n log n) * Space Complexity: O(log n) - * * The `perfectlyBalance` function takes a sorted array of nodes and builds a balanced binary search * tree using either a recursive or iterative approach. - * @param iterationType - The `iterationType` parameter is an optional parameter that specifies the - * type of iteration to use when building the balanced binary search tree. It can have two possible - * values: - * @returns a boolean value. + * @param {IterationType} iterationType - The `iterationType` parameter is an optional parameter that + * specifies the type of iteration to use when building the balanced binary search tree. It has a + * default value of `this.iterationType`, which means it will use the iteration type currently set in + * the object. + * @returns The function `perfectlyBalance` returns a boolean value. It returns `true` if the + * balancing operation is successful, and `false` if there are no nodes to balance. */ override perfectlyBalance(iterationType: IterationType = this.iterationType): boolean { const sorted = this.dfs(node => node, 'IN'), @@ -370,7 +403,7 @@ export class AVLTreeMultiMap< * Time complexity: O(n) * Space complexity: O(n) * - * The `clone` function creates a deep copy of a tree object. + * The function overrides the clone method to create a deep copy of a tree object. * @returns The `clone()` method is returning a cloned instance of the `TREE` object. */ override clone(): TREE { @@ -380,17 +413,26 @@ export class AVLTreeMultiMap< } /** - * The `_swapProperties` function swaps the key, value, count, and height properties between two nodes. - * @param {K | NODE | undefined} srcNode - The `srcNode` parameter represents the source node from - * which the values will be swapped. It can be of type `K`, `NODE`, or `undefined`. - * @param {K | NODE | undefined} destNode - The `destNode` parameter represents the destination - * node where the values from the source node will be swapped to. - * @returns either the `destNode` object if both `srcNode` and `destNode` are defined, or `undefined` - * if either `srcNode` or `destNode` is undefined. + * Time Complexity: O(1) + * Space Complexity: O(1) + */ + + /** + * Time Complexity: O(1) + * Space Complexity: O(1) + * + * The `_swapProperties` function swaps the properties (key, value, count, height) between two nodes + * in a binary search tree. + * @param {R | BSTNKeyOrNode} srcNode - The `srcNode` parameter represents the source node + * that will be swapped with the `destNode`. + * @param {R | BSTNKeyOrNode} destNode - The `destNode` parameter represents the destination + * node where the properties will be swapped with the source node. + * @returns The method is returning the `destNode` after swapping its properties with the `srcNode`. + * If either `srcNode` or `destNode` is undefined, it returns `undefined`. */ protected override _swapProperties( - srcNode: BSTNKeyOrNode, - destNode: BSTNKeyOrNode + srcNode: R | BSTNKeyOrNode, + destNode: R | BSTNKeyOrNode ): NODE | undefined { srcNode = this.ensureNode(srcNode); destNode = this.ensureNode(destNode); @@ -417,12 +459,20 @@ export class AVLTreeMultiMap< } /** + * Time Complexity: O(1) + * Space Complexity: O(1) + */ + + /** + * Time Complexity: O(1) + * Space Complexity: O(1) + * * The function replaces an old node with a new node and updates the count property of the new node. - * @param {NODE} oldNode - The `oldNode` parameter is of type `NODE` and represents the node that - * needs to be replaced in a data structure. - * @param {NODE} newNode - The `newNode` parameter is an object of type `NODE`. + * @param {NODE} oldNode - The oldNode parameter represents the node that needs to be replaced in the + * data structure. It is of type NODE. + * @param {NODE} newNode - The `newNode` parameter is an instance of the `NODE` class. * @returns The method is returning the result of calling the `_replaceNode` method from the - * superclass, after updating the `count` property of the `newNode` object. + * superclass, which is of type `NODE`. */ protected override _replaceNode(oldNode: NODE, newNode: NODE): NODE { newNode.count = oldNode.count + newNode.count; diff --git a/src/data-structures/binary-tree/avl-tree.ts b/src/data-structures/binary-tree/avl-tree.ts index 5568e48..8a9d812 100644 --- a/src/data-structures/binary-tree/avl-tree.ts +++ b/src/data-structures/binary-tree/avl-tree.ts @@ -16,6 +16,7 @@ import type { Comparable, KeyOrNodeOrEntry } from '../../types'; +import { BTNEntry } from '../../types'; import { IBinaryTree } from '../../interfaces'; export class AVLTreeNode< @@ -68,33 +69,39 @@ export class AVLTreeNode< export class AVLTree< K extends Comparable, V = any, + R = BTNEntry, NODE extends AVLTreeNode = AVLTreeNode>, - TREE extends AVLTree = AVLTree> + TREE extends AVLTree = AVLTree> > - extends BST - implements IBinaryTree { + extends BST + implements IBinaryTree { /** - * The constructor function initializes an AVLTree object with optional keysOrNodesOrEntries and options. - * @param [keysOrNodesOrEntries] - The `keysOrNodesOrEntries` 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. + * This is a constructor function for an AVLTree class that initializes the tree with keys, nodes, + * entries, or raw elements. + * @param keysOrNodesOrEntriesOrRawElements - The `keysOrNodesOrEntriesOrRawElements` parameter is an + * iterable object that can contain either keys, nodes, entries, or raw elements. These elements will + * be used to initialize the AVLTree. + * @param [options] - The `options` parameter is an optional object that can be used to customize the + * behavior of the AVLTree. It can include properties such as `compareFn` (a function used to compare + * keys), `allowDuplicates` (a boolean indicating whether duplicate keys are allowed), and + * `nodeBuilder` ( */ - constructor(keysOrNodesOrEntries: Iterable> = [], options?: AVLTreeOptions) { + constructor( + keysOrNodesOrEntriesOrRawElements: Iterable> = [], + options?: AVLTreeOptions + ) { super([], options); - if (keysOrNodesOrEntries) super.addMany(keysOrNodesOrEntries); + if (keysOrNodesOrEntriesOrRawElements) super.addMany(keysOrNodesOrEntriesOrRawElements); } /** - * The function creates a new AVL tree node with the specified key and value. - * @param {K} key - The key parameter is the key value that will be associated with - * the new node. It is used to determine the position of the node in the binary search tree. - * @param [value] - The parameter `value` is an optional value that can be assigned to the node. It is of - * type `V`, which means it can be any value that is assignable to the `value` property of the - * node type `NODE`. - * @returns a new AVLTreeNode object with the specified key and value. + * The function creates a new AVL tree node with the given key and value. + * @param {K} key - The key parameter is of type K, which represents the key of the node being + * created. + * @param {V} [value] - The "value" parameter is an optional parameter of type V. It represents the + * value associated with the key in the node being created. + * @returns The method is returning a new instance of the AVLTreeNode class, casted as the generic + * type NODE. */ override createNode(key: K, value?: V): NODE { return new AVLTreeNode(key, value) as NODE; @@ -107,8 +114,8 @@ export class AVLTree< * being created. * @returns a new AVLTree object. */ - override createTree(options?: AVLTreeOptions): TREE { - return new AVLTree([], { + override createTree(options?: AVLTreeOptions): TREE { + return new AVLTree([], { iterationType: this.iterationType, comparator: this.comparator, ...options @@ -116,12 +123,16 @@ export class AVLTree< } /** - * 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. + * The function checks if the input is an instance of AVLTreeNode. + * @param {R | KeyOrNodeOrEntry} keyOrNodeOrEntryOrRawElement - The parameter + * `keyOrNodeOrEntryOrRawElement` can be of type `R` or `KeyOrNodeOrEntry`. + * @returns a boolean value indicating whether the input parameter `keyOrNodeOrEntryOrRawElement` is + * an instance of the `AVLTreeNode` class. */ - override isNode(keyOrNodeOrEntry: KeyOrNodeOrEntry): keyOrNodeOrEntry is NODE { - return keyOrNodeOrEntry instanceof AVLTreeNode; + override isNode( + keyOrNodeOrEntryOrRawElement: R | KeyOrNodeOrEntry + ): keyOrNodeOrEntryOrRawElement is NODE { + return keyOrNodeOrEntryOrRawElement instanceof AVLTreeNode; } /** @@ -134,18 +145,19 @@ export class AVLTree< * 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. - * @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter can be either a key, a node, or an - * entry. - * @param {V} [value] - The `value` parameter represents the value associated with the key that is - * being added to the binary tree. - * @returns The method is returning either the inserted node or undefined. + * The function overrides the add method of a class and inserts a key-value pair into a data + * structure, then balances the path. + * @param {R | KeyOrNodeOrEntry} keyOrNodeOrEntryOrRawElement - The parameter + * `keyOrNodeOrEntryOrRawElement` can accept values of type `R`, `KeyOrNodeOrEntry`, or + * `RawElement`. + * @param {V} [value] - The `value` parameter is an optional value that you want to associate with + * the key or node being added to the data structure. + * @returns The method is returning a boolean value. */ - override add(keyOrNodeOrEntry: KeyOrNodeOrEntry, value?: V): boolean { - if (keyOrNodeOrEntry === null) return false; - const inserted = super.add(keyOrNodeOrEntry, value); - if (inserted) this._balancePath(keyOrNodeOrEntry); + override add(keyOrNodeOrEntryOrRawElement: R | KeyOrNodeOrEntry, value?: V): boolean { + if (keyOrNodeOrEntryOrRawElement === null) return false; + const inserted = super.add(keyOrNodeOrEntryOrRawElement, value); + if (inserted) this._balancePath(keyOrNodeOrEntryOrRawElement); return inserted; } @@ -158,16 +170,14 @@ export class AVLTree< * 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. + * The function overrides the delete method of a binary tree class and performs additional operations + * to balance the tree after deletion. * @param identifier - The `identifier` parameter is the value or condition used to identify the - * node(s) to be deleted from the binary tree. It can be of any type and is the return type of the - * `callback` function. - * @param {C} callback - The `callback` parameter is a function that will be called for each node - * that is deleted from the binary tree. It is an optional parameter and if not provided, it will - * default to the `_DEFAULT_CALLBACK` function. The `callback` function should have a single - * parameter of type `NODE - * @returns The method is returning an array of `BinaryTreeDeleteResult`. + * node(s) to be deleted from the binary tree. It can be of any type that is compatible with the + * binary tree's node type. + * @param {C} callback - The `callback` parameter is a function that will be used to determine if a + * node should be deleted or not. It is optional and has a default value of `this._DEFAULT_CALLBACK`. + * @returns The method is returning an array of BinaryTreeDeleteResult objects. */ override delete>( identifier: ReturnType, @@ -183,18 +193,26 @@ export class AVLTree< } /** - * The `_swapProperties` function swaps the key, value, and height properties between two nodes in a binary - * tree. - * @param {K | NODE | undefined} srcNode - The `srcNode` parameter represents the source node that - * needs to be swapped with the destination node. It can be of type `K`, `NODE`, or `undefined`. - * @param {K | NODE | undefined} destNode - The `destNode` parameter represents the destination - * node where the values from the source node will be swapped to. - * @returns either the `destNode` object if both `srcNode` and `destNode` are defined, or `undefined` - * if either `srcNode` or `destNode` is undefined. + * Time Complexity: O(1) + * Space Complexity: O(1) + */ + + /** + * Time Complexity: O(1) + * Space Complexity: O(1) + * + * The `_swapProperties` function swaps the key, value, and height properties between two nodes in a + * binary search tree. + * @param {R | BSTNKeyOrNode} srcNode - The `srcNode` parameter represents either a node + * object (`NODE`) or a key-value pair (`R`) that is being swapped with another node. + * @param {R | BSTNKeyOrNode} destNode - The `destNode` parameter is either an instance of + * `R` or an instance of `BSTNKeyOrNode`. + * @returns The method is returning the `destNodeEnsured` object if both `srcNodeEnsured` and + * `destNodeEnsured` are truthy. Otherwise, it returns `undefined`. */ protected override _swapProperties( - srcNode: BSTNKeyOrNode, - destNode: BSTNKeyOrNode + srcNode: R | BSTNKeyOrNode, + destNode: R | BSTNKeyOrNode ): NODE | undefined { const srcNodeEnsured = this.ensureNode(srcNode); const destNodeEnsured = this.ensureNode(destNode); @@ -230,7 +248,8 @@ export class AVLTree< * Space Complexity: O(1) * * The function calculates the balance factor of a node in a binary tree. - * @param {NODE} node - The parameter "node" represents a node in a binary tree data structure. + * @param {NODE} node - The parameter "node" is of type "NODE", which likely represents a node in a + * binary tree data structure. * @returns the balance factor of a given node. The balance factor is calculated by subtracting the * height of the left subtree from the height of the right subtree. */ @@ -275,7 +294,7 @@ export class AVLTree< * Time Complexity: O(1) * Space Complexity: O(1) * - * The function `_balanceLL` performs a left-left rotation to balance a binary tree. + * The `_balanceLL` function performs a left-left rotation to balance a binary search tree. * @param {NODE} A - A is a node in a binary tree. */ protected _balanceLL(A: NODE): void { @@ -470,10 +489,10 @@ export class AVLTree< * * 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 {NODE} node - The `node` parameter in the `_balancePath` function represents the node in the - * AVL tree that needs to be balanced. + * @param {R | KeyOrNodeOrEntry} node - The `node` parameter can be of type `R` or + * `KeyOrNodeOrEntry`. */ - protected _balancePath(node: KeyOrNodeOrEntry): void { + protected _balancePath(node: R | 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++) { @@ -514,13 +533,22 @@ export class AVLTree< } /** - * The function replaces an old node with a new node while preserving the height of the old node. - * @param {NODE} oldNode - The `oldNode` parameter is the node that you want to replace with the - * `newNode`. + * Time Complexity: O(1) + * Space Complexity: O(1) + */ + + /** + * Time Complexity: O(1) + * Space Complexity: O(1) + * + * The function replaces an old node with a new node and sets the height of the new node to be the + * same as the old node. + * @param {NODE} oldNode - The `oldNode` parameter represents the node that needs to be replaced in + * the data structure. * @param {NODE} newNode - The `newNode` parameter is the new node that will replace the `oldNode` in * the data structure. - * @returns the result of calling the `_replaceNode` method on the superclass, passing in the - * `oldNode` and `newNode` as arguments. + * @returns The method is returning the result of calling the `_replaceNode` method from the + * superclass, with the `oldNode` and `newNode` as arguments. */ protected override _replaceNode(oldNode: NODE, newNode: NODE): NODE { newNode.height = oldNode.height; diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index 44a39a2..2185737 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -133,32 +133,35 @@ export class BinaryTreeNode< export class BinaryTree< K extends Comparable, V = any, + R = BTNEntry, NODE extends BinaryTreeNode = BinaryTreeNode>, - TREE extends BinaryTree = BinaryTree> + TREE extends BinaryTree = BinaryTree> > extends IterableEntryBase - implements IBinaryTree { + implements IBinaryTree { iterationType: IterationType = 'ITERATIVE'; /** - * The constructor function initializes a binary tree object with optional keysOrNodesOrEntries and options. - * @param [keysOrNodesOrEntries] - An optional iterable of KeyOrNodeOrEntry objects. These objects represent the + * The constructor function initializes a binary tree object with optional keysOrNodesOrEntriesOrRawElements and options. + * @param [keysOrNodesOrEntriesOrRawElements] - 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(keysOrNodesOrEntries: Iterable> = [], options?: BinaryTreeOptions) { + constructor( + keysOrNodesOrEntriesOrRawElements: Iterable> = [], + options?: BinaryTreeOptions + ) { super(); if (options) { - const { iterationType } = options; + const { iterationType, toEntryFn } = options; if (iterationType) this.iterationType = iterationType; + if (typeof toEntryFn === 'function') this._toEntryFn = toEntryFn; } - this._size = 0; - - if (keysOrNodesOrEntries) this.addMany(keysOrNodesOrEntries); + if (keysOrNodesOrEntriesOrRawElements) this.addMany(keysOrNodesOrEntriesOrRawElements); } protected _root?: NODE | null; @@ -172,7 +175,7 @@ export class BinaryTree< return this._root; } - protected _size: number; + protected _size: number = 0; /** * The function returns the size of an object. @@ -192,6 +195,16 @@ export class BinaryTree< return this._NIL; } + protected _toEntryFn?: (rawElement: R) => BTNEntry; + + /** + * The function returns the value of the _toEntryFn property. + * @returns The function being returned is `this._toEntryFn`. + */ + get toEntryFn() { + return this._toEntryFn; + } + /** * Creates a new instance of BinaryTreeNode with the given key and value. * @param {K} key - The key for the new node. @@ -209,41 +222,46 @@ export class BinaryTree< * you can provide only a subset of the properties defined in the `BinaryTreeOptions` interface. * @returns a new instance of a binary tree. */ - createTree(options?: Partial): TREE { - return new BinaryTree([], { iterationType: this.iterationType, ...options }) as TREE; + createTree(options?: Partial>): TREE { + return new BinaryTree([], { iterationType: this.iterationType, ...options }) as TREE; } /** - * The function `keyValueOrEntryToNode` converts an keyOrNodeOrEntry object into a node object. - * @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter is of type `KeyOrNodeOrEntry`. + * The function `keyValueOrEntryOrRawElementToNode` converts a key-value pair, entry, or raw element + * into a node object. + * @param {R | KeyOrNodeOrEntry} keyOrNodeOrEntryOrRawElement - The parameter + * `keyOrNodeOrEntryOrRawElement` can be of type `R` or `KeyOrNodeOrEntry`. * @param {V} [value] - The `value` parameter is an optional value that can be passed to the - * `keyValueOrEntryToNode` function. It represents the value associated with the keyOrNodeOrEntry node. If no value - * is provided, it will be `undefined`. - * @returns a value of type NODE (node), or null, or undefined. + * `keyValueOrEntryOrRawElementToNode` function. It represents the value associated with a key in a + * key-value pair. If provided, it will be used to create a node with the specified key and value. + * @returns The function `keyValueOrEntryOrRawElementToNode` returns either a `NODE` object, `null`, + * or `undefined`. */ - keyValueOrEntryToNode(keyOrNodeOrEntry: KeyOrNodeOrEntry, value?: V): NODE | null | undefined { - if (keyOrNodeOrEntry === undefined) return; + keyValueOrEntryOrRawElementToNode( + keyOrNodeOrEntryOrRawElement: R | KeyOrNodeOrEntry, + value?: V + ): NODE | null | undefined { + if (keyOrNodeOrEntryOrRawElement === undefined) return; + if (keyOrNodeOrEntryOrRawElement === null) return null; - let node: NODE | null | undefined; - if (keyOrNodeOrEntry === null) { - node = null; - } else if (this.isEntry(keyOrNodeOrEntry)) { - const [key, value] = keyOrNodeOrEntry; - if (key === undefined) { - return; - } else if (key === null) { - node = null; - } else { - node = this.createNode(key, value); - } - } else if (this.isNode(keyOrNodeOrEntry)) { - node = keyOrNodeOrEntry; - } else if (!this.isNode(keyOrNodeOrEntry)) { - node = this.createNode(keyOrNodeOrEntry, value); - } else { - return; + if (this.isNode(keyOrNodeOrEntryOrRawElement)) return keyOrNodeOrEntryOrRawElement; + + if (this.toEntryFn) { + const [key, entryValue] = this.toEntryFn(keyOrNodeOrEntryOrRawElement as R); + if (key) return this.createNode(key, entryValue ?? value); + else return; } - return node; + + if (this.isEntry(keyOrNodeOrEntryOrRawElement)) { + const [key, value] = keyOrNodeOrEntryOrRawElement; + if (key === undefined) return; + else if (key === null) return null; + else return this.createNode(key, value); + } + + if (this.isKey(keyOrNodeOrEntryOrRawElement)) return this.createNode(keyOrNodeOrEntryOrRawElement, value); + + return; } /** @@ -255,81 +273,122 @@ 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 | NODE | null | undefined} keyOrNodeOrEntry - The `key` parameter can be of type `K`, `NODE`, - * `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 - * `'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. + * The `ensureNode` function checks if the input is a valid node and returns it, or converts it to a + * node if it is a key or entry. + * @param {R | KeyOrNodeOrEntry} keyOrNodeOrEntryOrRawElement - The parameter + * `keyOrNodeOrEntryOrRawElement` can accept a value of type `R`, `KeyOrNodeOrEntry`, or + * a raw element. + * @param {IterationType} [iterationType=ITERATIVE] - The `iterationType` parameter is an optional + * parameter that specifies the type of iteration to be used when searching for a node. It has a + * default value of `'ITERATIVE'`. + * @returns The function `ensureNode` returns either a `NODE` object, `null`, or `undefined`. */ ensureNode( - keyOrNodeOrEntry: KeyOrNodeOrEntry, + keyOrNodeOrEntryOrRawElement: R | KeyOrNodeOrEntry, iterationType: IterationType = 'ITERATIVE' ): NODE | null | undefined { - if (keyOrNodeOrEntry === this.NIL) return; - if (this.isRealNode(keyOrNodeOrEntry)) { - return keyOrNodeOrEntry; + if (keyOrNodeOrEntryOrRawElement === null) return null; + if (keyOrNodeOrEntryOrRawElement === undefined) return; + if (keyOrNodeOrEntryOrRawElement === this.NIL) return; + if (this.isNode(keyOrNodeOrEntryOrRawElement)) return keyOrNodeOrEntryOrRawElement; + + if (this.toEntryFn) { + const [key] = this.toEntryFn(keyOrNodeOrEntryOrRawElement as R); + if (key) return this.getNodeByKey(key); } - if (this.isEntry(keyOrNodeOrEntry)) { - const key = keyOrNodeOrEntry[0]; + + if (this.isEntry(keyOrNodeOrEntryOrRawElement)) { + const key = keyOrNodeOrEntryOrRawElement[0]; if (key === null) return null; if (key === undefined) return; return this.getNodeByKey(key, iterationType); } - if (keyOrNodeOrEntry === null) return null; - if (keyOrNodeOrEntry === undefined) return; - return this.getNodeByKey(keyOrNodeOrEntry, iterationType); + + if (this.isKey(keyOrNodeOrEntryOrRawElement)) return this.getNodeByKey(keyOrNodeOrEntryOrRawElement, iterationType); + return; } /** - * 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. + * The function checks if the input is an instance of the BinaryTreeNode class. + * @param {R | KeyOrNodeOrEntry} keyOrNodeOrEntryOrRawElement - The parameter + * `keyOrNodeOrEntryOrRawElement` can be of type `R` or `KeyOrNodeOrEntry`. + * @returns a boolean value indicating whether the input parameter `keyOrNodeOrEntryOrRawElement` is + * an instance of the `BinaryTreeNode` class. + */ + isNode(keyOrNodeOrEntryOrRawElement: R | KeyOrNodeOrEntry): keyOrNodeOrEntryOrRawElement is NODE { + return keyOrNodeOrEntryOrRawElement instanceof BinaryTreeNode; + } + + /** + * The function checks if a given node is a valid node in a binary search tree. + * @param {R | KeyOrNodeOrEntry} node - The parameter `node` can be of type `R` or + * `KeyOrNodeOrEntry`. * @returns a boolean value. */ - isNodeOrNull(node: KeyOrNodeOrEntry): node is NODE | null { - return this.isRealNode(node) || node === null; - } - - /** - * 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 NODE. - */ - isNode(keyOrNodeOrEntry: KeyOrNodeOrEntry): keyOrNodeOrEntry is NODE { - return keyOrNodeOrEntry instanceof BinaryTreeNode; - } - - /** - * 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 NODE { + isRealNode(node: R | KeyOrNodeOrEntry): node is NODE { if (node === this.NIL || node === null || node === undefined) return false; return this.isNode(node); } /** - * 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. + * The function checks if a given node is a real node or null. + * @param {R | KeyOrNodeOrEntry} node - The parameter `node` can be of type `R` or + * `KeyOrNodeOrEntry`. * @returns a boolean value. */ - isNIL(node: KeyOrNodeOrEntry) { + isNodeOrNull(node: R | KeyOrNodeOrEntry): node is NODE | null { + return this.isRealNode(node) || node === null; + } + + /** + * The function checks if a given node is equal to the NIL value. + * @param {R | KeyOrNodeOrEntry} node - The parameter `node` can be of type `R` or + * `KeyOrNodeOrEntry`. + * @returns a boolean value. + */ + isNIL(node: R | KeyOrNodeOrEntry) { return node === this.NIL; } /** - * The function checks if a given value is an entry in a binary tree node. - * @param keyOrNodeOrEntry - KeyOrNodeOrEntry - A generic type representing a node in a binary tree. It has - * two type parameters V and NODE, representing the value and node type respectively. + * The function checks if the input is an array with two elements, indicating it is a binary tree + * node entry. + * @param {R | KeyOrNodeOrEntry} keyOrNodeOrEntryOrRawElement - The parameter + * `keyOrNodeOrEntryOrRawElement` can be of type `R` or `KeyOrNodeOrEntry`. * @returns a boolean value. */ - isEntry(keyOrNodeOrEntry: KeyOrNodeOrEntry): keyOrNodeOrEntry is BTNEntry { - return Array.isArray(keyOrNodeOrEntry) && keyOrNodeOrEntry.length === 2; + isEntry( + keyOrNodeOrEntryOrRawElement: R | KeyOrNodeOrEntry + ): keyOrNodeOrEntryOrRawElement is BTNEntry { + return Array.isArray(keyOrNodeOrEntryOrRawElement) && keyOrNodeOrEntryOrRawElement.length === 2; + } + + /** + * The function checks if a given value is a valid key by evaluating its type and value. + * @param {any} key - The `key` parameter can be of any type. It is the value that we want to check + * if it is a valid key. + * @param [isCheckValueOf=true] - The `isCheckValueOf` parameter is a boolean flag that determines + * whether the function should check the valueOf() method of an object when the key is of type + * 'object'. If `isCheckValueOf` is true, the function will recursively call itself with the value + * returned by key.valueOf(). + * @returns a boolean value. + */ + isKey(key: any, isCheckValueOf = true): key is K { + if (key === null) return true; + const keyType = typeof key; + if (keyType === 'string' || keyType === 'bigint' || keyType === 'boolean') return true; + if (keyType === 'number') return !isNaN(key); + if (keyType === 'symbol' || keyType === 'undefined') return false; + if (keyType === 'function') return this.isKey(key()); + if (keyType === 'object') { + if (typeof key.toString === 'function') return true; + if (isCheckValueOf && typeof key.valueOf === 'function') { + this.isKey(key.valueOf(), false); + } + return false; + } + + return false; } /** @@ -341,14 +400,20 @@ export class BinaryTree< * Time Complexity O(n) * Space Complexity O(1) * - * The `add` function adds a new node to a binary tree, either by creating a new node or replacing an - * existing node with the same key. - * @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter can be one of the following: - * @param {V} [value] - The value to be inserted into the binary tree. - * @returns The function `add` returns either a node (`NODE`), `null`, or `undefined`. + * The `add` function is used to insert a new node into a binary tree, checking for duplicate keys + * and finding the appropriate insertion position. + * @param {R | KeyOrNodeOrEntry} keyOrNodeOrEntryOrRawElement - The + * `keyOrNodeOrEntryOrRawElement` parameter can accept a value of type `R`, which represents the key, + * node, entry, or raw element to be added to the tree. It can also accept a value of type + * `KeyOrNodeOrEntry + * @param {V} [value] - The `value` parameter is an optional value that can be associated with the + * key being added to the tree. It represents the value that will be stored in the tree for the given + * key. + * @returns a boolean value. It returns `true` if the insertion is successful, and `false` if the + * insertion position cannot be found or if there are duplicate keys. */ - add(keyOrNodeOrEntry: KeyOrNodeOrEntry, value?: V): boolean { - const newNode = this.keyValueOrEntryToNode(keyOrNodeOrEntry, value); + add(keyOrNodeOrEntryOrRawElement: R | KeyOrNodeOrEntry, value?: V): boolean { + const newNode = this.keyValueOrEntryOrRawElementToNode(keyOrNodeOrEntryOrRawElement, value); if (newNode === undefined) return false; // If the tree is empty, directly set the new node as the root node @@ -410,13 +475,20 @@ export class BinaryTree< * Time Complexity: O(k * n) * Space Complexity: O(1) * - * 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 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 `NODE`, `null`, or `undefined` values. + * The `addMany` function takes in an iterable of keys or nodes or entries or raw elements, and an + * optional iterable of values, and adds each key or node or entry with its corresponding value to a + * data structure, returning an array of booleans indicating whether each insertion was successful. + * @param keysOrNodesOrEntriesOrRawElements - An iterable containing keys, nodes, entries, or raw + * elements. These elements will be added to the data structure. + * @param [values] - An optional iterable of values that correspond to the keys or nodes or entries + * in the `keysOrNodesOrEntriesOrRawElements` parameter. + * @returns The function `addMany` returns an array of booleans indicating whether each element was + * successfully added to the data structure. */ - addMany(keysOrNodesOrEntries: Iterable>, values?: Iterable): boolean[] { + addMany( + keysOrNodesOrEntriesOrRawElements: Iterable>, + values?: Iterable + ): boolean[] { // TODO not sure addMany not be run multi times const inserted: boolean[] = []; @@ -425,7 +497,7 @@ export class BinaryTree< valuesIterator = values[Symbol.iterator](); } - for (const keyOrNodeOrEntry of keysOrNodesOrEntries) { + for (const keyOrNodeOrEntryOrRawElement of keysOrNodesOrEntriesOrRawElements) { let value: V | undefined | null = undefined; if (valuesIterator) { @@ -435,7 +507,7 @@ export class BinaryTree< } } - inserted.push(this.add(keyOrNodeOrEntry, value)); + inserted.push(this.add(keyOrNodeOrEntryOrRawElement, value)); } return inserted; @@ -451,17 +523,19 @@ export class BinaryTree< * 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 + * The `refill` function clears the current data and adds new data to the collection. + * @param keysOrNodesOrEntriesOrRawElements - An iterable collection of keys, nodes, entries, or raw + * elements. These can be of any type (R) or a specific type (KeyOrNodeOrEntry). + * @param [values] - The `values` parameter is an optional iterable of values that will be associated + * with the keys or nodes being added. If provided, the values will be assigned to the corresponding + * keys or nodes. If not provided, the values will be set to `undefined`. */ - refill(keysOrNodesOrEntries: Iterable>, values?: Iterable): void { + refill( + keysOrNodesOrEntriesOrRawElements: Iterable>, + values?: Iterable + ): void { this.clear(); - this.addMany(keysOrNodesOrEntries, values); + this.addMany(keysOrNodesOrEntriesOrRawElements, values); } delete>(identifier: K, callback?: C): BinaryTreeDeleteResult[]; @@ -476,21 +550,21 @@ export class BinaryTree< /** * Time Complexity: O(n) * Space Complexity: O(1) - * / + */ - /** + /** * Time Complexity: O(n) * Space Complexity: O(1) * - * The function deletes a node from a binary tree and returns an array of the deleted nodes along - * with the nodes that need to be balanced. - * @param {ReturnType | null | undefined} identifier - The identifier parameter is the value or - * object that you want to delete from the binary tree. It can be of any type that is compatible with - * the callback function's return type. It can also be null or undefined if you want to delete a - * specific node based on its value or object. + * The above function is a TypeScript implementation of deleting a node from a binary tree, returning + * the deleted node and the node that needs to be balanced. + * @param {ReturnType | null | undefined} identifier - The `identifier` parameter is the value + * used to identify the node that needs to be deleted from the binary tree. It can be of any type + * that is returned by the callback function. * @param {C} callback - The `callback` parameter is a function that is used to determine the - * identifier of the node to be deleted. It is optional and has a default value of - * `this._DEFAULT_CALLBACK`. The `callback` function should return the identifier of the node. + * identifier of the node to be deleted. It is of type `C`, which extends the `BTNCallback` + * interface. The `BTNCallback` interface represents a callback function that takes a node of + * type `NODE * @returns an array of `BinaryTreeDeleteResult`. */ delete>( @@ -545,7 +619,7 @@ export class BinaryTree< identifier: K, callback?: C, onlyOne?: boolean, - beginRoot?: KeyOrNodeOrEntry, + beginRoot?: R | KeyOrNodeOrEntry, iterationType?: IterationType ): NODE[]; @@ -553,7 +627,7 @@ export class BinaryTree< identifier: NODE | null | undefined, callback?: C, onlyOne?: boolean, - beginRoot?: KeyOrNodeOrEntry, + beginRoot?: R | KeyOrNodeOrEntry, iterationType?: IterationType ): NODE[]; @@ -561,7 +635,7 @@ export class BinaryTree< identifier: ReturnType, callback: C, onlyOne?: boolean, - beginRoot?: KeyOrNodeOrEntry, + beginRoot?: R | KeyOrNodeOrEntry, iterationType?: IterationType ): NODE[]; @@ -572,34 +646,33 @@ export class BinaryTree< /** * Time Complexity: O(n) - * Space Complexity: O(k + log n). + * Space Complexity: O(k + log n) * - * The function `getNodes` retrieves nodes from a binary tree based on a given identifier and - * callback function. + * The function `getNodes` returns an array of nodes that match a given identifier, using either a + * recursive or iterative approach. * @param {ReturnType | null | undefined} identifier - The `identifier` parameter is the value - * that you want to search for in the binary tree. It can be of any type that is returned by the - * callback function `C`. It can also be `null` or `undefined` if you don't want to search for a - * specific value. - * @param {C} callback - The `callback` parameter is a function that takes a node of type `NODE` as - * input and returns a value of type `C`. It is used to determine if a node matches the given - * identifier. If no callback is provided, the `_DEFAULT_CALLBACK` function is used as the - * default - * @param [onlyOne=false] - A boolean value indicating whether to only return the first node that - * matches the identifier. If set to true, the function will stop iterating once it finds a matching - * node and return that node. If set to false (default), the function will continue iterating and - * return all nodes that match the identifier. - * @param {K | NODE | null | undefined} beginRoot - The `beginRoot` parameter represents the - * starting node for the traversal. It can be either a key, a node object, or `null`/`undefined`. If - * it is `null` or `undefined`, an empty array will be returned. - * @param iterationType - The `iterationType` parameter determines the type of iteration used to - * traverse the binary tree. It can have two possible values: - * @returns an array of nodes of type `NODE`. + * that is used to identify the nodes. It can be of any type and is used to match against the result + * of the callback function for each node. + * @param {C} callback - The `callback` parameter is a function that takes a node as input and + * returns a value. This value is used to identify the nodes that match the given identifier. The + * `callback` function is optional and defaults to a default callback function + * (`this._DEFAULT_CALLBACK`) if not provided. + * @param [onlyOne=false] - A boolean value indicating whether to return only one node that matches + * the identifier or all nodes that match the identifier. If set to true, only the first matching + * node will be returned. If set to false, all matching nodes will be returned. The default value is + * false. + * @param {R | KeyOrNodeOrEntry} beginRoot - The `beginRoot` parameter is the starting + * point for the search. It can be either a node object, a key-value pair, or a key. If it is not + * provided, the `root` of the data structure is used as the starting point. + * @param {IterationType} iterationType - The `iterationType` parameter determines the type of + * iteration to be performed on the nodes of a binary tree. It can have two possible values: + * @returns an array of NODE objects. */ getNodes>( identifier: ReturnType | null | undefined, callback: C = this._DEFAULT_CALLBACK as C, onlyOne = false, - beginRoot: KeyOrNodeOrEntry = this.root, + beginRoot: R | KeyOrNodeOrEntry = this.root, iterationType: IterationType = this.iterationType ): NODE[] { beginRoot = this.ensureNode(beginRoot); @@ -641,21 +714,21 @@ export class BinaryTree< getNode>( identifier: K, callback?: C, - beginRoot?: KeyOrNodeOrEntry, + beginRoot?: R | KeyOrNodeOrEntry, iterationType?: IterationType ): NODE | null | undefined; getNode>( identifier: NODE | null | undefined, callback?: C, - beginRoot?: KeyOrNodeOrEntry, + beginRoot?: R | KeyOrNodeOrEntry, iterationType?: IterationType ): NODE | null | undefined; getNode>( identifier: ReturnType, callback: C, - beginRoot?: KeyOrNodeOrEntry, + beginRoot?: R | KeyOrNodeOrEntry, iterationType?: IterationType ): NODE | null | undefined; @@ -666,29 +739,26 @@ export class BinaryTree< /** * Time Complexity: O(n) - * Space Complexity: O(log n) + * Space Complexity: O(log n). * - * The function `getNode` returns the first node that matches the given identifier and callback - * function. + * The function `getNode` returns the first node that matches the given identifier and callback, + * starting from the specified root node and using the specified iteration type. * @param {ReturnType | null | undefined} identifier - The `identifier` parameter is the value - * used to identify the node you want to retrieve. It can be of any type that is returned by the - * callback function `C`. It can also be `null` or `undefined` if you don't have a specific - * identifier. - * @param {C} callback - The `callback` parameter is a function that will be called for each node in - * the binary tree. It is used to determine if a node matches the given identifier. The `callback` - * function should take a single parameter of type `NODE` (the type of the nodes in the binary tree) and - * @param {K | NODE | null | undefined} beginRoot - The `beginRoot` parameter is the starting point - * for searching the binary tree. It can be either a key value, a node object, or `null`/`undefined`. - * If `null` or `undefined` is passed, the search will start from the root of the binary tree. - * @param iterationType - The `iterationType` parameter is used to specify the type of iteration to - * be performed when searching for nodes in the binary tree. It determines the order in which the - * nodes are visited during the search. - * @returns a value of type `NODE | null | undefined`. + * used to identify the node you want to retrieve. It can be of any type that is the return type of + * the `C` callback function, or it can be `null` or `undefined`. + * @param {C} callback - The `callback` parameter is a function that will be used to determine if a + * node matches the desired criteria. It should return a value that can be used to identify the node. + * @param {R | KeyOrNodeOrEntry} beginRoot - The `beginRoot` parameter is the starting + * point for searching nodes in a tree structure. It can be either a root node, a key-value pair, or + * a node entry. If not provided, the search will start from the root of the tree. + * @param {IterationType} iterationType - The `iterationType` parameter is used to specify the type + * of iteration to be performed when searching for nodes. It can have one of the following values: + * @returns The method is returning a NODE object, or null, or undefined. */ getNode>( identifier: ReturnType | null | undefined, callback: C = this._DEFAULT_CALLBACK as C, - beginRoot: KeyOrNodeOrEntry = this.root, + beginRoot: R | KeyOrNodeOrEntry = this.root, iterationType: IterationType = this.iterationType ): NODE | null | undefined { return this.getNodes(identifier, callback, true, beginRoot, iterationType)[0] ?? null; @@ -703,15 +773,13 @@ export class BinaryTree< * Time Complexity: O(n) * Space Complexity: O(log n) * - * The function `getNodeByKey` searches for a node in a binary tree by its key, using either - * recursive or iterative iteration. - * @param {K} key - The `key` parameter is the key value that we are searching for in the tree. - * It is used to find the node with the matching key value. - * @param iterationType - The `iterationType` parameter is used to determine whether the search for - * the node with the given key should be performed iteratively or recursively. It has two possible - * values: - * @returns The function `getNodeByKey` returns a node (`NODE`) if a node with the specified key is - * found in the binary tree. If no node is found, it returns `undefined`. + * The function `getNodeByKey` returns a node with a specific key value from a tree structure. + * @param {K} key - The key parameter is the value that you want to search for in the tree. It is + * used to find the node with the matching key value. + * @param {IterationType} [iterationType=ITERATIVE] - The `iterationType` parameter is an optional + * parameter that specifies the type of iteration to be used when searching for a node in the tree. + * It has a default value of `'ITERATIVE'`. + * @returns a value of type NODE, null, or undefined. */ getNodeByKey(key: K, iterationType: IterationType = 'ITERATIVE'): NODE | null | undefined { return this.getNode(key, this._DEFAULT_CALLBACK, this.root, iterationType); @@ -720,21 +788,21 @@ export class BinaryTree< override get>( identifier: K, callback?: C, - beginRoot?: KeyOrNodeOrEntry, + beginRoot?: R | KeyOrNodeOrEntry, iterationType?: IterationType ): V | undefined; override get>( identifier: NODE | null | undefined, callback?: C, - beginRoot?: KeyOrNodeOrEntry, + beginRoot?: R | KeyOrNodeOrEntry, iterationType?: IterationType ): V | undefined; override get>( identifier: ReturnType, callback: C, - beginRoot?: KeyOrNodeOrEntry, + beginRoot?: R | KeyOrNodeOrEntry, iterationType?: IterationType ): V | undefined; @@ -747,28 +815,27 @@ export class BinaryTree< * Time Complexity: O(n) * Space Complexity: O(log n) * - * The function `get` retrieves the value of a node in a binary tree based on the provided identifier - * and callback function. + * The function `get` in TypeScript overrides the base class method and returns the value associated + * with the given identifier. * @param {ReturnType | null | undefined} identifier - The `identifier` parameter is the value - * used to identify the node in the binary tree. It can be of any type that is the return type of the + * used to identify the node in the binary tree. It can be of any type that is returned by the * callback function `C`. It can also be `null` or `undefined` if no identifier is provided. - * @param {C} callback - The `callback` parameter is a function that will be called with each node in - * the binary tree. It is used to determine whether a node matches the given identifier. The callback - * function should return a value that can be compared to the identifier to determine if it is a - * match. - * @param {K | NODE | null | undefined} beginRoot - The `beginRoot` parameter is the starting point - * for the search in the binary tree. It can be specified as a `K` (a unique identifier for a - * node), a node object of type `NODE`, or `null`/`undefined` to start the search from the root of - * @param iterationType - The `iterationType` parameter is used to specify the type of iteration to - * be performed when searching for a node in the binary tree. It is an optional parameter with a - * default value specified by `this.iterationType`. - * @returns The value of the node with the given identifier is being returned. If the node is not - * found, `undefined` is returned. + * @param {C} callback - The `callback` parameter is a function that will be used to determine if a + * node matches the given identifier. It is optional and defaults to `this._DEFAULT_CALLBACK`. + * @param {R | KeyOrNodeOrEntry} beginRoot - The `beginRoot` parameter is the starting + * point for the search in the binary tree. It can be either a root node of the tree or a key, node, + * or entry object that exists in the tree. If no specific starting point is provided, the search + * will begin from the root of the + * @param {IterationType} iterationType - The `iterationType` parameter is used to specify the type + * of iteration to be performed when searching for a node in the tree. It can have one of the + * following values: + * @returns The method is returning the value associated with the specified identifier in the binary + * tree. */ override get>( identifier: ReturnType | null | undefined, callback: C = this._DEFAULT_CALLBACK as C, - beginRoot: KeyOrNodeOrEntry = this.root, + beginRoot: R | KeyOrNodeOrEntry = this.root, iterationType: IterationType = this.iterationType ): V | undefined { return this.getNode(identifier, callback, beginRoot, iterationType)?.value; @@ -777,54 +844,53 @@ export class BinaryTree< override has>( identifier: K, callback?: C, - beginRoot?: KeyOrNodeOrEntry, + beginRoot?: R | KeyOrNodeOrEntry, iterationType?: IterationType ): boolean; override has>( identifier: NODE | null | undefined, callback?: C, - beginRoot?: KeyOrNodeOrEntry, + beginRoot?: R | KeyOrNodeOrEntry, iterationType?: IterationType ): boolean; override has>( identifier: ReturnType | null | undefined, callback: C, - beginRoot?: KeyOrNodeOrEntry, + beginRoot?: R | KeyOrNodeOrEntry, iterationType?: IterationType ): boolean; /** * Time Complexity: O(n) - * Space Complexity: O(log n). + * Space Complexity: O(log n) */ /** * Time Complexity: O(n) - * Space Complexity: O(log n). + * Space Complexity: O(log n) * - * The function checks if a Binary Tree Node with a specific identifier exists in the tree. + * The `has` function checks if a given identifier exists in the data structure and returns a boolean + * value. * @param {ReturnType | null | undefined} identifier - The `identifier` parameter is the value - * that you want to search for in the binary tree. It can be of any type that is returned by the - * callback function `C`. It can also be `null` or `undefined` if you don't want to specify a - * specific identifier. - * @param {C} callback - The `callback` parameter is a function that will be called for each node in - * the binary tree. It is used to filter the nodes based on certain conditions. The `callback` - * function should return a boolean value indicating whether the node should be included in the - * result or not. - * @param {K | NODE | null | undefined} beginRoot - The `beginRoot` parameter is the starting point - * for the search in the binary tree. It can be specified as a `K` (a unique identifier for a - * node in the binary tree), a node object (`NODE`), or `null`/`undefined` to start the search from - * @param iterationType - The `iterationType` parameter is a variable that determines the type of - * iteration to be performed on the binary tree. It is used to specify whether the iteration should - * be performed in a pre-order, in-order, or post-order manner. - * @returns a boolean value. + * used to identify a specific node or entry in the data structure. It can be of any type that is + * returned by the callback function `C`. It can also be `null` or `undefined` if no specific + * identifier is provided. + * @param {C} callback - The `callback` parameter is a function that will be used to determine + * whether a node should be included in the result or not. It is of type `C`, which extends the + * `BTNCallback` type. + * @param {R | KeyOrNodeOrEntry} beginRoot - The `beginRoot` parameter is the starting + * point for the iteration in the data structure. It can be either a root node, a key-value pair, or + * a node entry. If not specified, it defaults to the root of the data structure. + * @param {IterationType} iterationType - The `iterationType` parameter is used to specify the type + * of iteration to be performed. It is an optional parameter with a default value of `IterationType`. + * @returns The method is returning a boolean value. */ override has>( identifier: ReturnType | null | undefined, callback: C = this._DEFAULT_CALLBACK as C, - beginRoot: KeyOrNodeOrEntry = this.root, + beginRoot: R | KeyOrNodeOrEntry = this.root, iterationType: IterationType = this.iterationType ): boolean { callback = this._ensureCallback(identifier, callback); @@ -875,12 +941,13 @@ export class BinaryTree< * * The function checks if a binary tree is perfectly balanced by comparing the minimum height and the * height of the tree. - * @param {K | NODE | null | undefined} beginRoot - The `beginRoot` parameter is the starting point - * for calculating the height and minimum height of a binary tree. It can be either a `K` (a key - * value of a binary tree node), `NODE` (a node of a binary tree), `null`, or `undefined`. If + * @param {R | KeyOrNodeOrEntry} beginRoot - The parameter `beginRoot` is optional and + * has a default value of `this.root`. It represents the starting point for checking if the tree is + * perfectly balanced. It can be either a root node (`R`), a key or node or entry + * (`KeyOrNodeOrEntry = this.root): boolean { + isPerfectlyBalanced(beginRoot: R | KeyOrNodeOrEntry = this.root): boolean { return this.getMinHeight(beginRoot) + 1 >= this.getHeight(beginRoot); } @@ -893,16 +960,18 @@ export class BinaryTree< * Time Complexity: O(n) * Space Complexity: O(1) * - * The function `isSubtreeBST` checks if a given binary tree is a valid binary search tree. - * @param {K | NODE | null | undefined} beginRoot - The `beginRoot` parameter represents the root - * node of the binary search tree (BST) that you want to check if it is a subtree of another BST. - * @param iterationType - The `iterationType` parameter is an optional parameter that specifies the - * type of iteration to use when checking if a subtree is a binary search tree (BST). It can have two - * possible values: + * The function `isBST` checks if a binary search tree is valid, either recursively or iteratively. + * @param {R | KeyOrNodeOrEntry} beginRoot - The `beginRoot` parameter represents the + * starting point for checking if a binary search tree (BST) is valid. It can be either a root node + * of the BST, a key value of a node in the BST, or an entry object containing both the key and value + * of a node in the BST + * @param {IterationType} iterationType - The `iterationType` parameter is used to determine the type + * of iteration to be performed while checking if the binary search tree (BST) is valid. It can have + * two possible values: * @returns a boolean value. */ isBST( - beginRoot: KeyOrNodeOrEntry = this.root, + beginRoot: R | KeyOrNodeOrEntry = this.root, iterationType: IterationType = this.iterationType ): boolean { // TODO there is a bug @@ -954,16 +1023,17 @@ export class BinaryTree< * Time Complexity: O(n) * Space Complexity: O(1) * - * The function calculates the depth of a given node in a binary tree. - * @param {K | NODE | 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`, `NODE`, `null`, or - * `undefined`. - * @param {K | NODE | 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 - * `NODE` (binary tree node) or `null` or `undefined`. If no value is provided for `beginRoot - * @returns the depth of the `dist` relative to the `beginRoot`. + * The function calculates the depth of a given node or key in a tree-like data structure. + * @param {R | KeyOrNodeOrEntry} dist - The `dist` parameter can be either a `R` + * (representing a root node), or a `KeyOrNodeOrEntry` (representing a key, node, or + * entry). + * @param {R | KeyOrNodeOrEntry} beginRoot - The `beginRoot` parameter is optional and + * represents the starting point from which to calculate the depth. It can be either a reference to a + * node in the tree or a key-value pair or an entry object. If not provided, the default value is + * `this.root`, which refers to the root node + * @returns the depth of a node in a tree structure. */ - getDepth(dist: KeyOrNodeOrEntry, beginRoot: KeyOrNodeOrEntry = this.root): number { + getDepth(dist: R | KeyOrNodeOrEntry, beginRoot: R | KeyOrNodeOrEntry = this.root): number { let distEnsured = this.ensureNode(dist); const beginRootEnsured = this.ensureNode(beginRoot); let depth = 0; @@ -984,20 +1054,19 @@ export class BinaryTree< /** * Time Complexity: O(n) - * Space Complexity: O(log n) + * Space Complexity: O(1) * - * The function `getHeight` calculates the maximum height of a binary tree using either recursive or - * iterative traversal. - * @param {K | NODE | null | undefined} beginRoot - The `beginRoot` parameter represents the - * starting node of the binary tree from which we want to calculate the height. It can be of type - * `K`, `NODE`, `null`, or `undefined`. If not provided, it defaults to `this.root`. - * @param iterationType - The `iterationType` parameter is used to determine whether to calculate the - * height of the tree using a recursive approach or an iterative approach. It can have two possible - * values: - * @returns the height of the binary tree. + * The `getHeight` function calculates the maximum height of a binary tree using either a recursive + * or iterative approach. + * @param {R | KeyOrNodeOrEntry} beginRoot - The `beginRoot` parameter represents the + * starting point for calculating the height of a tree. It can be either a root node (`R`), a key or + * node or entry (`KeyOrNodeOrEntry`), or it defaults to the root of the current tree. + * @param {IterationType} iterationType - The `iterationType` parameter determines the type of + * iteration used to calculate the height of the tree. It can have two possible values: + * @returns the maximum height of the binary tree. */ getHeight( - beginRoot: KeyOrNodeOrEntry = this.root, + beginRoot: R | KeyOrNodeOrEntry = this.root, iterationType: IterationType = this.iterationType ): number { beginRoot = this.ensureNode(beginRoot); @@ -1040,15 +1109,18 @@ export class BinaryTree< * * The `getMinHeight` function calculates the minimum height of a binary tree using either a * recursive or iterative approach. - * @param {K | NODE | null | undefined} beginRoot - The `beginRoot` parameter represents the - * starting node of the binary tree from which we want to calculate the minimum height. It can be of - * type `K`, `NODE`, `null`, or `undefined`. If no value is provided, it defaults to `this.root`. - * @param iterationType - The `iterationType` parameter is used to determine the method of iteration - * 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. + * @param {R | KeyOrNodeOrEntry} beginRoot - The `beginRoot` parameter represents the + * starting point for calculating the minimum height of a tree. It can be either a root node (`R`), a + * key or node or entry (`KeyOrNodeOrEntry`), or it defaults to the root of the current + * tree. + * @param {IterationType} iterationType - The `iterationType` parameter determines the type of + * iteration to be used when calculating the minimum height of the tree. It can have two possible + * values: + * @returns The function `getMinHeight` returns a number, which represents the minimum height of the + * binary tree. */ getMinHeight( - beginRoot: KeyOrNodeOrEntry = this.root, + beginRoot: R | KeyOrNodeOrEntry = this.root, iterationType: IterationType = this.iterationType ): number { beginRoot = this.ensureNode(beginRoot); @@ -1096,24 +1168,22 @@ export class BinaryTree< /** * Time Complexity: O(log n) * Space Complexity: O(log n) - * / + */ - /** + /** * Time Complexity: O(log n) * Space Complexity: O(log n) * - * The function `getPathToRoot` returns an array of nodes from a given node to the root of a tree - * structure, with the option to reverse the order of the nodes. - * @param {K | NODE | null | undefined} beginNode - The `beginRoot` parameter represents the - * starting node from which you want to find the path to the root. It can be of type `K`, `NODE`, - * `null`, or `undefined`. + * The function `getPathToRoot` returns an array of nodes starting from a given node and traversing + * up to the root node, with an option to reverse the order of the nodes. + * @param {R | KeyOrNodeOrEntry} beginNode - The `beginNode` parameter can be either of + * type `R` or `KeyOrNodeOrEntry`. * @param [isReverse=true] - The `isReverse` parameter is a boolean flag that determines whether the * resulting path should be reversed or not. If `isReverse` is set to `true`, the path will be - * 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 (`NODE[]`). + * reversed before returning it. If `isReverse` is set to `false` or not provided, the path will + * @returns The function `getPathToRoot` returns an array of `NODE` objects. */ - getPathToRoot(beginNode: KeyOrNodeOrEntry, isReverse = true): NODE[] { - // TODO to support get path through passing key + getPathToRoot(beginNode: R | KeyOrNodeOrEntry, isReverse = true): NODE[] { const result: NODE[] = []; let beginNodeEnsured = this.ensureNode(beginNode); @@ -1121,7 +1191,6 @@ export class BinaryTree< while (beginNodeEnsured.parent) { // Array.push + Array.reverse is more efficient than Array.unshift - // TODO may consider using Deque, so far this is not the performance bottleneck result.push(beginNodeEnsured); beginNodeEnsured = beginNodeEnsured.parent; } @@ -1138,18 +1207,17 @@ export class BinaryTree< * Time Complexity: O(log n) * Space Complexity: O(1) * - * The function `getLeftMost` returns the leftmost node in a binary tree, either recursively or - * iteratively. - * @param {K | NODE | null | undefined} beginRoot - The `beginRoot` parameter is the starting point - * for finding the leftmost node in a binary tree. It can be either a `K` (a key value), `NODE` (a - * node), `null`, or `undefined`. If not provided, it defaults to `this.root`, - * @param iterationType - The `iterationType` parameter is used to determine the type of iteration to - * be performed when finding the leftmost node in a binary tree. It can have two possible values: - * @returns The function `getLeftMost` returns the leftmost node (`NODE`) in the binary tree. If there - * is no leftmost node, it returns `null` or `undefined` depending on the input. + * The `getLeftMost` function returns the leftmost node in a binary tree, either using recursive or + * iterative traversal. + * @param {R | KeyOrNodeOrEntry} beginRoot - The `beginRoot` parameter represents the + * starting point for finding the leftmost node in a binary tree. It can be either a root node (`R`), + * a key or node or entry (`KeyOrNodeOrEntry`), or `null` or `undefined`. + * @param {IterationType} iterationType - The `iterationType` parameter is used to specify the type + * of iteration to be performed. It can have two possible values: + * @returns The function `getLeftMost` returns the leftmost node in a binary tree. */ getLeftMost( - beginRoot: KeyOrNodeOrEntry = this.root, + beginRoot: R | KeyOrNodeOrEntry = this.root, iterationType: IterationType = this.iterationType ): NODE | null | undefined { if (this.isNIL(beginRoot)) return beginRoot as NODE; @@ -1184,19 +1252,18 @@ export class BinaryTree< * Time Complexity: O(log n) * Space Complexity: O(1) * - * The function `getRightMost` returns the rightmost node in a binary tree, either recursively or + * The `getRightMost` function returns the rightmost node in a binary tree, either recursively or * iteratively. - * @param {K | NODE | null | undefined} beginRoot - The `beginRoot` parameter represents the - * starting node from which we want to find the rightmost node. It can be of type `K`, `NODE`, - * `null`, or `undefined`. If not provided, it defaults to `this.root`, which is a property of the - * current object. - * @param iterationType - The `iterationType` parameter is an optional parameter that specifies the - * type of iteration to use when finding the rightmost node. It can have one of two values: - * @returns The function `getRightMost` returns the rightmost node (`NODE`) in a binary tree. If there - * is no rightmost node, it returns `null` or `undefined`, depending on the input. + * @param {R | KeyOrNodeOrEntry} beginRoot - The `beginRoot` parameter represents the + * starting point for finding the rightmost node in a binary tree. It can be either a root node + * (`R`), a key or node or entry (`KeyOrNodeOrEntry`), or `null` or `undefined`. + * @param {IterationType} iterationType - The `iterationType` parameter is used to specify the type + * of iteration to be performed when finding the rightmost node in a binary tree. It can have two + * possible values: + * @returns The function `getRightMost` returns a NODE object, `null`, or `undefined`. */ getRightMost( - beginRoot: KeyOrNodeOrEntry = this.root, + beginRoot: R | KeyOrNodeOrEntry = this.root, iterationType: IterationType = this.iterationType ): NODE | null | undefined { if (this.isNIL(beginRoot)) return beginRoot as NODE; @@ -1231,10 +1298,10 @@ export class BinaryTree< * Time Complexity: O(log n) * Space Complexity: O(1) * - * The function returns the predecessor of a given node in a tree. - * @param {NODE} node - The parameter `node` is of type `RedBlackTreeNode`, which represents a node in a + * The function returns the predecessor node of a given node in a binary tree. + * @param {NODE} node - The parameter "node" is of type "NODE", which represents a node in a binary * tree. - * @returns the predecessor of the given 'node'. + * @returns the predecessor node of the given node. */ getPredecessor(node: NODE): NODE { if (this.isRealNode(node.left)) { @@ -1261,8 +1328,8 @@ export class BinaryTree< * * The function `getSuccessor` returns the next node in a binary tree given a current node. * @param {K | NODE | null} [x] - The parameter `x` can be of type `K`, `NODE`, or `null`. - * @returns the successor of the given node or key. The successor is the node that comes immediately - * after the given node in the inorder traversal of the binary tree. + * @returns The function `getSuccessor` returns a `NODE` object if a successor exists, `null` if + * there is no successor, and `undefined` if the input `x` is not a valid node. */ getSuccessor(x?: K | NODE | null): NODE | null | undefined { x = this.ensureNode(x); @@ -1283,7 +1350,7 @@ export class BinaryTree< dfs>( callback?: C, pattern?: DFSOrderPattern, - beginRoot?: KeyOrNodeOrEntry, + beginRoot?: R | KeyOrNodeOrEntry, iterationType?: IterationType, includeNull?: false ): ReturnType[]; @@ -1291,7 +1358,7 @@ export class BinaryTree< dfs>( callback?: C, pattern?: DFSOrderPattern, - beginRoot?: KeyOrNodeOrEntry, + beginRoot?: R | KeyOrNodeOrEntry, iterationType?: IterationType, includeNull?: true ): ReturnType[]; @@ -1299,35 +1366,35 @@ export class BinaryTree< /** * Time complexity: O(n) * Space complexity: O(n) - * / + */ - /** + /** * Time complexity: O(n) * Space complexity: O(n) * - * The `dfs` function performs a depth-first search traversal on a binary tree or graph, based on the - * specified pattern and iteration type, and returns an array of values obtained from applying a - * callback function to each visited node. - * @param {C} callback - The `callback` parameter is a function that will be called for each node in - * the tree during the depth-first search. It takes a single parameter, which can be of type `NODE`, - * `null`, or `undefined`, and returns a value of any type. The default value for this parameter is - * @param {DFSOrderPattern} [pattern=in] - The `pattern` parameter determines the order in which the - * nodes are traversed during the depth-first search. It can have one of the following values: - * @param {K | NODE | null | undefined} beginRoot - The `beginRoot` parameter is the starting node - * for the depth-first search traversal. It can be specified as a key, a node object, or - * `null`/`undefined`. If not provided, the `beginRoot` will default to the root node of the tree. - * @param {IterationType} iterationType - The `iterationType` parameter determines the type of - * iteration to use when traversing the tree. It can have one of the following values: + * The `dfs` function performs a depth-first search traversal on a binary tree, executing a callback + * function on each node according to a specified pattern and iteration type. + * @param {C} callback - The `callback` parameter is a function that will be called for each node + * visited during the depth-first search. It takes a node as an argument and returns a value. The + * return type of the callback function is determined by the generic type `C`. + * @param {DFSOrderPattern} [pattern=IN] - The `pattern` parameter determines the order in which the + * nodes are visited during the depth-first search. It can have one of the following values: + * @param {R | KeyOrNodeOrEntry} beginRoot - The `beginRoot` parameter is the starting + * point of the depth-first search. It can be either a node object, a key-value pair, or a key. If it + * is a key or key-value pair, the method will find the corresponding node in the tree and start the + * search from there. + * @param {IterationType} [iterationType=ITERATIVE] - The `iterationType` parameter determines the + * type of iteration to use during the depth-first search. It can have two possible values: * @param [includeNull=false] - The `includeNull` parameter is a boolean value that determines - * whether null or undefined nodes should be included in the traversal. If `includeNull` is set to - * `true`, null or undefined nodes will be included in the traversal. If `includeNull` is set to - * `false`, null or undefined - * @returns an array of values that are the return values of the callback function. + * whether or not to include null values in the depth-first search traversal. If `includeNull` is set + * to `true`, null values will be included in the traversal. If `includeNull` is set to `false`, null + * values will + * @returns an array of the return types of the callback function. */ dfs>( callback: C = this._DEFAULT_CALLBACK as C, pattern: DFSOrderPattern = 'IN', - beginRoot: KeyOrNodeOrEntry = this.root, + beginRoot: R | KeyOrNodeOrEntry = this.root, iterationType: IterationType = 'ITERATIVE', includeNull = false ): ReturnType[] { @@ -1421,14 +1488,14 @@ export class BinaryTree< bfs>( callback?: C, - beginRoot?: KeyOrNodeOrEntry, + beginRoot?: R | KeyOrNodeOrEntry, iterationType?: IterationType, includeNull?: false ): ReturnType[]; bfs>( callback?: C, - beginRoot?: KeyOrNodeOrEntry, + beginRoot?: R | KeyOrNodeOrEntry, iterationType?: IterationType, includeNull?: true ): ReturnType[]; @@ -1442,26 +1509,27 @@ export class BinaryTree< * Time complexity: O(n) * Space complexity: O(n) * - * The `bfs` function performs a breadth-first search traversal on a binary tree, executing a - * callback function on each node. + * The `bfs` function performs a breadth-first search on a binary tree, calling a callback function + * on each node and returning an array of the results. * @param {C} callback - The `callback` parameter is a function that will be called for each node in - * the breadth-first search traversal. It takes a single parameter, which is the current node being + * the breadth-first search traversal. It takes a single argument, which is the current node being * visited, and returns a value of any type. - * @param {K | NODE | null | undefined} beginRoot - The `beginRoot` parameter represents the - * starting node for the breadth-first search traversal. It can be specified as a key, a node object, - * or `null`/`undefined` to indicate the root of the tree. If not provided, the `root` property of - * the class is used as - * @param iterationType - The `iterationType` parameter determines the type of iteration to be - * performed during the breadth-first search (BFS). It can have two possible values: - * @param [includeNull=false] - The `includeNull` parameter is a boolean flag that determines whether - * to include null values in the breadth-first search traversal. If `includeNull` is set to - * `true`, null values will be included in the traversal, otherwise they will be skipped. - * @returns an array of values that are the result of invoking the callback function on each node in - * the breadth-first traversal of a binary tree. + * @param {R | KeyOrNodeOrEntry} beginRoot - The `beginRoot` parameter represents the + * starting point of the breadth-first search. It can be either a root node of a tree or a key, node, + * or entry object. If no value is provided, the `root` property of the class is used as the default + * starting point. + * @param {IterationType} iterationType - The `iterationType` parameter determines the type of + * iteration to be performed. It can have two possible values: + * @param [includeNull=false] - The `includeNull` parameter is a boolean value that determines + * whether or not to include null values in the breadth-first search (BFS) traversal. If + * `includeNull` is set to `true`, null values will be included in the traversal. If `includeNull` is + * set to `false + * @returns The function `bfs` returns an array of values that are the result of invoking the + * `callback` function on each node in the breadth-first order traversal of the binary tree. */ bfs>( callback: C = this._DEFAULT_CALLBACK as C, - beginRoot: KeyOrNodeOrEntry = this.root, + beginRoot: R | KeyOrNodeOrEntry = this.root, iterationType: IterationType = this.iterationType, includeNull = false ): ReturnType[] { @@ -1515,14 +1583,14 @@ export class BinaryTree< listLevels>( callback?: C, - beginRoot?: KeyOrNodeOrEntry, + beginRoot?: R | KeyOrNodeOrEntry, iterationType?: IterationType, includeNull?: false ): ReturnType[][]; listLevels>( callback?: C, - beginRoot?: KeyOrNodeOrEntry, + beginRoot?: R | KeyOrNodeOrEntry, iterationType?: IterationType, includeNull?: true ): ReturnType[][]; @@ -1537,25 +1605,25 @@ export class BinaryTree< * Space complexity: O(n) * * The `listLevels` function returns an array of arrays, where each inner array represents a level in - * a binary tree and contains the values returned by a callback function applied to the nodes at that - * level. + * a binary tree and contains the results of applying a callback function to the nodes at that level. * @param {C} callback - The `callback` parameter is a function that will be called for each node in - * the tree. It takes a single parameter, which can be of type `NODE`, `null`, or `undefined`, and - * returns a value of any type. - * @param {K | NODE | null | undefined} beginRoot - The `beginRoot` parameter represents the - * starting node for traversing the tree. It can be either a node object (`NODE`), a key value - * (`K`), `null`, or `undefined`. If not provided, it defaults to the root node of the tree. - * @param iterationType - The `iterationType` parameter determines the type of iteration to be - * performed on the tree. It can have two possible values: + * the tree. It takes a node as an argument and returns a value. The return type of the callback + * function is determined by the generic type `C` which extends `BTNCallback`. + * @param {R | KeyOrNodeOrEntry} beginRoot - The `beginRoot` parameter represents the + * starting point for traversing the tree. It can be either a root node, a key-value pair, or a node + * entry. If no value is provided, the `root` property of the class is used as the default starting + * point. + * @param {IterationType} iterationType - The `iterationType` parameter determines the type of + * iteration to be performed on the binary tree. It can have two possible values: * @param [includeNull=false] - The `includeNull` parameter is a boolean value that determines - * whether to include null values in the resulting levels. If `includeNull` is set to `true`, + * whether or not to include null values in the resulting levels. If `includeNull` is set to `true`, * null values will be included in the levels. If `includeNull` is set to `false`, null values will * be excluded * @returns The function `listLevels` returns a two-dimensional array of type `ReturnType[][]`. */ listLevels>( callback: C = this._DEFAULT_CALLBACK as C, - beginRoot: KeyOrNodeOrEntry = this.root, + beginRoot: R | KeyOrNodeOrEntry = this.root, iterationType: IterationType = this.iterationType, includeNull = false ): ReturnType[][] { @@ -1612,22 +1680,22 @@ export class BinaryTree< * 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 - * the tree. It takes a single parameter of type `NODE` (the type of the nodes in the tree) and returns - * a value of any type. - * @param {DFSOrderPattern} [pattern=in] - The `pattern` parameter in the `morris` function - * determines the order in which the nodes of a binary tree are traversed. It can have one of the + * the tree. It takes a single argument, which is the current node, and can return any value. The + * return type of the `callback` function is determined by the `ReturnType` type, which represents + * the return + * @param {DFSOrderPattern} [pattern=IN] - The `pattern` parameter in the `morris` function is used + * to specify the order in which the nodes of a binary tree are traversed. It can take one of the * following values: - * @param {K | NODE | null | undefined} beginRoot - The `beginRoot` parameter is the starting node - * 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 nodes is determined - * by the return type of the `callback` function. + * @param {R | KeyOrNodeOrEntry} beginRoot - The `beginRoot` parameter is the starting + * point for the traversal. It can be either a node object, a key, or an entry object. If no value is + * provided, the `root` of the tree is used as the starting point. + * @returns The function `morris` returns an array of values that are the return values of the + * callback function `callback`. */ morris>( callback: C = this._DEFAULT_CALLBACK as C, pattern: DFSOrderPattern = 'IN', - beginRoot: KeyOrNodeOrEntry = this.root + beginRoot: R | KeyOrNodeOrEntry = this.root ): ReturnType[] { beginRoot = this.ensureNode(beginRoot); if (beginRoot === null) return []; @@ -1719,8 +1787,7 @@ export class BinaryTree< * Time complexity: O(n) * Space complexity: O(n) * - * The `clone` function creates a new tree object and copies all the nodes from the original tree to - * the new tree. + * The `clone` function creates a deep copy of a tree object. * @returns The `clone()` method is returning a cloned instance of the `TREE` object. */ clone(): TREE { @@ -1746,16 +1813,16 @@ export class BinaryTree< * Time Complexity: O(n) * Space Complexity: O(n) * - * 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. - * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value - * to be used as the `this` value when executing the `predicate` function. If `thisArg` is provided, - * it will be passed as the first argument to the `predicate` function. If `thisArg` is - * @returns The `filter` method is returning a new tree object that contains the key-value pairs that - * pass the given predicate function. + * The `filter` function creates a new tree with entries that pass a given predicate function. + * @param predicate - The `predicate` parameter is a callback function that is used to test each + * element in the tree. It takes three arguments: `value`, `key`, and `index`. The `value` argument + * represents the value of the current element being processed, the `key` argument represents the key + * of the + * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that allows you to + * specify the value of `this` within the `predicate` function. When the `predicate` function is + * called, `thisArg` will be used as the value of `this` within the function. If `thisArg` + * @returns The `filter` method is returning a new tree object that contains the entries that pass + * the given predicate function. */ filter(predicate: EntryCallback, thisArg?: any) { const newTree = this.createTree(); @@ -1777,15 +1844,15 @@ export class BinaryTree< * Time Complexity: O(n) * Space Complexity: O(n) * - * The `map` function creates a new tree by applying a callback function to each key-value pair in - * the original tree. - * @param callback - The callback parameter is a function that will be called for each key-value pair - * in the tree. It takes four arguments: the value of the current pair, the key of the current pair, - * the index of the current pair, and a reference to the tree itself. The callback function should - * return a new - * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that allows you to - * specify the value of `this` within the callback function. If you pass a value for `thisArg`, it - * will be used as the `this` value when the callback function is called. If you don't pass a value + * The `map` function creates a new tree by applying a callback function to each entry in the current + * tree. + * @param callback - The callback parameter is a function that will be called for each entry in the + * tree. It takes three arguments: value, key, and index. The value argument represents the value of + * the current entry, the key argument represents the key of the current entry, and the index + * argument represents the index of the + * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value + * to be used as `this` when executing the `callback` function. If `thisArg` is provided, it will be + * passed as the `this` value to the `callback` function. If `thisArg` is * @returns The `map` method is returning a new tree object. */ map(callback: EntryCallback, thisArg?: any) { @@ -1816,13 +1883,17 @@ export class BinaryTree< * 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 | NODE | null | undefined} [beginRoot=this.root] - The `root` parameter is of type `K | NODE | 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. + * The `print` function in TypeScript prints the binary tree structure with customizable options. + * @param {R | KeyOrNodeOrEntry} beginRoot - The `beginRoot` parameter is the starting + * point for printing the binary tree. It can be either a node of the binary tree or a key or entry + * that exists in the binary tree. If no value is provided, the root of the binary tree will be used + * as the starting point. + * @param {BinaryTreePrintOptions} [options] - The `options` parameter is an optional object that + * allows you to customize the printing behavior. It has the following properties: + * @returns Nothing is being returned. The function has a return type of `void`, which means it does + * not return any value. */ - override print(beginRoot: KeyOrNodeOrEntry = this.root, options?: BinaryTreePrintOptions): void { + override print(beginRoot: R | KeyOrNodeOrEntry = this.root, options?: BinaryTreePrintOptions): void { const opts = { isShowUndefined: false, isShowNull: false, isShowRedBlackNIL: false, ...options }; beginRoot = this.ensureNode(beginRoot); if (!beginRoot) return; @@ -1848,13 +1919,19 @@ export class BinaryTree< } /** - * The function `_getIterator` is a protected generator function that returns an iterator for the - * key-value pairs in a binary search tree. - * @param node - The `node` parameter represents the current node in the binary search tree. It is an - * optional parameter with a default value of `this.root`, which means if no node is provided, the - * root node of the tree will be used as the starting point for iteration. - * @returns The function `_getIterator` returns an `IterableIterator` of key-value pairs `[K, V | - * undefined]`. + * Time Complexity: O(1) + * Space Complexity: O(1) + */ + + /** + * Time Complexity: O(1) + * Space Complexity: O(1) + * + * The function `_getIterator` is a generator function that returns an iterator for the key-value + * pairs in a binary search tree. + * @param node - The `node` parameter represents the current node in the binary search tree. It is + * initially set to the root node of the tree. + * @returns an IterableIterator<[K, V | undefined]>. */ protected* _getIterator(node = this.root): IterableIterator<[K, V | undefined]> { if (!node) return; @@ -1888,6 +1965,14 @@ export class BinaryTree< } /** + * Time Complexity: O(n) + * Space Complexity: O(n) + */ + + /** + * Time Complexity: O(n) + * Space Complexity: O(n) + * * The `_displayAux` function is responsible for generating the display layout of a binary tree node, * taking into account various options such as whether to show null, undefined, or NaN nodes. * @param {NODE | null | undefined} node - The `node` parameter represents a node in a binary tree. @@ -1972,14 +2057,26 @@ export class BinaryTree< protected _DEFAULT_CALLBACK = (node: NODE | null | undefined) => (node ? node.key : undefined); /** - * Swap the data of two nodes in the binary tree. - * @param {NODE} srcNode - The source node to swap. - * @param {NODE} destNode - The destination node to swap. - * @returns {NODE} - The destination node after the swap. + * Time Complexity: O(1) + * Space Complexity: O(1) + */ + + /** + * Time Complexity: O(1) + * Space Complexity: O(1) + * + * The function `_swapProperties` swaps the key-value properties between two nodes. + * @param {R | KeyOrNodeOrEntry} srcNode - The source node that will be swapped with the + * destination node. It can be either an instance of the class `R`, or an object of type + * `KeyOrNodeOrEntry`. + * @param {R | KeyOrNodeOrEntry} destNode - The `destNode` parameter is the node where + * the properties will be swapped with the `srcNode`. + * @returns either the `destNode` object with its properties swapped with the `srcNode` object's + * properties, or `undefined` if either `srcNode` or `destNode` is falsy. */ protected _swapProperties( - srcNode: KeyOrNodeOrEntry, - destNode: KeyOrNodeOrEntry + srcNode: R | KeyOrNodeOrEntry, + destNode: R | KeyOrNodeOrEntry ): NODE | undefined { srcNode = this.ensureNode(srcNode); destNode = this.ensureNode(destNode); @@ -2002,12 +2099,21 @@ export class BinaryTree< } /** - * The function replaces an old node with a new node in a binary tree. + * Time Complexity: O(1) + * Space Complexity: O(1) + */ + + /** + * Time Complexity: O(1) + * Space Complexity: O(1) + * + * The function replaces a node in a binary tree with a new node, updating the parent, left child, + * right child, and root if necessary. * @param {NODE} oldNode - The oldNode parameter represents the node that needs to be replaced in the * tree. * @param {NODE} newNode - The `newNode` parameter is the node that will replace the `oldNode` in the * tree. - * @returns The method is returning the newNode. + * @returns the newNode. */ protected _replaceNode(oldNode: NODE, newNode: NODE): NODE { if (oldNode.parent) { @@ -2028,10 +2134,18 @@ export class BinaryTree< } /** - * The function sets the root property of an object to a given value, and if the value is not null, - * it also sets the parent property of the value to undefined. - * @param {NODE | null | undefined} v - The parameter `v` is of type `NODE | null | undefined`, which means it can either be of - * type `NODE` or `null`. + * Time Complexity: O(1) + * Space Complexity: O(1) + */ + + /** + * Time Complexity: O(1) + * Space Complexity: O(1) + * + * The function sets the root property of an object to the provided value, and also updates the + * parent property of the new root. + * @param {NODE | null | undefined} v - The parameter `v` is of type `NODE | null | undefined`. This + * means that it can accept a value of type `NODE`, `null`, or `undefined`. */ protected _setRoot(v: NODE | null | undefined) { if (v) { @@ -2040,6 +2154,24 @@ export class BinaryTree< this._root = v; } + /** + * Time Complexity: O(1) + * Space Complexity: O(1) + */ + + /** + * Time Complexity: O(1) + * Space Complexity: O(1) + * + * The function `_ensureCallback` ensures that a callback function is provided and returns it. + * @param {ReturnType | null | undefined} identifier - The `identifier` parameter is of type + * `ReturnType | null | undefined`. This means it can accept a value that is the return type of + * the generic type `C`, or it can be `null` or `undefined`. + * @param {C} callback - The `callback` parameter is a function that takes a `node` as an argument + * and returns a value. It is of type `C`, which is a generic type that extends the + * `BTNCallback` type. + * @returns the callback parameter. + */ protected _ensureCallback>( identifier: ReturnType | null | undefined, callback: C = this._DEFAULT_CALLBACK as C diff --git a/src/data-structures/binary-tree/bst.ts b/src/data-structures/binary-tree/bst.ts index 77e4ae4..866caba 100644 --- a/src/data-structures/binary-tree/bst.ts +++ b/src/data-structures/binary-tree/bst.ts @@ -11,7 +11,7 @@ import type { BSTNodeNested, BSTOptions, BTNCallback, - BTNodePureExemplar, + BTNPureKeyOrNodeOrEntry, Comparable, Comparator, CP, @@ -19,6 +19,7 @@ import type { IterationType, KeyOrNodeOrEntry } from '../../types'; +import { BTNEntry } from '../../types'; import { BinaryTree, BinaryTreeNode } from './binary-tree'; import { IBinaryTree } from '../../interfaces'; import { Queue } from '../queue'; @@ -95,21 +96,24 @@ export class BSTNode< export class BST< K extends Comparable, V = any, + R = BTNEntry, NODE extends BSTNode = BSTNode>, - TREE extends BST = BST> + TREE extends BST = BST> > - extends BinaryTree - implements IBinaryTree { + extends BinaryTree + implements IBinaryTree { /** - * This is the constructor function for a Binary Search Tree class in TypeScript, which initializes - * the tree with keys, nodes, or entries and optional options. - * @param keysOrNodesOrEntries - The `keysOrNodesOrEntries` parameter is an iterable object that can - * contain keys, nodes, or entries. It is used to initialize the binary search tree with the provided - * keys, nodes, or entries. - * @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: + * This is the constructor function for a Binary Search Tree class in TypeScript. + * @param keysOrNodesOrEntriesOrRawElements - The `keysOrNodesOrEntriesOrRawElements` parameter is an + * iterable that can contain either keys, nodes, entries, or raw elements. These elements will be + * added to the binary search tree during the construction of the object. + * @param [options] - An optional object that contains additional options for the Binary Search Tree. + * It can include a comparator function that defines the order of the elements in the tree. */ - constructor(keysOrNodesOrEntries: Iterable> = [], options?: BSTOptions) { + constructor( + keysOrNodesOrEntriesOrRawElements: Iterable> = [], + options?: BSTOptions + ) { super([], options); if (options) { @@ -117,7 +121,7 @@ export class BST< if (comparator) this._comparator = comparator; } - if (keysOrNodesOrEntries) this.addMany(keysOrNodesOrEntries); + if (keysOrNodesOrEntriesOrRawElements) this.addMany(keysOrNodesOrEntriesOrRawElements); } protected override _root?: NODE = undefined; @@ -130,20 +134,6 @@ export class BST< return this._root; } - protected _comparator: Comparator = (a: K, b: K): CP => { - if (a > b) return 1; - if (a < b) return -1; - return 0; - }; - - /** - * The function returns the value of the _comparator property. - * @returns The `_comparator` property is being returned. - */ - get comparator() { - return this._comparator; - } - /** * The function creates a new BSTNode with the given key and value and returns it. * @param {K} key - The key parameter is of type K, which represents the type of the key for the node @@ -159,13 +149,12 @@ export class BST< /** * The function creates a new binary search tree with the specified options. * @param [options] - The `options` parameter is an optional object that allows you to customize the - * behavior of the `createTree` method. It is of type `Partial>`, which means it is a - * partial object of type `BSTOptions`. - * @returns a new instance of the BST class, with the provided options merged with the default - * options. The returned value is casted as TREE. + * behavior of the `createTree` method. It accepts a partial `BSTOptions` object, which has the + * following properties: + * @returns a new instance of the BST class with the provided options. */ - override createTree(options?: Partial>): TREE { - return new BST([], { + override createTree(options?: Partial>): TREE { + return new BST([], { iterationType: this.iterationType, comparator: this.comparator, ...options @@ -173,97 +162,69 @@ export class BST< } /** - * The function `keyValueOrEntryToNode` takes an keyOrNodeOrEntry and returns a node if the keyOrNodeOrEntry is valid, - * otherwise it returns undefined. - * @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 - * `keyValueOrEntryToNode` function. It represents the value associated with the keyOrNodeOrEntry node. - * @returns a node of type NODE or undefined. + * The function overrides a method and converts a key, value pair or entry or raw element to a node. + * @param {R | KeyOrNodeOrEntry} keyOrNodeOrEntryOrRawElement - A variable that can be of + * type R or KeyOrNodeOrEntry. It represents either a key, a node, an entry, or a raw + * element. + * @param {V} [value] - The `value` parameter is an optional value of type `V`. It represents the + * value associated with a key in a key-value pair. + * @returns either a NODE object or undefined. */ - override keyValueOrEntryToNode(keyOrNodeOrEntry: KeyOrNodeOrEntry, value?: V): NODE | undefined { - let node: NODE | 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); - } - } else if (!this.isNode(keyOrNodeOrEntry)) { - node = this.createNode(keyOrNodeOrEntry, value); - } else { - return; - } - return node; + override keyValueOrEntryOrRawElementToNode( + keyOrNodeOrEntryOrRawElement: R | KeyOrNodeOrEntry, + value?: V + ): NODE | undefined { + return super.keyValueOrEntryOrRawElementToNode(keyOrNodeOrEntryOrRawElement, value) ?? undefined; } - /** - * Time Complexity: O(log n) - * Space Complexity: O(log n) - */ - /** * 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 | NODE | undefined} keyOrNodeOrEntry - The `key` parameter can be of type `K`, `NODE`, 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 `'ITERATIVE'`. - * @returns either a node object (NODE) or undefined. + * The function ensures the existence of a node in a data structure and returns it, or undefined if + * it doesn't exist. + * @param {R | KeyOrNodeOrEntry} keyOrNodeOrEntryOrRawElement - The parameter + * `keyOrNodeOrEntryOrRawElement` can accept a value of type `R`, which represents the key, node, + * entry, or raw element that needs to be ensured in the tree. + * @param {IterationType} [iterationType=ITERATIVE] - The `iterationType` parameter is an optional + * parameter that specifies the type of iteration to be used when ensuring a node. It has a default + * value of `'ITERATIVE'`. + * @returns The method is returning either the node that was ensured or `undefined` if the node could + * not be ensured. */ override ensureNode( - keyOrNodeOrEntry: KeyOrNodeOrEntry, + keyOrNodeOrEntryOrRawElement: R | KeyOrNodeOrEntry, iterationType: IterationType = 'ITERATIVE' ): NODE | undefined { - if (keyOrNodeOrEntry === this.NIL) return; - if (this.isRealNode(keyOrNodeOrEntry)) { - return keyOrNodeOrEntry; - } - - if (this.isEntry(keyOrNodeOrEntry)) { - const key = keyOrNodeOrEntry[0]; - if (key === null || key === undefined) return; - return this.getNodeByKey(key, iterationType); - } - - const key = keyOrNodeOrEntry; - if (key === null || key === undefined) return; - return this.getNodeByKey(key, iterationType); + return super.ensureNode(keyOrNodeOrEntryOrRawElement, iterationType) ?? undefined; } /** - * 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. + * The function checks if the input is an instance of the BSTNode class. + * @param {R | KeyOrNodeOrEntry} keyOrNodeOrEntryOrRawElement - The parameter + * `keyOrNodeOrEntryOrRawElement` can be of type `R` or `KeyOrNodeOrEntry`. + * @returns a boolean value indicating whether the input parameter `keyOrNodeOrEntryOrRawElement` is + * an instance of the `BSTNode` class. */ - override isNode(keyOrNodeOrEntry: KeyOrNodeOrEntry): keyOrNodeOrEntry is NODE { - return keyOrNodeOrEntry instanceof BSTNode; + override isNode( + keyOrNodeOrEntryOrRawElement: R | KeyOrNodeOrEntry + ): keyOrNodeOrEntryOrRawElement is NODE { + return keyOrNodeOrEntryOrRawElement instanceof BSTNode; } - /** - * Time Complexity: O(log n) - * Space Complexity: O(1) - */ - /** * Time Complexity: O(log n) * Space Complexity: O(1) * - * The `add` function in TypeScript adds a new node to a binary search tree based on the key value, - * updating the value if the key already exists. - * @param keyOrNodeOrEntry - It is a parameter that can accept three types of values: - * @param {V} [value] - The value to be added to the binary search tree. - * @returns The method returns a boolean value. + * The `add` function in TypeScript adds a new node to a binary search tree based on the key value. + * @param {R | KeyOrNodeOrEntry} keyOrNodeOrEntryOrRawElement - The parameter + * `keyOrNodeOrEntryOrRawElement` can accept a value of type `R` or `KeyOrNodeOrEntry`. + * @param {V} [value] - The `value` parameter is an optional value that can be associated with the + * key in the binary search tree. If provided, it will be stored in the node along with the key. + * @returns a boolean value. */ - override add(keyOrNodeOrEntry: KeyOrNodeOrEntry, value?: V): boolean { - const newNode = this.keyValueOrEntryToNode(keyOrNodeOrEntry, value); + override add(keyOrNodeOrEntryOrRawElement: R | KeyOrNodeOrEntry, value?: V): boolean { + const newNode = this.keyValueOrEntryOrRawElementToNode(keyOrNodeOrEntryOrRawElement, value); if (newNode === undefined) return false; if (this.root === undefined) { @@ -275,17 +236,8 @@ export class BST< let current = this.root; while (current !== undefined) { if (this.comparator(current.key, newNode.key) === 0) { - // 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 true; - - // } else { - // The key value is the same and the reference is the same, replace the entire node - // this._replaceNode(current, newNode); - - // return; - // } } else if (this.comparator(current.key, newNode.key) > 0) { if (current.left === undefined) { current.left = newNode; @@ -307,19 +259,18 @@ export class BST< } /** - * Time Complexity: O(k log n) - * Space Complexity: O(k + log n) + * Time Complexity: O(log n) + * Space Complexity: O(log n) */ /** * Time Complexity: O(k log n) * Space Complexity: O(k + log n) * - * The `addMany` function in TypeScript adds multiple keys or nodes to a data structure, balancing - * the structure if specified, and returns an array indicating whether each key or node was - * successfully inserted. - * @param keysOrNodesOrEntries - An iterable containing keys, nodes, or entries to be added to the - * data structure. + * The `addMany` function in TypeScript adds multiple keys or nodes to a data structure and returns + * an array indicating whether each key or node was successfully inserted. + * @param keysOrNodesOrEntriesOrRawElements - An iterable containing keys, nodes, entries, or raw + * elements to be added to the data structure. * @param [values] - An optional iterable of values to be associated with the keys or nodes being * added. If provided, the values will be assigned to the corresponding keys or nodes in the same * order. If not provided, undefined will be assigned as the value for each key or node. @@ -328,14 +279,13 @@ export class BST< * algorithm. If set to false, the elements will be added without balancing the tree. The default * value is true. * @param {IterationType} iterationType - The `iterationType` parameter is an optional parameter that - * specifies the type of iteration to use when adding multiple keys or nodes to the binary tree. It - * has a default value of `this.iterationType`, which means it will use the iteration type specified - * in the binary tree instance. - * @returns The function `addMany` returns an array of booleans indicating whether each key or node - * or entry was successfully inserted into the data structure. + * specifies the type of iteration to use when adding multiple keys or nodes to the binary search + * tree. It can have two possible values: + * @returns The function `addMany` returns an array of booleans indicating whether each element was + * successfully inserted into the data structure. */ override addMany( - keysOrNodesOrEntries: Iterable>, + keysOrNodesOrEntriesOrRawElements: Iterable>, values?: Iterable, isBalanceAdd = true, iterationType: IterationType = this.iterationType @@ -349,7 +299,7 @@ export class BST< } if (!isBalanceAdd) { - for (const kve of keysOrNodesOrEntries) { + for (const kve of keysOrNodesOrEntriesOrRawElements) { const value = valuesIterator?.next().value; const nn = this.add(kve, value); inserted.push(nn); @@ -357,29 +307,36 @@ export class BST< return inserted; } - const realBTNExemplars: BTNodePureExemplar[] = []; + const realBTNExemplars: (R | BTNPureKeyOrNodeOrEntry)[] = []; - const isRealBTNExemplar = (kve: KeyOrNodeOrEntry): kve is BTNodePureExemplar => { + const isRealBTNExemplar = (kve: R | KeyOrNodeOrEntry): kve is BTNPureKeyOrNodeOrEntry => { if (kve === undefined || kve === null) return false; return !(this.isEntry(kve) && (kve[0] === undefined || kve[0] === null)); }; - for (const kve of keysOrNodesOrEntries) { + for (const kve of keysOrNodesOrEntriesOrRawElements) { isRealBTNExemplar(kve) && realBTNExemplars.push(kve); } - let sorted: BTNodePureExemplar[] = []; + let sorted: (R | BTNPureKeyOrNodeOrEntry)[] = []; sorted = realBTNExemplars.sort((a, b) => { let keyA: K | undefined | null, keyB: K | undefined | null; - if (this.isEntry(a)) { - keyA = a[0]; - } else if (this.isRealNode(a)) keyA = a.key; - else keyA = a; + if (this.isEntry(a)) keyA = a[0]; + else if (this.isRealNode(a)) keyA = a.key; + else if (this.toEntryFn) { + keyA = this.toEntryFn(a as R)[0]; + } else { + keyA = a as K; + } if (this.isEntry(b)) keyB = b[0]; else if (this.isRealNode(b)) keyB = b.key; - else keyB = b; + else if (this.toEntryFn) { + keyB = this.toEntryFn(b as R)[0]; + } else { + keyB = b as K; + } if (keyA !== undefined && keyA !== null && keyB !== undefined && keyB !== null) { return this.comparator(keyA, keyB); @@ -387,7 +344,7 @@ export class BST< return 0; }); - const _dfs = (arr: BTNodePureExemplar[]) => { + const _dfs = (arr: (R | BTNPureKeyOrNodeOrEntry)[]) => { if (arr.length === 0) return; const mid = Math.floor((arr.length - 1) / 2); @@ -425,38 +382,32 @@ export class BST< } /** - * Time Complexity: O(log n) - * Space Complexity: O(k + log n) - * / - - /** * Time Complexity: O(log n) * Space Complexity: O(k + log n) * - * The function `getNodes` returns an array of nodes that match a given identifier, using either a - * recursive or iterative approach. + * The `getNodes` function in TypeScript retrieves nodes from a binary tree based on a given + * identifier and callback function. * @param {ReturnType | undefined} identifier - The `identifier` parameter is the value that you - * want to search for in the nodes of the binary tree. It can be of any type that is returned by the - * callback function `C`. - * @param {C} callback - The `callback` parameter is a function that takes a node of type `NODE` as its - * argument and returns a value of type `ReturnType`. The `C` type parameter represents a callback - * function type that extends the `BTNCallback` type. The `BTNCallback` type is - * @param [onlyOne=false] - A boolean flag indicating whether to stop searching after finding the - * first node that matches the identifier. If set to true, the function will return an array - * containing only the first matching node. If set to false (default), the function will continue - * searching for all nodes that match the identifier and return an array containing - * @param {K | NODE | undefined} beginRoot - The `beginRoot` parameter represents the starting node - * for the traversal. It can be either a key value or a node object. If it is undefined, the - * traversal will start from the root of the tree. - * @param iterationType - The `iterationType` parameter determines the type of iteration to be - * performed on the binary tree. It can have two possible values: - * @returns The method returns an array of nodes (`NODE[]`). + * want to search for in the binary tree. It can be of any type that is returned by the callback + * function. + * @param {C} callback - The `callback` parameter is a function that takes a node as input and + * returns a value. This value is used to identify the nodes that match the given identifier. The + * `callback` function is optional and defaults to `this._DEFAULT_CALLBACK`. + * @param [onlyOne=false] - A boolean value indicating whether to return only the first matching node + * or all matching nodes. If set to true, only the first matching node will be returned. If set to + * false, all matching nodes will be returned. The default value is false. + * @param {R | KeyOrNodeOrEntry} beginRoot - The `beginRoot` parameter is the starting + * point for the search in the binary tree. It can be either a node object, a key-value pair, or an + * entry object. If it is not provided, the `root` of the binary tree is used as the starting point. + * @param {IterationType} iterationType - The `iterationType` parameter determines the type of + * iteration to be performed. It can have two possible values: + * @returns The method `getNodes` returns an array of `NODE` objects. */ override getNodes>( identifier: ReturnType | undefined, callback: C = this._DEFAULT_CALLBACK as C, onlyOne = false, - beginRoot: KeyOrNodeOrEntry = this.root, + beginRoot: R | KeyOrNodeOrEntry = this.root, iterationType: IterationType = this.iterationType ): NODE[] { beginRoot = this.ensureNode(beginRoot); @@ -524,58 +475,57 @@ export class BST< * Time Complexity: O(log n) * Space Complexity: O(1) * - * The `getNode` function retrieves a node from a Red-Black Tree based on the provided identifier and - * callback function. - * @param {ReturnType | undefined} identifier - The `identifier` parameter is the value or key - * that you want to search for in the binary search tree. It can be of any type that is compatible - * with the type of nodes in the tree. - * @param {C} callback - The `callback` parameter is a function that will be called for each node in - * the tree. It is used to determine whether a node matches the given identifier. The `callback` - * function should take a node as its parameter and return a value that can be compared to the - * `identifier` parameter. + * The function `getNode` returns the first node that matches the given identifier and callback + * function in a binary search tree. + * @param {ReturnType | undefined} identifier - The `identifier` parameter is the value that you + * want to search for in the binary search tree. It can be of any type that is compatible with the + * type returned by the callback function. + * @param {C} callback - The `callback` parameter is a function that will be used to determine if a + * node matches the desired criteria. It should be a function that takes a node as an argument and + * returns a boolean value indicating whether the node matches the criteria or not. If no callback is + * provided, the default callback will be * @param beginRoot - The `beginRoot` parameter is the starting point for the search in the binary - * search tree. It can be either a key or a node. If it is a key, it will be converted to a node - * using the `ensureNode` method. If it is not provided, the `root` - * @param iterationType - The `iterationType` parameter is used to specify the type of iteration to - * be performed when searching for nodes in the binary search tree. It is an optional parameter and - * its default value is taken from the `iterationType` property of the class. - * @returns The method is returning a value of type `NODE | null | undefined`. + * search tree. It can be either a key or a node. If it is a key, the search will start from the node + * with that key. If it is a node, the search will start from that node. + * @param {IterationType} iterationType - The `iterationType` parameter is used to specify the type + * of iteration to be performed when searching for nodes in the binary search tree. It can have one + * of the following values: + * @returns The method is returning a NODE object or undefined. */ override getNode>( identifier: ReturnType | undefined, callback: C = this._DEFAULT_CALLBACK as C, - beginRoot: BSTNKeyOrNode = this.root, + beginRoot: R | BSTNKeyOrNode = this.root, iterationType: IterationType = this.iterationType ): NODE | undefined { return this.getNodes(identifier, callback, true, beginRoot, iterationType)[0] ?? undefined; } /** - * Time Complexity: O(log n) - * Space Complexity: O(1) + * Time Complexity: O(k log n) + * Space Complexity: O(k + log n) */ /** * 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. - * @param {K} key - The `key` parameter is the key value that we are searching for in the tree. - * It is used to identify the node that we want to retrieve. - * @param iterationType - The `iterationType` parameter is an optional parameter that specifies the - * type of iteration to use when searching for a node in the binary tree. It can have two possible - * values: - * @returns The function `getNodeByKey` returns a node (`NODE`) if a node with the specified key is - * found in the binary tree. If no node is found, it returns `undefined`. + * The function `getNodeByKey` returns a node with a specific key from a tree data structure. + * @param {K} key - The key parameter is the value used to search for a specific node in the tree. It + * is typically a unique identifier or a value that can be used to determine the position of the node + * in the tree structure. + * @param {IterationType} [iterationType=ITERATIVE] - The `iterationType` parameter is an optional + * parameter that specifies the type of iteration to be used when searching for a node in the tree. + * It has a default value of `'ITERATIVE'`. + * @returns The method is returning a NODE object or undefined. */ override getNodeByKey(key: K, iterationType: IterationType = 'ITERATIVE'): NODE | undefined { return this.getNode(key, this._DEFAULT_CALLBACK, this.root, iterationType); } /** - * Time complexity: O(n) - * Space complexity: O(n) + * Time Complexity: O(log n) + * Space Complexity: O(k + log n) */ /** @@ -585,30 +535,31 @@ export class BST< * The function overrides the depth-first search method and returns an array of the return types of * the callback function. * @param {C} callback - The `callback` parameter is a function that will be called for each node - * during the depth-first search traversal. It is an optional parameter and if not provided, a - * default callback function will be used. - * @param {DFSOrderPattern} [pattern=in] - The `pattern` parameter specifies the order in which the - * nodes are visited during the depth-first search. It can have one of the following values: - * @param beginRoot - The `beginRoot` parameter is used to specify the starting point for the - * Depth-First Search (DFS) traversal. It can be either a key, a node, or an entry in the tree. If no - * value is provided, the DFS traversal will start from the root of the tree. - * @param {IterationType} iterationType - The `iterationType` parameter specifies the type of - * iteration to be used during the Depth-First Search (DFS) traversal. It can have one of the + * during the depth-first search traversal. It is an optional parameter and defaults to + * `this._DEFAULT_CALLBACK`. The type `C` represents the type of the callback function. + * @param {DFSOrderPattern} [pattern=IN] - The "pattern" parameter in the code snippet refers to the + * order in which the Depth-First Search (DFS) algorithm visits the nodes in a tree or graph. It can + * take one of the following values: + * @param {R | KeyOrNodeOrEntry} beginRoot - The `beginRoot` parameter is the starting + * point for the depth-first search traversal. It can be either a root node, a key-value pair, or a + * node entry. If not specified, the default value is the root of the tree. + * @param {IterationType} [iterationType=ITERATIVE] - The `iterationType` parameter specifies the + * type of iteration to be used during the Depth-First Search (DFS) traversal. It can have one of the * following values: * @returns The method is returning an array of the return type of the callback function. */ override dfs>( callback: C = this._DEFAULT_CALLBACK as C, pattern: DFSOrderPattern = 'IN', - beginRoot: KeyOrNodeOrEntry = this.root, + beginRoot: R | KeyOrNodeOrEntry = this.root, iterationType: IterationType = 'ITERATIVE' ): ReturnType[] { return super.dfs(callback, pattern, beginRoot, iterationType, false); } /** - * Time complexity: O(n) - * Space complexity: O(n) + * Time Complexity: O(log n) + * Space Complexity: O(1) */ /** @@ -618,85 +569,85 @@ export class BST< * The function overrides the breadth-first search method and returns an array of the return types of * the callback function. * @param {C} callback - The `callback` parameter is a function that will be called for each node - * visited during the breadth-first search traversal. It is an optional parameter and if not - * provided, a default callback function will be used. - * @param beginRoot - The `beginRoot` parameter is the starting point for the breadth-first search - * traversal. It can be either a key, a node, or an entry in the tree. If not specified, the root of - * the tree is used as the starting point. - * @param iterationType - The `iterationType` parameter is used to specify the type of iteration to - * be performed during the breadth-first search (BFS) traversal. It determines the order in which the - * nodes are visited. - * @returns The method is returning an array of the return type of the callback function. + * visited during the breadth-first search. It should take a single argument, which is the current + * node being visited, and it can return a value of any type. + * @param {R | KeyOrNodeOrEntry} beginRoot - The `beginRoot` parameter is the starting + * point for the breadth-first search. It can be either a root node, a key-value pair, or an entry + * object. If no value is provided, the default value is the root of the tree. + * @param {IterationType} iterationType - The `iterationType` parameter is used to specify the type + * of iteration to be performed during the breadth-first search (BFS) traversal. It can have one of + * the following values: + * @returns an array of the return type of the callback function. */ override bfs>( callback: C = this._DEFAULT_CALLBACK as C, - beginRoot: KeyOrNodeOrEntry = this.root, + beginRoot: R | KeyOrNodeOrEntry = this.root, iterationType: IterationType = this.iterationType ): ReturnType[] { return super.bfs(callback, beginRoot, iterationType, false); } /** - * Time complexity: O(n) - * Space complexity: O(n) + * Time Complexity: O(log n) + * Space Complexity: O(1) */ /** * Time complexity: O(n) * Space complexity: O(n) * - * The function overrides the listLevels method and returns an array of arrays containing the return - * type of the callback function for each level of the tree. + * The function overrides the listLevels method from the superclass and returns an array of arrays + * containing the results of the callback function applied to each level of the tree. * @param {C} callback - The `callback` parameter is a generic type `C` that extends - * `BTNCallback`. It represents a callback function that will be called for each node in the tree - * during the level listing process. - * @param beginRoot - The `beginRoot` parameter is used to specify the starting point for listing the - * levels of a binary tree. It can be either a key, a node, or an entry in the binary tree. If not - * provided, the root of the binary tree is used as the starting point. - * @param iterationType - The `iterationType` parameter is used to specify the type of iteration to - * be performed on the tree. It determines the order in which the nodes are visited during the - * iteration. + * `BTNCallback`. It represents a callback function that will be called for each node in the + * tree during the iteration process. + * @param {R | KeyOrNodeOrEntry} beginRoot - The `beginRoot` parameter is the starting + * point for listing the levels of the binary tree. It can be either a root node of the tree, a + * key-value pair representing a node in the tree, or a key representing a node in the tree. If no + * value is provided, the root of + * @param {IterationType} iterationType - The `iterationType` parameter is used to specify the type + * of iteration to be performed on the tree. It can have one of the following values: * @returns The method is returning a two-dimensional array of the return type of the callback * function. */ override listLevels>( callback: C = this._DEFAULT_CALLBACK as C, - beginRoot: KeyOrNodeOrEntry = this.root, + beginRoot: R | KeyOrNodeOrEntry = this.root, iterationType: IterationType = this.iterationType ): ReturnType[][] { return super.listLevels(callback, beginRoot, iterationType, false); } /** - * Time Complexity: O(log n) - * Space Complexity: O(log n) + * Time complexity: O(n) + * Space complexity: O(n) */ /** - * Time Complexity: O(log n) - * Space Complexity: O(log n) + * Time complexity: O(n) + * Space complexity: O(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. + * The `lesserOrGreaterTraverse` function traverses a binary tree and applies a callback function to + * each node that meets a certain condition based on a target node and a comparison value. * @param {C} callback - The `callback` parameter is a function that will be called for each node - * that satisfies the condition specified by the `lesserOrGreater` parameter. It takes a single - * parameter of type `NODE` (the node type) and returns a value of any type. + * that meets the condition specified by the `lesserOrGreater` parameter. It takes a single argument, + * which is the current node being traversed, and returns a value of any type. * @param {CP} lesserOrGreater - The `lesserOrGreater` parameter is used to determine whether to - * traverse nodes that are lesser than, greater than, or equal to the `targetNode`. It is of type - * `CP`, which is a custom type representing the comparison operator. The possible values for - * `lesserOrGreater` are - * @param {K | NODE | undefined} targetNode - The `targetNode` parameter represents the node in the - * binary tree that you want to traverse from. It can be specified either by its key, by the node - * object itself, or it can be left undefined to start the traversal from the root of the tree. - * @param iterationType - The `iterationType` parameter determines the type of traversal to be - * performed on the binary tree. It can have two possible values: + * traverse nodes that are lesser, greater, or both than the `targetNode`. It accepts the values -1, + * 0, or 1, where: + * @param {R | KeyOrNodeOrEntry} targetNode - The `targetNode` parameter is the node in + * the binary tree that you want to start traversing from. It can be specified either by providing + * the key of the node, the node itself, or an entry containing the key and value of the node. If no + * `targetNode` is provided, + * @param {IterationType} iterationType - The `iterationType` parameter determines the type of + * traversal to be performed on the binary tree. It can have two possible values: * @returns The function `lesserOrGreaterTraverse` returns an array of values of type * `ReturnType`, which is the return type of the callback function passed as an argument. */ lesserOrGreaterTraverse>( callback: C = this._DEFAULT_CALLBACK as C, lesserOrGreater: CP = -1, - targetNode: KeyOrNodeOrEntry = this.root, + targetNode: R | KeyOrNodeOrEntry = this.root, iterationType: IterationType = this.iterationType ): ReturnType[] { const targetNodeEnsured = this.ensureNode(targetNode); @@ -734,19 +685,20 @@ export class BST< } /** - * Time Complexity: O(log n) - * Space Complexity: O(log n) + * Time complexity: O(n) + * Space complexity: O(n) */ /** - * Time Complexity: O(log n) - * Space Complexity: O(log n) + * Time complexity: O(n) + * Space complexity: O(n) * - * The `perfectlyBalance` function balances a binary search tree by adding nodes in a way that - * ensures the tree is perfectly balanced. - * @param iterationType - The `iterationType` parameter is an optional parameter that specifies the - * type of iteration to use when building a balanced binary search tree. It can have two possible - * values: + * The `perfectlyBalance` function takes an optional `iterationType` parameter and returns `true` if + * the binary search tree is perfectly balanced, otherwise it returns `false`. + * @param {IterationType} iterationType - The `iterationType` parameter is an optional parameter that + * specifies the type of iteration to use when building a balanced binary search tree. It has a + * default value of `this.iterationType`, which means it will use the iteration type specified in the + * current instance of the class. * @returns The function `perfectlyBalance` returns a boolean value. */ perfectlyBalance(iterationType: IterationType = this.iterationType): boolean { @@ -787,27 +739,20 @@ export class BST< } /** - * Balancing Adjustment: - * Perfectly Balanced Binary Tree: Since the balance of a perfectly balanced binary tree is already fixed, no additional balancing adjustment is needed. Any insertion or deletion operation will disrupt the perfect balance, often requiring a complete reconstruction of the tree. - * AVL Tree: After insertion or deletion operations, an AVL tree performs rotation adjustments based on the balance factor of nodes to restore the tree's balance. These rotations can be left rotations, right rotations, left-right rotations, or right-left rotations, performed as needed. - * - * Use Cases and Efficiency: - * Perfectly Balanced Binary Tree: Perfectly balanced binary trees are typically used in specific scenarios such as complete binary heaps in heap sort or certain types of Huffman trees. However, they are not suitable for dynamic operations requiring frequent insertions and deletions, as these operations often necessitate full tree reconstruction. - * AVL Tree: AVL trees are well-suited for scenarios involving frequent searching, insertion, and deletion operations. Through rotation adjustments, AVL trees maintain their balance, ensuring average and worst-case time complexity of O(log n). - */ - - /** - * Time Complexity: O(n) - * Space Complexity: O(log n) + * Time complexity: O(n) + * Space complexity: O(n) */ /** * 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 - * to check if the AVL tree is balanced. It can have two possible values: + * The function `isAVLBalanced` checks if a binary tree is AVL balanced using either a recursive or + * iterative approach. + * @param {IterationType} iterationType - The `iterationType` parameter is an optional parameter that + * specifies the type of iteration to use when checking if the AVL tree is balanced. It has a default + * value of `this.iterationType`, which means it will use the iteration type specified in the current + * instance of the AVL tree. * @returns a boolean value. */ isAVLBalanced(iterationType: IterationType = this.iterationType): boolean { @@ -855,9 +800,45 @@ export class BST< } /** - * The function sets the root property of an object and updates the parent property of the new root. - * @param {NODE | undefined} v - The parameter `v` is of type `NODE | undefined`. This means that it - * can either be an object of type `NODE` or it can be `undefined`. + * Time complexity: O(n) + * Space complexity: O(n) + */ + + protected _DEFAULT_COMPARATOR = (a: K, b: K): number => { + if (typeof a === 'object' && typeof b === 'object' && this.comparator === this._DEFAULT_COMPARATOR) { + throw TypeError( + 'When comparing two object types, it is necessary to customize a [comparator] function of options parameter during the instantiation of the data structure.' + ); + } + if (a > b) return 1; + if (a < b) return -1; + return 0; + }; + + /** + * Time complexity: O(n) + * Space complexity: O(n) + */ + + protected _comparator: Comparator = this._DEFAULT_COMPARATOR; + + /** + * Time Complexity: O(n) + * Space Complexity: O(log n) + */ + + /** + * The function returns the value of the _comparator property. + * @returns The `_comparator` property is being returned. + */ + get comparator() { + return this._comparator; + } + + /** + * The function sets the root of a tree-like structure and updates the parent property of the new + * root. + * @param {NODE | undefined} v - v is a parameter of type NODE or undefined. */ protected override _setRoot(v: NODE | undefined) { if (v) { diff --git a/src/data-structures/binary-tree/rb-tree.ts b/src/data-structures/binary-tree/rb-tree.ts index 50536be..c17c84e 100644 --- a/src/data-structures/binary-tree/rb-tree.ts +++ b/src/data-structures/binary-tree/rb-tree.ts @@ -9,6 +9,7 @@ import type { RedBlackTreeNested, RedBlackTreeNodeNested } from '../../types'; +import { BTNEntry } from '../../types'; import { BST, BSTNode } from './bst'; import { IBinaryTree } from '../../interfaces'; @@ -55,28 +56,32 @@ export class RedBlackTreeNode< export class RedBlackTree< K extends Comparable, V = any, + R = BTNEntry, NODE extends RedBlackTreeNode = RedBlackTreeNode>, - TREE extends RedBlackTree = RedBlackTree> + TREE extends RedBlackTree = RedBlackTree> > - extends BST - implements IBinaryTree { + extends BST + implements IBinaryTree { /** * This is the constructor function for a Red-Black Tree data structure in TypeScript. - * @param keysOrNodesOrEntries - The `keysOrNodesOrEntries` parameter is an iterable object that can - * contain keys, nodes, or entries. It is used to initialize the RBTree with the provided keys, - * nodes, or entries. + * @param keysOrNodesOrEntriesOrRawElements - The `keysOrNodesOrEntriesOrRawElements` parameter is an + * iterable object that can contain either keys, nodes, entries, or raw elements. It is used to + * initialize the RBTree with the provided elements. * @param [options] - The `options` parameter is an optional object that can be passed to the - * constructor. It allows you to customize the behavior of the RBTree. It can include properties such - * as `compareKeys`, `compareValues`, `allowDuplicates`, etc. These properties define how the RBTree - * should compare keys and + * constructor. It is of type `RBTreeOptions`. This object can contain various options for + * configuring the behavior of the Red-Black Tree. The specific properties and their meanings would + * depend on the implementation */ - constructor(keysOrNodesOrEntries: Iterable> = [], options?: RBTreeOptions) { + constructor( + keysOrNodesOrEntriesOrRawElements: Iterable> = [], + options?: RBTreeOptions + ) { super([], options); this._root = this.NIL; - if (keysOrNodesOrEntries) { - this.addMany(keysOrNodesOrEntries); + if (keysOrNodesOrEntriesOrRawElements) { + this.addMany(keysOrNodesOrEntriesOrRawElements); } } @@ -92,29 +97,30 @@ export class RedBlackTree< /** * The function creates a new Red-Black Tree node with the specified key, value, and color. - * @param {K} key - The key parameter represents the key of the node being created. It is of type K, - * which is a generic type representing the key's data type. + * @param {K} key - The key parameter represents the key value of the node being created. It is of + * type K, which is a generic type that can be replaced with any specific type when using the + * function. * @param {V} [value] - The `value` parameter is an optional parameter that represents the value - * associated with the key in the node. It is not required and can be omitted if not needed. - * @param {RBTNColor} color - The "color" parameter is used to specify the color of the node in a - * Red-Black Tree. It is an optional parameter with a default value of "'BLACK'". The color - * can be either "'RED'" or "'BLACK'". - * @returns The method is returning a new instance of a RedBlackTreeNode with the specified key, - * value, and color. + * associated with the key in the node. It is not required and can be omitted if you only need to + * create a node with a key. + * @param {RBTNColor} [color=BLACK] - The "color" parameter is used to specify the color of the node + * in a Red-Black Tree. It can have two possible values: "RED" or "BLACK". By default, the color is + * set to "BLACK" if not specified. + * @returns A new instance of a RedBlackTreeNode with the specified key, value, and color is being + * returned. */ override createNode(key: K, value?: V, color: RBTNColor = 'BLACK'): NODE { return new RedBlackTreeNode(key, value, color) as NODE; } /** - * The function creates a Red-Black Tree with the given options and returns it. - * @param [options] - The `options` parameter is an optional object that contains configuration - * options for creating the Red-Black Tree. It is of type `RBTreeOptions`, where `K` represents - * the type of keys in the tree. + * The function creates a new Red-Black Tree with the specified options. + * @param [options] - The `options` parameter is an optional object that contains additional + * configuration options for creating the Red-Black Tree. It has the following properties: * @returns a new instance of a RedBlackTree object. */ - override createTree(options?: RBTreeOptions): TREE { - return new RedBlackTree([], { + override createTree(options?: RBTreeOptions): TREE { + return new RedBlackTree([], { iterationType: this.iterationType, ...options }) as TREE; @@ -126,54 +132,57 @@ export class RedBlackTree< */ /** - * Time Complexity: O(1) - * Space Complexity: O(1) - * - * The function `keyValueOrEntryToNode` takes a key, value, or entry and returns a node if it is - * valid, otherwise it returns undefined. - * @param {KeyOrNodeOrEntry} keyOrNodeOrEntry - The key, value, or entry to convert. - * @param {V} [value] - The value associated with the key (if `keyOrNodeOrEntry` is a key). - * @returns {NODE | undefined} - The corresponding Red-Black Tree node, or `undefined` if conversion fails. - */ - override keyValueOrEntryToNode(keyOrNodeOrEntry: KeyOrNodeOrEntry, value?: V): NODE | undefined { - let node: NODE | 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, 'RED'); - } - } else if (!this.isNode(keyOrNodeOrEntry)) { - node = this.createNode(keyOrNodeOrEntry, value, 'RED'); - } else { - return; - } - return node; - } - - /** - * Time Complexity: O(1) - * Space Complexity: O(1) - * / - - /** * Time Complexity: O(1) * Space Complexity: O(1) * * The function checks if the input is an instance of the RedBlackTreeNode class. - * @param {KeyOrNodeOrEntry} keyOrNodeOrEntry - The object to check. - * @returns {boolean} - `true` if the object is a Red-Black Tree node, `false` otherwise. + * @param {R | KeyOrNodeOrEntry} keyOrNodeOrEntryOrRawElement - The parameter + * `keyOrNodeOrEntryOrRawElement` can be of type `R` or `KeyOrNodeOrEntry`. + * @returns a boolean value indicating whether the input parameter `keyOrNodeOrEntryOrRawElement` is + * an instance of the `RedBlackTreeNode` class. */ - override isNode(keyOrNodeOrEntry: KeyOrNodeOrEntry): keyOrNodeOrEntry is NODE { - return keyOrNodeOrEntry instanceof RedBlackTreeNode; + override isNode( + keyOrNodeOrEntryOrRawElement: R | KeyOrNodeOrEntry + ): keyOrNodeOrEntryOrRawElement is NODE { + return keyOrNodeOrEntryOrRawElement instanceof RedBlackTreeNode; } + // /** + // * Time Complexity: O(1) + // * Space Complexity: O(1) + // */ + // + // /** + // * Time Complexity: O(1) + // * Space Complexity: O(1) + // * + // * The function `keyValueOrEntryOrRawElementToNode` takes a key, value, or entry and returns a node if it is + // * valid, otherwise it returns undefined. + // * @param {KeyOrNodeOrEntry} keyOrNodeOrEntryOrRawElement - The key, value, or entry to convert. + // * @param {V} [value] - The value associated with the key (if `keyOrNodeOrEntryOrRawElement` is a key). + // * @returns {NODE | undefined} - The corresponding Red-Black Tree node, or `undefined` if conversion fails. + // */ + // override keyValueOrEntryOrRawElementToNode(keyOrNodeOrEntryOrRawElement: R | KeyOrNodeOrEntry, value?: V): NODE | undefined { + // + // if (keyOrNodeOrEntryOrRawElement === null || keyOrNodeOrEntryOrRawElement === undefined) return; + // if (this.isNode(keyOrNodeOrEntryOrRawElement)) return keyOrNodeOrEntryOrRawElement; + // + // if (this.toEntryFn) { + // const [key, entryValue] = this.toEntryFn(keyOrNodeOrEntryOrRawElement as R); + // if (key) return this.createNode(key, entryValue ?? value, 'RED'); + // } + // + // if (this.isEntry(keyOrNodeOrEntryOrRawElement)) { + // const [key, value] = keyOrNodeOrEntryOrRawElement; + // if (key === undefined || key === null) return; + // else return this.createNode(key, value, 'RED'); + // } + // + // if (this.isKey(keyOrNodeOrEntryOrRawElement)) return this.createNode(keyOrNodeOrEntryOrRawElement, value, 'RED'); + // + // return ; + // } + /** * Time Complexity: O(1) * Space Complexity: O(1) @@ -200,17 +209,19 @@ export class RedBlackTree< * Time Complexity: O(log n) * Space Complexity: O(1) * - * The function adds a new node to a Red-Black Tree data structure and returns a boolean indicating - * whether the operation was successful. - * @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter can be either a key, a node, or an - * entry. - * @param {V} [value] - The `value` parameter is the value associated with the key that is being - * added to the tree. - * @returns The method is returning a boolean value. It returns true if the node was successfully - * added or updated, and false otherwise. + * The function adds a new node to a binary search tree and returns true if the node was successfully + * added. + * @param {R | KeyOrNodeOrEntry} keyOrNodeOrEntryOrRawElement - The parameter + * `keyOrNodeOrEntryOrRawElement` can accept a value of type `R` or `KeyOrNodeOrEntry`. + * @param {V} [value] - The `value` parameter is an optional value that you want to associate with + * the key in the data structure. It represents the value that you want to add or update in the data + * structure. + * @returns The method is returning a boolean value. If a new node is successfully added to the tree, + * the method returns true. If the node already exists and its value is updated, the method also + * returns true. If the node cannot be added or updated, the method returns false. */ - override add(keyOrNodeOrEntry: KeyOrNodeOrEntry, value?: V): boolean { - const newNode = this.keyValueOrEntryToNode(keyOrNodeOrEntry, value); + override add(keyOrNodeOrEntryOrRawElement: R | KeyOrNodeOrEntry, value?: V): boolean { + const newNode = this.keyValueOrEntryOrRawElementToNode(keyOrNodeOrEntryOrRawElement, value); if (!this.isRealNode(newNode)) return false; const insertStatus = this._insert(newNode); @@ -236,16 +247,16 @@ export class RedBlackTree< * Time Complexity: O(log n) * Space Complexity: O(1) * - * The function `delete` in a binary tree class deletes a node from the tree and fixes the tree if - * necessary. - * @param {ReturnType | null | undefined} identifier - The `identifier` parameter is the - * identifier of the node that needs to be deleted from the binary tree. It can be of any type that - * is returned by the callback function `C`. It can also be `null` or `undefined` if the node to be - * deleted is not found. - * @param {C} callback - The `callback` parameter is a function that is used to retrieve a node from - * the binary tree based on its identifier. It is an optional parameter and if not provided, the - * `_DEFAULT_CALLBACK` function is used as the default callback. The callback function should - * return the identifier of the node to + * The function overrides the delete method of a binary tree data structure, allowing for the + * deletion of a node and maintaining the balance of the tree. + * @param {ReturnType | null | undefined} identifier - The `identifier` parameter is the value + * that identifies the node to be deleted from the binary tree. It can be of any type that is + * returned by the callback function `C`. It can also be `null` or `undefined` if there is no node to + * delete. + * @param {C} callback - The `callback` parameter is a function that is used to determine the + * equality of nodes in the binary tree. It is optional and has a default value of + * `this._DEFAULT_CALLBACK`. The type of the `callback` parameter is `C`, which is a generic type + * that extends the `BTNCallback * @returns an array of BinaryTreeDeleteResult objects. */ override delete>( @@ -309,6 +320,14 @@ export class RedBlackTree< } /** + * Time Complexity: O(1) + * Space Complexity: O(1) + */ + + /** + * Time Complexity: O(1) + * Space Complexity: O(1) + * * The function sets the root of a tree-like structure and updates the parent property of the new * root. * @param {NODE | undefined} v - v is a parameter of type NODE or undefined. @@ -332,8 +351,8 @@ export class RedBlackTree< * The function replaces an old node with a new node while preserving the color of the old node. * @param {NODE} oldNode - The `oldNode` parameter represents the node that needs to be replaced in * the data structure. - * @param {NODE} newNode - The `newNode` parameter is the new node that will replace the old node in - * the data structure. + * @param {NODE} newNode - The `newNode` parameter is of type `NODE`, which represents a node in a + * data structure. * @returns The method is returning the result of calling the `_replaceNode` method from the * superclass, with the `oldNode` and `newNode` parameters. */ @@ -352,12 +371,13 @@ export class RedBlackTree< * Time Complexity: O(log n) * Space Complexity: O(1) * - * The `_insert` function inserts or updates a node in a binary search tree and performs necessary - * fix-ups to maintain the red-black tree properties. - * @param {NODE} node - The `node` parameter represents the node that needs to be inserted into a - * binary search tree. It contains a `key` property that is used to determine the position of the - * node in the tree. - * @returns {'inserted' | 'updated'} - The result of the insertion. + * The `_insert` function inserts a node into a binary search tree and performs necessary fix-ups to + * maintain the red-black tree properties. + * @param {NODE} node - The `node` parameter represents the node that needs to be inserted into the + * binary search tree. + * @returns a string value indicating the result of the insertion operation. It can return either + * 'UPDATED' if the node with the same key already exists and was updated, or 'CREATED' if a new node + * was created and inserted into the tree. */ protected _insert(node: NODE): CRUD { let current = this.root; @@ -432,8 +452,8 @@ export class RedBlackTree< * Space Complexity: O(1) * * The `_insertFixup` function is used to fix the Red-Black Tree after inserting a new node. - * @param {NODE | undefined} z - The parameter `z` represents a node in the Red-Black Tree. It can - * either be a valid node object or `undefined`. + * @param {NODE | undefined} z - The parameter `z` represents a node in the Red-Black Tree data + * structure. It can either be a valid node or `undefined`. */ protected _insertFixup(z: NODE | undefined): void { // Continue fixing the tree as long as the parent of z is red @@ -504,9 +524,10 @@ export class RedBlackTree< * * The `_deleteFixup` function is used to fix the red-black tree after a node deletion by adjusting * the colors and performing rotations. - * @param {NODE | undefined} node - The `node` parameter represents a node in a Red-Black Tree data - * structure. It can be either a valid node object or `undefined`. - * @returns The function does not return any value. It has a return type of `void`. + * @param {NODE | undefined} node - The `node` parameter represents a node in a binary tree. It can + * be either a valid node object or `undefined`. + * @returns The function does not return any value. It has a return type of `void`, which means it + * does not return anything. */ protected _deleteFixup(node: NODE | undefined): void { // Early exit condition diff --git a/src/data-structures/binary-tree/tree-multi-map.ts b/src/data-structures/binary-tree/tree-multi-map.ts index 1cad83c..a704865 100644 --- a/src/data-structures/binary-tree/tree-multi-map.ts +++ b/src/data-structures/binary-tree/tree-multi-map.ts @@ -17,6 +17,7 @@ import type { TreeMultiMapNodeNested, TreeMultiMapOptions } from '../../types'; +import { BTNEntry } from '../../types'; import { IBinaryTree } from '../../interfaces'; import { RedBlackTree, RedBlackTreeNode } from './rb-tree'; @@ -65,23 +66,27 @@ export class TreeMultiMapNode< export class TreeMultiMap< K extends Comparable, V = any, + R = BTNEntry, NODE extends TreeMultiMapNode = TreeMultiMapNode>, - TREE extends TreeMultiMap = TreeMultiMap> + TREE extends TreeMultiMap = TreeMultiMap> > - extends RedBlackTree - implements IBinaryTree { + extends RedBlackTree + implements IBinaryTree { /** - * The constructor function initializes a new instance of the TreeMultiMap class with optional - * initial keys, nodes, or entries. - * @param keysOrNodesOrEntries - The `keysOrNodesOrEntries` parameter is an iterable object that can - * contain keys, nodes, or entries. It is used to initialize the TreeMultiMap with the provided keys, - * nodes, or entries. - * @param [options] - The `options` parameter is an optional object that can be passed to the - * constructor. It allows you to customize the behavior of the `TreeMultiMap` instance. + * The constructor function initializes a TreeMultiMap object with optional initial data. + * @param keysOrNodesOrEntriesOrRawElements - The parameter `keysOrNodesOrEntriesOrRawElements` is an + * iterable that can contain keys, nodes, entries, or raw elements. It is used to initialize the + * TreeMultiMap with initial data. + * @param [options] - The `options` parameter is an optional object that can be used to customize the + * behavior of the `TreeMultiMap` constructor. It can include properties such as `compareKeys` and + * `compareValues`, which are functions used to compare keys and values respectively. */ - constructor(keysOrNodesOrEntries: Iterable> = [], options?: TreeMultiMapOptions) { + constructor( + keysOrNodesOrEntriesOrRawElements: Iterable> = [], + options?: TreeMultiMapOptions + ) { super([], options); - if (keysOrNodesOrEntries) this.addMany(keysOrNodesOrEntries); + if (keysOrNodesOrEntriesOrRawElements) this.addMany(keysOrNodesOrEntriesOrRawElements); } protected _count = 0; @@ -117,16 +122,15 @@ export class TreeMultiMap< /** * The function creates a new TreeMultiMapNode with the specified key, value, color, and count. * @param {K} key - The key parameter represents the key of the node being created. It is of type K, - * which is a generic type representing the key type of the node. - * @param {V} [value] - The `value` parameter represents the value associated with the key in the - * node. It is an optional parameter, which means it can be omitted when calling the `createNode` - * function. If provided, it should be of type `V`. + * which is a generic type representing the type of keys in the tree. + * @param {V} [value] - The `value` parameter is an optional parameter that represents the value + * associated with the key in the node. It is of type `V`, which can be any data type. * @param {RBTNColor} [color=BLACK] - The color parameter is used to specify the color of the node in * a Red-Black Tree. It can have two possible values: 'RED' or 'BLACK'. The default value is 'BLACK'. * @param {number} [count] - The `count` parameter represents the number of occurrences of a key in * the tree. It is an optional parameter and is used to keep track of the number of values associated * with a key in the tree. - * @returns A new instance of the TreeMultiMapNode class is being returned. + * @returns A new instance of the TreeMultiMapNode class, casted as NODE. */ override createNode(key: K, value?: V, color: RBTNColor = 'BLACK', count?: number): NODE { return new TreeMultiMapNode(key, value, count, color) as NODE; @@ -135,64 +139,67 @@ export class TreeMultiMap< /** * The function creates a new instance of a TreeMultiMap with the specified options and returns it. * @param [options] - The `options` parameter is an optional object that contains additional - * configuration options for creating the `TreeMultiMap`. It can include properties such as - * `keyComparator`, `valueComparator`, `allowDuplicates`, etc. + * configuration options for creating the `TreeMultiMap`. It is of type `TreeMultiMapOptions`. * @returns a new instance of the `TreeMultiMap` class, with the provided options merged with the - * existing `iterationType` option. The returned value is casted as `TREE`. + * existing `iterationType` property. The returned value is casted as `TREE`. */ - override createTree(options?: TreeMultiMapOptions): TREE { - return new TreeMultiMap([], { + override createTree(options?: TreeMultiMapOptions): TREE { + return new TreeMultiMap([], { iterationType: this.iterationType, ...options }) as TREE; } /** - * The function `keyValueOrEntryToNode` takes a key, value, and count and returns a node if the input - * is valid. - * @param keyOrNodeOrEntry - The parameter `keyOrNodeOrEntry` can be of type `KeyOrNodeOrEntry`. It can accept three types of values: - * @param {V} [value] - The `value` parameter is an optional value of type `V`. It represents the - * value associated with a key in a key-value pair. - * @param [count=1] - The count parameter is an optional parameter that specifies the number of times - * the key-value pair should be added to the node. If not provided, it defaults to 1. - * @returns a NODE object or undefined. + * The function `keyValueOrEntryOrRawElementToNode` takes in a key, value, and count and returns a + * node based on the input. + * @param {R | KeyOrNodeOrEntry} keyOrNodeOrEntryOrRawElement - The parameter + * `keyOrNodeOrEntryOrRawElement` can be of type `R` or `KeyOrNodeOrEntry`. + * @param {V} [value] - The `value` parameter is an optional value that represents the value + * associated with the key in the node. It is used when creating a new node or updating the value of + * an existing node. + * @param [count=1] - The `count` parameter is an optional parameter that specifies the number of + * times the key-value pair should be added to the data structure. If not provided, it defaults to 1. + * @returns either a NODE object or undefined. */ - override keyValueOrEntryToNode( - keyOrNodeOrEntry: KeyOrNodeOrEntry, + override keyValueOrEntryOrRawElementToNode( + keyOrNodeOrEntryOrRawElement: R | KeyOrNodeOrEntry, value?: V, count = 1 ): NODE | undefined { - let node: NODE | undefined; - if (keyOrNodeOrEntry === undefined || keyOrNodeOrEntry === null) { - 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, 'BLACK', count); - } - } else if (!this.isNode(keyOrNodeOrEntry)) { - node = this.createNode(keyOrNodeOrEntry, value, 'BLACK', count); - } else { - return; + if (keyOrNodeOrEntryOrRawElement === undefined || keyOrNodeOrEntryOrRawElement === null) return; + + if (this.isNode(keyOrNodeOrEntryOrRawElement)) return keyOrNodeOrEntryOrRawElement; + + if (this.toEntryFn) { + const [key] = this.toEntryFn(keyOrNodeOrEntryOrRawElement as R); + if (key) return this.getNodeByKey(key); } - return node; + + if (this.isEntry(keyOrNodeOrEntryOrRawElement)) { + const [key, value] = keyOrNodeOrEntryOrRawElement; + if (key === undefined || key === null) return; + else return this.createNode(key, value, 'BLACK', count); + } + + if (this.isKey(keyOrNodeOrEntryOrRawElement)) + return this.createNode(keyOrNodeOrEntryOrRawElement, value, 'BLACK', count); + + return; } /** - * The function "isNode" checks if a given key, node, or entry is an instance of the TreeMultiMapNode - * class. - * @param keyOrNodeOrEntry - The parameter `keyOrNodeOrEntry` can be of type `KeyOrNodeOrEntry`. - * @returns a boolean value indicating whether the input parameter `keyOrNodeOrEntry` is an instance - * of the `TreeMultiMapNode` class. + * The function checks if the input is an instance of the TreeMultiMapNode class. + * @param {R | KeyOrNodeOrEntry} keyOrNodeOrEntryOrRawElement - The parameter + * `keyOrNodeOrEntryOrRawElement` can be of type `R` or `KeyOrNodeOrEntry`. + * @returns a boolean value indicating whether the input parameter `keyOrNodeOrEntryOrRawElement` is + * an instance of the `TreeMultiMapNode` class. */ - override isNode(keyOrNodeOrEntry: KeyOrNodeOrEntry): keyOrNodeOrEntry is NODE { - return keyOrNodeOrEntry instanceof TreeMultiMapNode; + override isNode( + keyOrNodeOrEntryOrRawElement: R | KeyOrNodeOrEntry + ): keyOrNodeOrEntryOrRawElement is NODE { + return keyOrNodeOrEntryOrRawElement instanceof TreeMultiMapNode; } /** @@ -204,17 +211,20 @@ export class TreeMultiMap< * Time Complexity: O(log n) * Space Complexity: O(1) * - * The function overrides the add method in TypeScript and adds a new node to the data structure. - * @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter can accept three types of values: + * The function overrides the add method of a class and adds a new node to a data structure, updating + * the count and returning a boolean indicating success. + * @param {R | KeyOrNodeOrEntry} keyOrNodeOrEntryOrRawElement - The + * `keyOrNodeOrEntryOrRawElement` parameter can accept one of the following types: * @param {V} [value] - The `value` parameter represents the value associated with the key in the - * data structure. + * data structure. It is an optional parameter, so it can be omitted if not needed. * @param [count=1] - The `count` parameter represents the number of times the key-value pair should - * be added to the data structure. By default, it is set to 1, meaning that the key-value pair will - * be added once. However, you can specify a different value for `count` if you want to add - * @returns a boolean value. + * be added to the data structure. By default, it is set to 1, meaning that if no value is provided + * for `count`, the key-value pair will be added once. + * @returns The method is returning a boolean value. It returns true if the addition of the new node + * was successful, and false otherwise. */ - override add(keyOrNodeOrEntry: KeyOrNodeOrEntry, value?: V, count = 1): boolean { - const newNode = this.keyValueOrEntryToNode(keyOrNodeOrEntry, value, count); + override add(keyOrNodeOrEntryOrRawElement: R | KeyOrNodeOrEntry, value?: V, count = 1): boolean { + const newNode = this.keyValueOrEntryOrRawElementToNode(keyOrNodeOrEntryOrRawElement, value, count); const orgCount = newNode?.count || 0; const isSuccessAdded = super.add(newNode); @@ -235,20 +245,18 @@ export class TreeMultiMap< * Time Complexity: O(log n) * Space Complexity: O(1) * - * The `delete` function in a TypeScript class is used to delete nodes from a binary tree based on a - * given identifier, and it returns an array of results containing information about the deleted - * nodes. - * @param {ReturnType | null | undefined} identifier - The identifier parameter is the value used - * to identify the node to be deleted. It can be of any type that is returned by the callback - * function. It can also be null or undefined if no node needs to be deleted. - * @param {C} callback - The `callback` parameter is a function that takes a node of type `NODE` as - * input and returns a value of type `ReturnType`. It is used to determine if a node matches the - * identifier for deletion. If no callback is provided, the `_DEFAULT_CALLBACK` function is - * used - * @param [ignoreCount=false] - A boolean value indicating whether to ignore the count of the target - * node when performing deletion. If set to true, the count of the target node will not be considered - * and the node will be deleted regardless of its count. If set to false (default), the count of the - * target node will be decremented + * The function `delete` is used to remove a node from a binary tree and fix the tree if necessary. + * @param {ReturnType | null | undefined} identifier - The `identifier` parameter is the value or + * key that is used to identify the node that needs to be deleted from the binary tree. It can be of + * any type that is returned by the callback function `C`. It can also be `null` or `undefined` if + * the node to be deleted + * @param {C} callback - The `callback` parameter is a function that is used to determine the + * equality of nodes in the binary tree. It is optional and has a default value of + * `this._DEFAULT_CALLBACK`. The `callback` function is used to compare nodes when searching for a + * specific node or when performing other operations on the + * @param [ignoreCount=false] - A boolean flag indicating whether to ignore the count of the node + * being deleted. If set to true, the count of the node will not be taken into account when deleting + * it. If set to false, the count of the node will be decremented by 1 before deleting it. * @returns an array of BinaryTreeDeleteResult objects. */ override delete>( @@ -372,10 +380,12 @@ export class TreeMultiMap< * * The `perfectlyBalance` function takes a sorted array of nodes and builds a balanced binary search * tree using either a recursive or iterative approach. - * @param iterationType - The `iterationType` parameter is an optional parameter that specifies the - * type of iteration to use when building the balanced binary search tree. It can have two possible - * values: - * @returns a boolean value. + * @param {IterationType} iterationType - The `iterationType` parameter is an optional parameter that + * specifies the type of iteration to use when building the balanced binary search tree. It has a + * default value of `this.iterationType`, which means it will use the iteration type specified by the + * `iterationType` property of the current object. + * @returns The function `perfectlyBalance` returns a boolean value. It returns `true` if the + * balancing operation is successful, and `false` if there are no nodes to balance. */ override perfectlyBalance(iterationType: IterationType = this.iterationType): boolean { const sorted = this.dfs(node => node, 'IN'), @@ -434,19 +444,27 @@ export class TreeMultiMap< } /** - * The function swaps the properties of two nodes in a binary search tree. - * @param srcNode - The source node that needs to be swapped with the destination node. It can be - * either a key or a node object. - * @param destNode - The `destNode` parameter is the node in the binary search tree where the - * properties will be swapped with the `srcNode`. + * Time Complexity: O(1) + * Space Complexity: O(1) + */ + + /** + * Time Complexity: O(1) + * Space Complexity: O(1) + * + * The `_swapProperties` function swaps the properties (key, value, count, color) between two nodes + * in a binary search tree. + * @param {R | BSTNKeyOrNode} srcNode - The `srcNode` parameter represents the source node + * that will be swapped with the `destNode`. It can be either an instance of the `R` class or an + * instance of the `BSTNKeyOrNode` class. + * @param {R | BSTNKeyOrNode} destNode - The `destNode` parameter represents the destination + * node where the properties will be swapped with the source node. * @returns The method is returning the `destNode` after swapping its properties with the `srcNode`. - * If both `srcNode` and `destNode` are valid nodes, the method swaps their `key`, `value`, `count`, - * and `color` properties. If the swapping is successful, the method returns the modified `destNode`. - * If either `srcNode` or `destNode` is + * If either `srcNode` or `destNode` is undefined, it returns undefined. */ protected override _swapProperties( - srcNode: BSTNKeyOrNode, - destNode: BSTNKeyOrNode + srcNode: R | BSTNKeyOrNode, + destNode: R | BSTNKeyOrNode ): NODE | undefined { srcNode = this.ensureNode(srcNode); destNode = this.ensureNode(destNode); @@ -473,14 +491,22 @@ export class TreeMultiMap< } /** - * The function replaces an old node with a new node and updates the count property of the new node. - * @param {NODE} oldNode - The `oldNode` parameter is of type `NODE` and represents the node that - * needs to be replaced in the data structure. - * @param {NODE} newNode - The `newNode` parameter is an object of type `NODE`. - * @returns The method is returning the result of calling the `_replaceNode` method from the - * superclass, after updating the `count` property of the `newNode` object. + * Time Complexity: O(1) + * Space Complexity: O(1) */ - protected _replaceNode(oldNode: NODE, newNode: NODE): NODE { + + /** + * Time Complexity: O(1) + * Space Complexity: O(1) + * + * The function replaces an old node with a new node and updates the count property of the new node. + * @param {NODE} oldNode - The `oldNode` parameter is the node that you want to replace in the data + * structure. + * @param {NODE} newNode - The `newNode` parameter is an instance of the `NODE` class. + * @returns The method is returning the result of calling the `_replaceNode` method from the + * superclass, which is of type `NODE`. + */ + protected override _replaceNode(oldNode: NODE, newNode: NODE): NODE { newNode.count = oldNode.count + newNode.count; return super._replaceNode(oldNode, newNode); } diff --git a/src/data-structures/graph/abstract-graph.ts b/src/data-structures/graph/abstract-graph.ts index 542ce08..b66825a 100644 --- a/src/data-structures/graph/abstract-graph.ts +++ b/src/data-structures/graph/abstract-graph.ts @@ -496,9 +496,9 @@ export abstract class AbstractGraph< /** * Dijkstra algorithm time: O(VE) space: O(VO + EO) - * / + */ - /** + /** * Time Complexity: O(V^2 + E) - Quadratic time in the worst case (no heap optimization). * Space Complexity: O(V + E) - Depends on the implementation (Dijkstra's algorithm). */ @@ -639,9 +639,9 @@ export abstract class AbstractGraph< * Dijkstra's algorithm is suitable for graphs with non-negative edge weights, whereas the Bellman-Ford algorithm and Floyd-Warshall algorithm can handle negative-weight edgeMap. * The time complexity of Dijkstra's algorithm and the Bellman-Ford algorithm depends on the size of the graph, while the time complexity of the Floyd-Warshall algorithm is O(VO^3), where VO is the number of nodes. For dense graphs, Floyd-Warshall might become slower. * - * / + */ - /** + /** * Time Complexity: O((V + E) * log(V)) - Depends on the implementation (using a binary heap). * Space Complexity: O(V + E) - Depends on the implementation (using a binary heap). */ @@ -777,9 +777,9 @@ export abstract class AbstractGraph< * Time Complexity: O(V * E) - Quadratic time in the worst case (Bellman-Ford algorithm). * Space Complexity: O(V + E) - Depends on the implementation (Bellman-Ford algorithm). * one to rest pairs - * / + */ - /** + /** * Time Complexity: O(V * E) - Quadratic time in the worst case (Bellman-Ford algorithm). * Space Complexity: O(V + E) - Depends on the implementation (Bellman-Ford algorithm). * @@ -887,9 +887,9 @@ export abstract class AbstractGraph< /** * Dijkstra algorithm time: O(logVE) space: O(VO + EO) - * / + */ - /** + /** * Dijkstra algorithm time: O(logVE) space: O(VO + EO) * Dijkstra's algorithm is used to find the shortest paths from a source node to all other nodes in a graph. Its basic idea is to repeatedly choose the node closest to the source node and update the distances of other nodes using this node as an intermediary. Dijkstra's algorithm requires that the edge weights in the graph are non-negative. */ @@ -907,9 +907,9 @@ export abstract class AbstractGraph< * Not support graph with negative weight cycle * all pairs * The Floyd-Warshall algorithm is used to find the shortest paths between all pairs of nodes in a graph. It employs dynamic programming to compute the shortest paths from any node to any other node. The Floyd-Warshall algorithm's advantage lies in its ability to handle graphs with negative-weight edgeMap, and it can simultaneously compute shortest paths between any two nodes. - * / + */ - /** + /** * Time Complexity: O(V^3) - Cubic time (Floyd-Warshall algorithm). * Space Complexity: O(V^2) - Quadratic space (Floyd-Warshall algorithm). * diff --git a/src/data-structures/hash/hash-map.ts b/src/data-structures/hash/hash-map.ts index 1b0e3da..fd5ac19 100644 --- a/src/data-structures/hash/hash-map.ts +++ b/src/data-structures/hash/hash-map.ts @@ -16,20 +16,21 @@ import { IterableEntryBase } from '../base'; import { isWeakKey, rangeCheck } from '../../utils'; /** - * 1. Key-Value Pair Storage: HashMap stores key-value pairs. Each key maps to a value. + * 1. Key-Value Pair Storage: HashMap stores key-value pairs. Each key map to a value. * 2. Fast Lookup: It's used when you need to quickly find, insert, or delete entries based on a key. - * 3. Unique Keys: Keys are unique. If you try to insert another entry with the same key, the old entry will be replaced by the new one. + * 3. Unique Keys: Keys are unique. + * If you try to insert another entry with the same key, the new one will replace the old entry. * 4. Unordered Collection: HashMap does not guarantee the order of entries, and the order may change over time. */ export class HashMap extends IterableEntryBase { /** * The constructor function initializes a HashMap object with an optional initial collection and * options. - * @param rawCollection - The `rawCollection` parameter is an iterable collection of elements of type + * @param entryOrRawElements - The `entryOrRawElements` parameter is an iterable collection of elements of a type * `T`. It is an optional parameter and its default value is an empty array `[]`. * @param [options] - The `options` parameter is an optional object that can contain two properties: */ - constructor(rawCollection: Iterable = [], options?: HashMapOptions) { + constructor(entryOrRawElements: Iterable = [], options?: HashMapOptions) { super(); if (options) { const { hashFn, toEntryFn } = options; @@ -40,8 +41,8 @@ export class HashMap extends IterableEntryBase extends IterableEntryBase [K, V] = (rawElement: R) => { - if (this.isEntry(rawElement)) { - // TODO, For performance optimization, it may be necessary to only inspect the first element traversed. - return rawElement; - } else { - throw new Error( - "If the provided rawCollection does not adhere to the [key, value] type format, the toEntryFn in the constructor's options parameter needs to specified." - ); - } - }; + protected _toEntryFn?: (rawElement: R) => [K, V]; /** * The function returns the value of the _toEntryFn property. @@ -164,23 +156,24 @@ export class HashMap extends IterableEntryBase): boolean[] { + setMany(entryOrRawElements: Iterable): boolean[] { const results: boolean[] = []; - for (const rawEle of rawCollection) { - let key, value; + for (const rawEle of entryOrRawElements) { + let key: K | undefined, value: V | undefined; if (this.isEntry(rawEle)) { key = rawEle[0]; value = rawEle[1]; - } else { + } else if (this.toEntryFn) { const item = this.toEntryFn(rawEle); key = item[0]; value = item[1]; } - results.push(this.set(key, value)); + + if (key !== undefined && value !== undefined) results.push(this.set(key, value)); } return results; } @@ -383,14 +376,14 @@ export class LinkedHashMap extends IterableEntryBa /** * The constructor initializes a LinkedHashMap object with an optional raw collection and options. - * @param rawCollection - The `rawCollection` parameter is an iterable collection of elements. It is + * @param entryOrRawElements - The `entryOrRawElements` parameter is an iterable collection of elements. It is * used to initialize the HashMapLinked instance with key-value pairs. Each element in the - * `rawCollection` is converted to a key-value pair using the `toEntryFn` function (if provided) and + * `entryOrRawElements` is converted to a key-value pair using the `toEntryFn` function (if provided) and * then added to the HashMap * @param [options] - The `options` parameter is an optional object that can contain the following * properties: */ - constructor(rawCollection: Iterable = [], options?: LinkedHashMapOptions) { + constructor(entryOrRawElements: Iterable = [], options?: LinkedHashMapOptions) { super(); this._sentinel = >{}; this._sentinel.prev = this._sentinel.next = this._head = this._tail = this._sentinel; @@ -405,8 +398,8 @@ export class LinkedHashMap extends IterableEntryBa } } - if (rawCollection) { - for (const el of rawCollection) { + if (entryOrRawElements) { + for (const el of entryOrRawElements) { const [key, value] = this.toEntryFn(el); this.set(key, value); } @@ -460,7 +453,7 @@ export class LinkedHashMap extends IterableEntryBa /** * The function returns the head node of a HashMapLinkedNode. * @returns The method `getHead()` is returning a `HashMapLinkedNode` object with key type `K` and - * value type `V | undefined`. + * a value type `V | undefined`. */ get head(): HashMapLinkedNode { return this._head; @@ -482,7 +475,7 @@ export class LinkedHashMap extends IterableEntryBa return rawElement; } else { throw new Error( - "If the provided rawCollection does not adhere to the [key, value] type format, the toEntryFn in the constructor's options parameter needs to specified." + "If the provided entryOrRawElements does not adhere to the [key, value] type format, the toEntryFn in the constructor's options parameter needs to specified." ); } }; @@ -590,7 +583,7 @@ export class LinkedHashMap extends IterableEntryBa node = this.objMap.get(hash); if (!node && isNewKey) { - // Create new node + // Create a new node node = { key: hash, value, prev: this.tail, next: this._sentinel }; this.objMap.set(hash, node); } else if (node) { @@ -630,13 +623,13 @@ export class LinkedHashMap extends IterableEntryBa * The function `setMany` takes an iterable collection, converts each element into a key-value pair * using a provided function, and sets each key-value pair in the current object, returning an array * of booleans indicating the success of each set operation. - * @param rawCollection - The rawCollection parameter is an iterable collection of elements of type + * @param entryOrRawElements - The entryOrRawElements parameter is an iterable collection of elements of type * R. * @returns The `setMany` function returns an array of booleans. */ - setMany(rawCollection: Iterable): boolean[] { + setMany(entryOrRawElements: Iterable): boolean[] { const results: boolean[] = []; - for (const rawEle of rawCollection) { + for (const rawEle of entryOrRawElements) { const [key, value] = this.toEntryFn(rawEle); results.push(this.set(key, value)); } @@ -692,9 +685,9 @@ export class LinkedHashMap extends IterableEntryBa /** * Time Complexity: O(n) * Space Complexity: O(1) - * / + */ - /** + /** * Time Complexity: O(n) * Space Complexity: O(1) * @@ -717,9 +710,9 @@ export class LinkedHashMap extends IterableEntryBa /** * Time Complexity: O(1) * Space Complexity: O(1) - * / + */ - /** + /** * Time Complexity: O(1) * Space Complexity: O(1) * @@ -764,9 +757,9 @@ export class LinkedHashMap extends IterableEntryBa /** * Time Complexity: O(n) * Space Complexity: O(1) - * / + */ - /** + /** * Time Complexity: O(n) * Space Complexity: O(1) * @@ -787,9 +780,9 @@ export class LinkedHashMap extends IterableEntryBa /** * Time Complexity: O(1) * Space Complexity: O(1) - * / + */ - /** + /** * Time Complexity: O(1) * Space Complexity: O(1) * @@ -814,9 +807,9 @@ export class LinkedHashMap extends IterableEntryBa /** * Time Complexity: O(1) * Space Complexity: O(1) - * / + */ - /** + /** * Time Complexity: O(1) * Space Complexity: O(1) * @@ -854,9 +847,9 @@ export class LinkedHashMap extends IterableEntryBa /** * Time Complexity: O(n) * Space Complexity: O(n) - * / + */ - /** + /** * Time Complexity: O(n) * Space Complexity: O(n) * @@ -886,9 +879,9 @@ export class LinkedHashMap extends IterableEntryBa /** * Time Complexity: O(n) * Space Complexity: O(n) - * / + */ - /** + /** * Time Complexity: O(n) * Space Complexity: O(n) * @@ -940,9 +933,9 @@ export class LinkedHashMap extends IterableEntryBa * Time Complexity: O(n) * Space Complexity: O(1) * where n is the number of entries in the LinkedHashMap. - * / + */ - /** + /** * Time Complexity: O(n) * Space Complexity: O(1) * where n is the number of entries in the LinkedHashMap. diff --git a/src/data-structures/queue/deque.ts b/src/data-structures/queue/deque.ts index f1a80ce..530f3c4 100644 --- a/src/data-structures/queue/deque.ts +++ b/src/data-structures/queue/deque.ts @@ -814,9 +814,9 @@ export class Deque extends IterableElementBase { /** * Time Complexity: O(n) * Space Complexity: O(1) - * / + */ - /** + /** * Time Complexity: O(n) * Space Complexity: O(1) * diff --git a/src/data-structures/queue/queue.ts b/src/data-structures/queue/queue.ts index cbeed65..3dc3849 100644 --- a/src/data-structures/queue/queue.ts +++ b/src/data-structures/queue/queue.ts @@ -358,7 +358,7 @@ export class LinkedListQueue extends SinglyLinkedList { * @returns The `clone()` method is returning a new instance of `LinkedListQueue` with the same * values as the original `LinkedListQueue`. */ - clone(): LinkedListQueue { + override clone(): LinkedListQueue { return new LinkedListQueue(this.values()); } } diff --git a/src/data-structures/trie/trie.ts b/src/data-structures/trie/trie.ts index 6844431..6d2b551 100644 --- a/src/data-structures/trie/trie.ts +++ b/src/data-structures/trie/trie.ts @@ -91,7 +91,7 @@ export class TrieNode { * 8. Autocomplete: Providing recommended words or phrases as a user types. * 9. Spell Check: Checking the spelling of words. * 10. IP Routing: Used in certain types of IP routing algorithms. - * 11. Text Word Frequency Count: Counting and storing the frequency of words in a large amount of text data." + * 11. Text Word Frequency Count: Counting and storing the frequency of words in a large amount of text data. */ export class Trie extends IterableElementBase { /** @@ -187,7 +187,7 @@ export class Trie extends IterableElementBase { * @param {string} word - The word to check for. * @returns {boolean} True if the word is present in the Trie. */ - has(word: string): boolean { + override has(word: string): boolean { word = this._caseProcess(word); let cur = this.root; for (const c of word) { diff --git a/src/interfaces/binary-tree.ts b/src/interfaces/binary-tree.ts index 1f6ec3d..d28ac6d 100644 --- a/src/interfaces/binary-tree.ts +++ b/src/interfaces/binary-tree.ts @@ -12,16 +12,17 @@ import type { export interface IBinaryTree< K extends Comparable, V = any, - N extends BinaryTreeNode = BinaryTreeNodeNested, - TREE extends BinaryTree = BinaryTreeNested + R = [K, V], + NODE extends BinaryTreeNode = BinaryTreeNodeNested, + TREE extends BinaryTree = BinaryTreeNested > { - createNode(key: K, value?: N['value']): N; + createNode(key: K, value?: NODE['value']): NODE; - createTree(options?: Partial): TREE; + createTree(options?: Partial>): TREE; - add(keyOrNodeOrEntry: KeyOrNodeOrEntry, value?: V, count?: number): boolean; + add(keyOrNodeOrEntryOrRawElement: KeyOrNodeOrEntry, value?: V, count?: number): boolean; - addMany(nodes: Iterable>, values?: Iterable): boolean[]; + addMany(nodes: Iterable>, values?: Iterable): boolean[]; - delete>(identifier: ReturnType | null, callback: C): BinaryTreeDeleteResult[]; + delete>(identifier: ReturnType | null, callback: C): BinaryTreeDeleteResult[]; } diff --git a/src/types/common.ts b/src/types/common.ts index b6d32b9..6aad98d 100644 --- a/src/types/common.ts +++ b/src/types/common.ts @@ -1,4 +1,3 @@ -export type BSTVariant = 'STANDARD' | 'INVERSE'; export type CP = 1 | -1 | 0; /** @@ -39,7 +38,7 @@ export type KeyOrNodeOrEntry = BTNEntry | BTNKeyOrNode; export type BTNodePureKeyOrNode = K | N; -export type BTNodePureExemplar = [K, V | undefined] | BTNodePureKeyOrNode; +export type BTNPureKeyOrNodeOrEntry = [K, V | undefined] | BTNodePureKeyOrNode; export type BSTNKeyOrNode = K | undefined | N; diff --git a/src/types/data-structures/binary-tree/avl-tree-multi-map.ts b/src/types/data-structures/binary-tree/avl-tree-multi-map.ts index a8d4136..78609a7 100644 --- a/src/types/data-structures/binary-tree/avl-tree-multi-map.ts +++ b/src/types/data-structures/binary-tree/avl-tree-multi-map.ts @@ -4,6 +4,6 @@ import { Comparable } from "../../utils"; export type AVLTreeMultiMapNodeNested = AVLTreeMultiMapNode>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -export type AVLTreeMultiMapNested> = AVLTreeMultiMap>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +export type AVLTreeMultiMapNested> = AVLTreeMultiMap>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -export type AVLTreeMultiMapOptions = AVLTreeOptions & {} +export type AVLTreeMultiMapOptions = AVLTreeOptions & {} diff --git a/src/types/data-structures/binary-tree/avl-tree.ts b/src/types/data-structures/binary-tree/avl-tree.ts index b69d454..4438480 100644 --- a/src/types/data-structures/binary-tree/avl-tree.ts +++ b/src/types/data-structures/binary-tree/avl-tree.ts @@ -4,6 +4,6 @@ import { Comparable } from "../../utils"; export type AVLTreeNodeNested = AVLTreeNode>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -export type AVLTreeNested> = AVLTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +export type AVLTreeNested> = AVLTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -export type AVLTreeOptions = BSTOptions & {}; +export type AVLTreeOptions = BSTOptions & {}; diff --git a/src/types/data-structures/binary-tree/binary-tree.ts b/src/types/data-structures/binary-tree/binary-tree.ts index 8fc595f..cd52cf7 100644 --- a/src/types/data-structures/binary-tree/binary-tree.ts +++ b/src/types/data-structures/binary-tree/binary-tree.ts @@ -1,11 +1,12 @@ import { BinaryTree, BinaryTreeNode } from '../../../data-structures'; -import { IterationType } from "../../common"; -import { Comparable } from "../../utils"; +import { BTNEntry, IterationType } from '../../common'; +import { Comparable } from '../../utils'; export type BinaryTreeNodeNested = BinaryTreeNode>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -export type BinaryTreeNested> = BinaryTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +export type BinaryTreeNested> = BinaryTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -export type BinaryTreeOptions = { +export type BinaryTreeOptions = { iterationType?: IterationType + toEntryFn?: (rawElement: R) => BTNEntry; } diff --git a/src/types/data-structures/binary-tree/bst.ts b/src/types/data-structures/binary-tree/bst.ts index b6112a6..416e0d6 100644 --- a/src/types/data-structures/binary-tree/bst.ts +++ b/src/types/data-structures/binary-tree/bst.ts @@ -1,12 +1,12 @@ import { BST, BSTNode } from '../../../data-structures'; import type { BinaryTreeOptions } from './binary-tree'; -import { Comparator } from "../../common"; -import { Comparable } from "../../utils"; +import { Comparator } from '../../common'; +import { Comparable } from '../../utils'; export type BSTNodeNested = BSTNode>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -export type BSTNested> = BST>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +export type BSTNested> = BST>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -export type BSTOptions = BinaryTreeOptions & { +export type BSTOptions = BinaryTreeOptions & { comparator?: Comparator } diff --git a/src/types/data-structures/binary-tree/rb-tree.ts b/src/types/data-structures/binary-tree/rb-tree.ts index 6667f4a..d874ef6 100644 --- a/src/types/data-structures/binary-tree/rb-tree.ts +++ b/src/types/data-structures/binary-tree/rb-tree.ts @@ -6,6 +6,6 @@ export type RBTNColor = 'RED' | 'BLACK'; export type RedBlackTreeNodeNested = RedBlackTreeNode>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -export type RedBlackTreeNested> = RedBlackTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +export type RedBlackTreeNested> = RedBlackTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -export type RBTreeOptions = BSTOptions & {}; +export type RBTreeOptions = BSTOptions & {}; diff --git a/src/types/data-structures/binary-tree/tree-multi-map.ts b/src/types/data-structures/binary-tree/tree-multi-map.ts index 426744b..6dbc4b6 100644 --- a/src/types/data-structures/binary-tree/tree-multi-map.ts +++ b/src/types/data-structures/binary-tree/tree-multi-map.ts @@ -1,9 +1,9 @@ import { TreeMultiMap, TreeMultiMapNode } from '../../../data-structures'; import type { RBTreeOptions } from './rb-tree'; -import { Comparable } from "../../utils"; +import { Comparable } from '../../utils'; export type TreeMultiMapNodeNested = TreeMultiMapNode>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -export type TreeMultiMapNested> = TreeMultiMap>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +export type TreeMultiMapNested> = TreeMultiMap>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -export type TreeMultiMapOptions = RBTreeOptions & {} +export type TreeMultiMapOptions = RBTreeOptions & {} diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 7a7d850..32ddf0b 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -108,7 +108,7 @@ export const roundFixed = (num: number, digit: number = 10) => { export function isComparable(key: any): key is Comparable { const keyType = typeof key; - if (keyType === 'number') return isNaN(key); + if (keyType === 'number') return !isNaN(key); if (keyType === 'string') return true; if (keyType === 'bigint') return true; if (keyType === 'boolean') return true; @@ -117,8 +117,8 @@ export function isComparable(key: any): key is Comparable { if (keyType === 'function') return isComparable(key()); if (keyType === 'object') { if (key === null) return true; - if (typeof key.valueOf === 'function') return isComparable(key.valueOf()); - if (typeof key.toString === 'function') return isComparable(key.toString()); + // if (typeof key.valueOf === 'function') return isComparable(key.valueOf()); // This will keep recursing because every object has a valueOf method. + // if (typeof key.toString === 'function') return isComparable(key.toString()); // This will also keep recursing because every string type has a toString method. return false; } diff --git a/test/integration/index.html b/test/integration/index.html index d44a80b..d1fbdf4 100644 --- a/test/integration/index.html +++ b/test/integration/index.html @@ -11,6 +11,20 @@ +
@@ -26,19 +40,19 @@ const { Queue } = dataStructureTyped; const queue = new Queue(); const n = 1000000; - const startEn = performance.now(); - for (let i = 0; i < n; i++) { - queue.push(i); - } - console.log((performance.now() - startEn).toFixed(2), `Queue ${n.toLocaleString()} enqueue `); + logPerf(`Queue ${n.toLocaleString()} enqueue`, () => { + for (let i = 0; i < n; i++) { + queue.push(i); + } + }) + let last = 0; - const startTime = performance.now(); - for (let i = 0; i < n; i++) { - last = queue.shift(); - } - - console.log((performance.now() - startTime).toFixed(2), `Queue ${n.toLocaleString()} dequeue `); + logPerf(`Queue ${n.toLocaleString()} dequeue `, () => { + for (let i = 0; i < n; i++) { + last = queue.shift(); + } + }) } catch (e) { console.error(e); diff --git a/test/unit/data-structures/binary-tree/avl-tree-multi-map.test.ts b/test/unit/data-structures/binary-tree/avl-tree-multi-map.test.ts index 39d9be9..436fcc9 100644 --- a/test/unit/data-structures/binary-tree/avl-tree-multi-map.test.ts +++ b/test/unit/data-structures/binary-tree/avl-tree-multi-map.test.ts @@ -689,3 +689,71 @@ describe('AVLTreeMultiMap iterative methods test', () => { expect([...values]).toEqual(['a', 'b', 'c']); }); }); + +describe('AVLTree toEntryFn', () => { + it('should toEntryFn 1', () => { + const tree = new AVLTreeMultiMap([], { + toEntryFn: ele => [ele.obj.id, ele.obj.id] + }); + tree.add({ obj: { id: 1 } }); + tree.add({ obj: { id: 2 } }); + tree.add({ obj: { id: 3 } }); + tree.add({ obj: { id: 4 } }); + tree.add({ obj: { id: 5 } }); + + const expected = [1, 2, 3, 4, 5]; + + expect(tree.morris(node => node.key, 'IN')).toEqual(expected); + expect(tree.dfs(node => node.key, 'IN')).toEqual(expected); + expect(tree.dfs(node => node.key, 'IN', tree.root, 'RECURSIVE')).toEqual(expected); + }); + + it('should toEntryFn 2', () => { + const tree = new AVLTreeMultiMap( + [{ obj: { id: 1 } }, { obj: { id: 2 } }, { obj: { id: 3 } }, { obj: { id: 4 } }, { obj: { id: 5 } }], + { + toEntryFn: ele => [ele.obj.id, ele.obj.id] + } + ); + + const expected = [1, 2, 3, 4, 5]; + + expect(tree.morris(node => node.key, 'IN')).toEqual(expected); + expect(tree.dfs(node => node.key, 'IN')).toEqual(expected); + expect(tree.dfs(node => node.key, 'IN', tree.root, 'RECURSIVE')).toEqual(expected); + }); + + it('should toEntryFn throw error', () => { + expect( + () => + new AVLTreeMultiMap<{ obj: { id: number } }, number>([ + { obj: { id: 1 } }, + { obj: { id: 2 } }, + { obj: { id: 3 } }, + { obj: { id: 4 } }, + { obj: { id: 5 } } + ]) + ).toThrowError( + 'When comparing two object types, it is necessary to customize a [comparator] function of options parameter during the instantiation of the data structure.' + ); + }); + + it('should toEntryFn 3', () => { + const tree = new AVLTreeMultiMap<{ obj: { id: number } }, number>( + [{ obj: { id: 1 } }, { obj: { id: 2 } }, { obj: { id: 3 } }, { obj: { id: 4 } }, { obj: { id: 5 } }], + { comparator: (a, b) => a.obj.id - b.obj.id } + ); + + const expected = [ + { obj: { id: 1 } }, + { obj: { id: 2 } }, + { obj: { id: 3 } }, + { obj: { id: 4 } }, + { obj: { id: 5 } } + ]; + + expect(tree.morris(node => node.key, 'IN')).toEqual(expected); + expect(tree.dfs(node => node.key, 'IN')).toEqual(expected); + expect(tree.dfs(node => node.key, 'IN', tree.root, 'RECURSIVE')).toEqual(expected); + }); +}); 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 b0128de..54569df 100644 --- a/test/unit/data-structures/binary-tree/binary-tree.test.ts +++ b/test/unit/data-structures/binary-tree/binary-tree.test.ts @@ -403,6 +403,62 @@ describe('BinaryTree Morris Traversal', () => { }); }); +describe('BinaryTree toEntryFn', () => { + it('should toEntryFn 1', () => { + const tree = new BinaryTree([], { + toEntryFn: ele => [ele.obj.id, ele.obj.id] + }); + tree.add({ obj: { id: 1 } }); + tree.add({ obj: { id: 2 } }); + tree.add({ obj: { id: 3 } }); + tree.add({ obj: { id: 4 } }); + tree.add({ obj: { id: 5 } }); + + const expected = [4, 2, 5, 1, 3]; + + expect(tree.morris(node => node.key, 'IN')).toEqual(expected); + expect(tree.dfs(node => node.key, 'IN')).toEqual(expected); + expect(tree.dfs(node => node.key, 'IN', tree.root, 'RECURSIVE')).toEqual(expected); + }); + + it('should toEntryFn 2', () => { + const tree = new BinaryTree( + [{ obj: { id: 1 } }, { obj: { id: 2 } }, { obj: { id: 3 } }, { obj: { id: 4 } }, { obj: { id: 5 } }], + { + toEntryFn: ele => [ele.obj.id, ele.obj.id] + } + ); + + const expected = [4, 2, 5, 1, 3]; + + expect(tree.morris(node => node.key, 'IN')).toEqual(expected); + expect(tree.dfs(node => node.key, 'IN')).toEqual(expected); + expect(tree.dfs(node => node.key, 'IN', tree.root, 'RECURSIVE')).toEqual(expected); + }); + + it('should toEntryFn 3', () => { + const tree = new BinaryTree<{ obj: { id: number } }, number>([ + { obj: { id: 1 } }, + { obj: { id: 2 } }, + { obj: { id: 3 } }, + { obj: { id: 4 } }, + { obj: { id: 5 } } + ]); + + const expected = [ + { obj: { id: 4 } }, + { obj: { id: 2 } }, + { obj: { id: 5 } }, + { obj: { id: 1 } }, + { obj: { id: 3 } } + ]; + + expect(tree.morris(node => node.key, 'IN')).toEqual(expected); + expect(tree.dfs(node => node.key, 'IN')).toEqual(expected); + expect(tree.dfs(node => node.key, 'IN', tree.root, 'RECURSIVE')).toEqual(expected); + }); +}); + describe('BinaryTree traversals', () => { const tree = new BinaryTree(); diff --git a/test/unit/data-structures/graph/directed-graph.test.ts b/test/unit/data-structures/graph/directed-graph.test.ts index a29ac40..6fa46e2 100644 --- a/test/unit/data-structures/graph/directed-graph.test.ts +++ b/test/unit/data-structures/graph/directed-graph.test.ts @@ -132,11 +132,11 @@ class MyDirectedGraph< VO extends MyVertex = MyVertex, EO extends MyEdge = MyEdge > extends DirectedGraph { - createVertex(key: VertexKey, value: V): VO { + override createVertex(key: VertexKey, value: V): VO { return new MyVertex(key, value) as VO; } - createEdge(src: VertexKey, dest: VertexKey, weight?: number, value?: E): EO { + override createEdge(src: VertexKey, dest: VertexKey, weight?: number, value?: E): EO { return new MyEdge(src, dest, weight ?? 1, value) as EO; } diff --git a/test/utils/big-o.ts b/test/utils/big-o.ts index 1c9175f..3d42c56 100644 --- a/test/utils/big-o.ts +++ b/test/utils/big-o.ts @@ -206,14 +206,20 @@ export function logBigOMetrics(target: any, propertyKey: string, descriptor: Pro return descriptor; } -export const logPerf = function (fn: (...args: any[]) => any, args: any[], thisArg?: any) { +export const logPerf = function ( + label: string = 'function running cost', + fn: (...args: any[]) => any, + args: any[], + thisArg?: any +) { const start = performance.now(); + let result: any; if (thisArg) { - if (args && args.length > 0) fn.apply(thisArg, args); - else fn.apply(thisArg); + if (args && args.length > 0) result = fn.apply(thisArg, args); + else result = fn.apply(thisArg); } else { - if (args && args.length > 0) fn(...args); - else fn(); + if (args && args.length > 0) result = fn(...args); + else result = fn(); } - console.log(`function running cost : ${(performance.now() - start).toFixed(2)} ms`); + console.log(`${(performance.now() - start).toFixed(2)} ms, ${label}, ${result}`); }; diff --git a/tsconfig-base.json b/tsconfig-base.json index 7102137..d27f3ff 100644 --- a/tsconfig-base.json +++ b/tsconfig-base.json @@ -16,6 +16,7 @@ "strict": true, // Enable strict type checking, including enabling all strict options. "traceResolution": false, // Whether to trace the module resolution process. "types": ["node", "jest"], // Specifies the name of the type declaration file to include. + "noImplicitOverride": true, "typeRoots": ["node_modules/@types", "src/types", "test/types"] }, "compileOnSave": false, // Whether to automatically compile when saving.