diff --git a/CHANGELOG.md b/CHANGELOG.md index b112baf..2ece9ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ All notable changes to this project will be documented in this file. - [Semantic Versioning](https://semver.org/spec/v2.0.0.html) - [`auto-changelog`](https://github.com/CookPete/auto-changelog) -## [v1.42.2](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) +## [v1.42.3](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) ### Changes diff --git a/README.md b/README.md index 853d220..7a24af6 100644 --- a/README.md +++ b/README.md @@ -636,40 +636,40 @@ optimal approach to data structure design. [//]: # (Start of Replace Section)
avl-tree
-
test nametime taken (ms)executions per secsample deviation
10,000 add randomly31.9331.322.30e-4
10,000 add & delete randomly69.1214.470.00
10,000 addMany41.1424.311.60e-4
10,000 get28.6834.867.65e-4
+
test nametime taken (ms)executions per secsample deviation
10,000 add randomly30.3332.973.56e-4
10,000 add & delete randomly66.1015.130.00
10,000 addMany39.4425.353.62e-4
10,000 get27.0636.962.52e-4
binary-tree
-
test nametime taken (ms)executions per secsample deviation
1,000 add randomly13.1276.213.40e-4
1,000 add & delete randomly16.3361.224.17e-4
1,000 addMany10.9691.223.99e-4
1,000 get18.6553.634.20e-4
1,000 dfs71.8213.920.00
1,000 bfs58.9516.960.00
1,000 morris37.4626.704.60e-4
+
test nametime taken (ms)executions per secsample deviation
1,000 add randomly12.9077.521.09e-4
1,000 add & delete randomly16.1361.991.61e-4
1,000 addMany10.7493.091.00e-4
1,000 get18.0955.281.90e-4
1,000 dfs71.1214.067.83e-4
1,000 bfs57.2417.474.17e-4
1,000 morris37.2926.813.77e-4
bst
-
test nametime taken (ms)executions per secsample deviation
10,000 add randomly32.9830.320.00
10,000 add & delete randomly74.4713.430.00
10,000 addMany29.9333.416.02e-4
10,000 get29.9233.428.61e-4
+
test nametime taken (ms)executions per secsample deviation
10,000 add randomly31.5831.670.00
10,000 add & delete randomly71.0914.078.99e-4
10,000 addMany29.6833.690.00
10,000 get28.5535.030.00
rb-tree
-
test nametime taken (ms)executions per secsample deviation
100,000 add randomly80.4912.420.01
100,000 add & 1000 delete randomly89.9711.110.01
100,000 getNode68.6314.570.01
+
test nametime taken (ms)executions per secsample deviation
100,000 add randomly84.6411.820.01
100,000 add & 1000 delete randomly81.3212.300.01
100,000 getNode61.1816.350.00
directed-graph
-
test nametime taken (ms)executions per secsample deviation
1,000 addVertex0.109878.721.87e-6
1,000 addEdge6.34157.782.53e-4
1,000 getVertex0.052.12e+41.05e-6
1,000 getEdge23.0843.330.00
tarjan217.754.590.01
tarjan all219.234.560.01
topologicalSort175.735.690.02
+
test nametime taken (ms)executions per secsample deviation
1,000 addVertex0.109637.473.79e-6
1,000 addEdge6.09164.181.31e-4
1,000 getVertex0.052.14e+41.35e-6
1,000 getEdge23.9141.820.01
tarjan218.654.570.01
tarjan all221.674.510.00
topologicalSort184.345.420.02
heap
-
test nametime taken (ms)executions per secsample deviation
10,000 add & pop4.64215.446.89e-5
10,000 fib add & pop357.372.800.01
+
test nametime taken (ms)executions per secsample deviation
10,000 add & pop4.63215.774.49e-5
10,000 fib add & pop355.192.820.00
doubly-linked-list
-
test nametime taken (ms)executions per secsample deviation
1,000,000 unshift239.344.180.04
1,000,000 unshift & shift168.745.930.04
1,000,000 insertBefore324.743.080.06
+
test nametime taken (ms)executions per secsample deviation
1,000,000 unshift213.534.680.02
1,000,000 unshift & shift162.976.140.02
1,000,000 insertBefore335.192.980.09
singly-linked-list
-
test nametime taken (ms)executions per secsample deviation
10,000 push & pop213.864.680.01
10,000 insertBefore254.023.940.02
+
test nametime taken (ms)executions per secsample deviation
10,000 push & pop231.354.320.02
10,000 insertBefore251.493.980.01
max-priority-queue
-
test nametime taken (ms)executions per secsample deviation
10,000 refill & poll11.3987.762.14e-4
+
test nametime taken (ms)executions per secsample deviation
10,000 refill & poll11.4887.141.91e-4
deque
-
test nametime taken (ms)executions per secsample deviation
1,000,000 push233.914.280.05
1,000,000 shift25.6139.050.00
+
test nametime taken (ms)executions per secsample deviation
1,000,000 push215.144.650.05
1,000,000 shift25.1539.760.00
queue
-
test nametime taken (ms)executions per secsample deviation
1,000,000 push43.8822.790.01
1,000,000 push & shift81.7112.240.00
+
test nametime taken (ms)executions per secsample deviation
1,000,000 push44.1522.650.01
1,000,000 push & shift80.8712.370.00
trie
-
test nametime taken (ms)executions per secsample deviation
100,000 push59.9316.690.01
100,000 getWords93.1010.740.01
+
test nametime taken (ms)executions per secsample deviation
100,000 push61.3816.290.01
100,000 getWords104.279.590.02
[//]: # (End of Replace Section) \ No newline at end of file diff --git a/package.json b/package.json index e13c156..f3b8678 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "copy:to-subs": "sh scripts/copy_to_all_subs.sh", "publish:subs": "npm run copy:to-subs && sh scripts/publish_all_subs.sh", "publish:docs": "sh scripts/publish_docs.sh", - "publish:all": "npm run ci && npm run benchmark && npm publish && npm run publish:docs && npm run publish:subs" + "publish:all": "npm run ci && npm publish && npm run publish:docs && npm run publish:subs" }, "repository": { "type": "git", diff --git a/src/data-structures/binary-tree/avl-tree.ts b/src/data-structures/binary-tree/avl-tree.ts index 47d99fd..8e72d8a 100644 --- a/src/data-structures/binary-tree/avl-tree.ts +++ b/src/data-structures/binary-tree/avl-tree.ts @@ -49,13 +49,14 @@ export class AVLTree = AVLTreeNode = AVLTreeNode = AVLTreeNode = BinaryTreeNode } } - protected _root: N | null = null; + protected _root: N | null | undefined = undefined; /** * Get the root node of the binary tree. */ - get root(): N | null { + get root(): N | null | undefined { return this._root; } @@ -155,7 +155,7 @@ export class BinaryTree = BinaryTreeNode * Clear the binary tree, removing all nodes. */ clear() { - this._setRoot(null); + this._setRoot(undefined); this._size = 0; } @@ -173,7 +173,7 @@ export class BinaryTree = BinaryTreeNode * @param {V} value - The value for the new node (optional). * @returns {N | null | undefined} - The inserted node, or null if nothing was inserted, or undefined if the operation failed. */ - add(keyOrNode: BTNKey | N | null, value?: V): N | null | undefined { + add(keyOrNode: BTNKey | N | null | undefined, value?: V): N | null | undefined { const _bfs = (root: N, newNode: N | null): N | undefined | null => { const queue = new Queue([root]); while (queue.size > 0) { @@ -236,7 +236,7 @@ export class BinaryTree = BinaryTreeNode * the value of the nodes will be `undefined`. * @returns The function `addMany` returns an array of `N`, `null`, or `undefined` values. */ - addMany(keysOrNodes: (BTNKey | null)[] | (N | null)[], values?: V[]): (N | null | undefined)[] { + addMany(keysOrNodes: (BTNKey | null | undefined)[] | (N | null | undefined)[], values?: V[]): (N | null | undefined)[] { // TODO not sure addMany not be run multi times return keysOrNodes.map((keyOrNode, i) => { if (keyOrNode instanceof BinaryTreeNode) { @@ -261,14 +261,14 @@ export class BinaryTree = BinaryTreeNode * array. Each value in the `data` array will be assigned to the * @returns The method is returning a boolean value. */ - refill(keysOrNodes: (BTNKey | null)[] | (N | null)[], data?: Array): boolean { + refill(keysOrNodes: (BTNKey | null | undefined)[] | (N | null | undefined)[], data?: Array): boolean { this.clear(); return keysOrNodes.length === this.addMany(keysOrNodes, data).length; } delete>(identifier: BTNKey, callback?: C): BinaryTreeDeletedResult[]; - delete>(identifier: N | null, callback?: C): BinaryTreeDeletedResult[]; + delete>(identifier: N | null | undefined, callback?: C): BinaryTreeDeletedResult[]; delete>(identifier: ReturnType, callback: C): BinaryTreeDeletedResult[]; @@ -287,7 +287,7 @@ export class BinaryTree = BinaryTreeNode * `this.defaultOneParamCallback`, which */ delete>( - identifier: ReturnType | null, + identifier: ReturnType | null | undefined, callback: C = this.defaultOneParamCallback as C ): BinaryTreeDeletedResult[] { const bstDeletedResult: BinaryTreeDeletedResult[] = []; @@ -297,8 +297,8 @@ export class BinaryTree = BinaryTreeNode const curr = this.getNode(identifier, callback); if (!curr) return bstDeletedResult; - const parent: N | null = curr?.parent ? curr.parent : null; - let needBalanced: N | null = null, + const parent: N | null | undefined = curr?.parent ? curr.parent : null; + let needBalanced: N | null | undefined = null, orgCurrent = curr; if (!curr.left) { @@ -336,16 +336,16 @@ export class BinaryTree = BinaryTreeNode /** * The function `getDepth` calculates the depth of a given node in a binary tree relative to a * specified root node. - * @param {BTNKey | N | null} distNode - The `distNode` parameter represents the node + * @param {BTNKey | N | null | undefined} distNode - The `distNode` parameter represents the node * whose depth we want to find in the binary tree. It can be either a node object (`N`), a key value * of the node (`BTNKey`), or `null`. - * @param {BTNKey | N | null} beginRoot - The `beginRoot` parameter represents the + * @param {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter represents the * starting node from which we want to calculate the depth. It can be either a node object or the key * of a node in the binary tree. If no value is provided for `beginRoot`, it defaults to the root * node of the binary tree. * @returns the depth of the `distNode` relative to the `beginRoot`. */ - getDepth(distNode: BTNKey | N | null, beginRoot: BTNKey | N | null = this.root): number { + getDepth(distNode: BTNKey | N | null | undefined, beginRoot: BTNKey | N | null | undefined = this.root): number { if (typeof distNode === 'number') distNode = this.getNode(distNode); if (typeof beginRoot === 'number') beginRoot = this.getNode(beginRoot); let depth = 0; @@ -362,7 +362,7 @@ export class BinaryTree = BinaryTreeNode /** * The `getHeight` function calculates the maximum height of a binary tree using either recursive or * iterative approach. - * @param {BTNKey | N | null} beginRoot - The `beginRoot` parameter represents the + * @param {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter represents the * starting node from which the height of the binary tree is calculated. It can be either a node * object (`N`), a key value of a node in the tree (`BTNKey`), or `null` if no starting * node is specified. If ` @@ -371,7 +371,7 @@ export class BinaryTree = BinaryTreeNode * possible values: * @returns the height of the binary tree. */ - getHeight(beginRoot: BTNKey | N | null = this.root, iterationType = this.iterationType): number { + getHeight(beginRoot: BTNKey | N | null | undefined = this.root, iterationType = this.iterationType): number { if (typeof beginRoot === 'number') beginRoot = this.getNode(beginRoot); if (!beginRoot) return -1; @@ -413,14 +413,14 @@ export class BinaryTree = BinaryTreeNode /** * The `getMinHeight` function calculates the minimum height of a binary tree using either a * recursive or iterative approach. - * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node from which we want to + * @param {N | null | undefined} beginRoot - The `beginRoot` parameter is the starting node from which we want to * calculate the minimum height of the tree. It is optional and defaults to the root of the tree if * not provided. * @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. */ - getMinHeight(beginRoot: N | null = this.root, iterationType = this.iterationType): number { + getMinHeight(beginRoot: N | null | undefined = this.root, iterationType = this.iterationType): number { if (!beginRoot) return -1; if (iterationType === IterationType.RECURSIVE) { @@ -436,7 +436,7 @@ export class BinaryTree = BinaryTreeNode } else { const stack: N[] = []; let node: N | null | undefined = beginRoot, - last: N | null = null; + last: N | null | undefined = null; const depths: Map = new Map(); while (stack.length > 0 || node) { @@ -465,11 +465,11 @@ export class BinaryTree = BinaryTreeNode /** * The function checks if a binary tree is perfectly balanced by comparing the minimum height and the * height of the tree. - * @param {N | null} beginRoot - The parameter `beginRoot` is of type `N | null`, which means it can + * @param {N | null | undefined} beginRoot - The parameter `beginRoot` is of type `N | null | undefined`, which means it can * either be of type `N` (representing a node in a tree) or `null` (representing an empty tree). * @returns The method is returning a boolean value. */ - isPerfectlyBalanced(beginRoot: N | null = this.root): boolean { + isPerfectlyBalanced(beginRoot: N | null | undefined = this.root): boolean { return this.getMinHeight(beginRoot) + 1 >= this.getHeight(beginRoot); } @@ -477,15 +477,15 @@ export class BinaryTree = BinaryTreeNode identifier: BTNKey, callback?: C, onlyOne?: boolean, - beginRoot?: N | null, + beginRoot?: N | null | undefined, iterationType?: IterationType ): N[]; getNodes>( - identifier: N | null, + identifier: N | null | undefined, callback?: C, onlyOne?: boolean, - beginRoot?: N | null, + beginRoot?: N | null | undefined, iterationType?: IterationType ): N[]; @@ -493,7 +493,7 @@ export class BinaryTree = BinaryTreeNode identifier: ReturnType, callback: C, onlyOne?: boolean, - beginRoot?: N | null, + beginRoot?: N | null | undefined, iterationType?: IterationType ): N[]; @@ -511,7 +511,7 @@ export class BinaryTree = BinaryTreeNode * first node that matches the identifier. If set to true, the function will return an array with * only one element (or an empty array if no matching node is found). If set to false (default), the * function will continue searching for all - * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node from which the + * @param {N | null | undefined} beginRoot - The `beginRoot` parameter is the starting node from which the * traversal of the binary tree will begin. It is optional and defaults to the root of the binary * tree. * @param iterationType - The `iterationType` parameter determines the type of iteration used to @@ -519,10 +519,10 @@ export class BinaryTree = BinaryTreeNode * @returns The function `getNodes` returns an array of nodes (`N[]`). */ getNodes>( - identifier: ReturnType | null, + identifier: ReturnType | null | undefined, callback: C = this.defaultOneParamCallback as C, onlyOne = false, - beginRoot: N | null = this.root, + beginRoot: N | null | undefined = this.root, iterationType = this.iterationType ): N[] { if (!beginRoot) return []; @@ -562,21 +562,21 @@ export class BinaryTree = BinaryTreeNode has>( identifier: BTNKey, callback?: C, - beginRoot?: N | null, + beginRoot?: N | null | undefined, iterationType?: IterationType ): boolean; has>( - identifier: N | null, + identifier: N | null | undefined, callback?: C, - beginRoot?: N | null, + beginRoot?: N | null | undefined, iterationType?: IterationType ): boolean; has>( - identifier: ReturnType | null, + identifier: ReturnType | null | undefined, callback: C, - beginRoot?: N | null, + beginRoot?: N | null | undefined, iterationType?: IterationType ): boolean; @@ -598,7 +598,7 @@ export class BinaryTree = BinaryTreeNode * @returns a boolean value. */ has>( - identifier: ReturnType | null, + identifier: ReturnType | null | undefined, callback: C = this.defaultOneParamCallback as C, beginRoot = this.root, iterationType = this.iterationType @@ -611,23 +611,23 @@ export class BinaryTree = BinaryTreeNode getNode>( identifier: BTNKey, callback?: C, - beginRoot?: N | null, + beginRoot?: N | null | undefined, iterationType?: IterationType - ): N | null; + ): N | null | undefined; getNode>( - identifier: N | null, + identifier: N | null | undefined, callback?: C, - beginRoot?: N | null, + beginRoot?: N | null | undefined, iterationType?: IterationType - ): N | null; + ): N | null | undefined; getNode>( identifier: ReturnType, callback: C, - beginRoot?: N | null, + beginRoot?: N | null | undefined, iterationType?: IterationType - ): N | null; + ): N | null | undefined; /** * The function `get` returns the first node in a binary tree that matches the given property or key. @@ -645,11 +645,11 @@ export class BinaryTree = BinaryTreeNode * @returns either the found node (of type N) or null if no node is found. */ getNode>( - identifier: ReturnType | null, + identifier: ReturnType | null | undefined, callback: C = this.defaultOneParamCallback as C, beginRoot = this.root, iterationType = this.iterationType - ): N | null { + ): N | null | undefined { if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C; return this.getNodes(identifier, callback, true, beginRoot, iterationType)[0] ?? null; @@ -658,21 +658,21 @@ export class BinaryTree = BinaryTreeNode get>( identifier: BTNKey, callback?: C, - beginRoot?: N | null, + beginRoot?: N | null | undefined, iterationType?: IterationType ): V | undefined; get>( - identifier: N | null, + identifier: N | null | undefined, callback?: C, - beginRoot?: N | null, + beginRoot?: N | null | undefined, iterationType?: IterationType ): V | undefined; get>( identifier: ReturnType, callback: C, - beginRoot?: N | null, + beginRoot?: N | null | undefined, iterationType?: IterationType ): V | undefined; @@ -692,7 +692,7 @@ export class BinaryTree = BinaryTreeNode * @returns either the found value (of type V) or undefined if no node value is found. */ get>( - identifier: ReturnType | null, + identifier: ReturnType | null | undefined, callback: C = this.defaultOneParamCallback as C, beginRoot = this.root, iterationType = this.iterationType @@ -728,7 +728,7 @@ export class BinaryTree = BinaryTreeNode /** * The function `getLeftMost` returns the leftmost node in a binary tree, either using recursive or * iterative traversal. - * @param {BTNKey | N | null} beginRoot - The `beginRoot` parameter is the starting point + * @param {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting point * for finding the leftmost node in a binary tree. It can be either a node object (`N`), a key value * of a node (`BTNKey`), or `null` if the tree is empty. * @param iterationType - The `iterationType` parameter is used to determine the type of iteration to @@ -736,7 +736,7 @@ export class BinaryTree = BinaryTreeNode * @returns The function `getLeftMost` returns the leftmost node (`N`) in a binary tree. If there is * no leftmost node, it returns `null`. */ - getLeftMost(beginRoot: BTNKey | N | null = this.root, iterationType = this.iterationType): N | null { + getLeftMost(beginRoot: BTNKey | N | null | undefined = this.root, iterationType = this.iterationType): N | null | undefined { if (typeof beginRoot === 'number') beginRoot = this.getNode(beginRoot); if (!beginRoot) return beginRoot; @@ -762,15 +762,15 @@ export class BinaryTree = BinaryTreeNode /** * The function `getRightMost` returns the rightmost node in a binary tree, either recursively or * iteratively. - * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node from which we want to - * find the rightmost node. It is of type `N | null`, which means it can either be a node of type `N` + * @param {N | null | undefined} beginRoot - The `beginRoot` parameter is the starting node from which we want to + * find the rightmost node. It is of type `N | null | undefined`, which means it can either be a node of type `N` * or `null`. If it is `null`, it means there is no starting node * @param iterationType - The `iterationType` parameter is used to determine 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 the rightmost node (`N`) in a binary tree. If the * `beginRoot` parameter is `null`, it returns `null`. */ - getRightMost(beginRoot: N | null = this.root, iterationType = this.iterationType): N | null { + getRightMost(beginRoot: N | null | undefined = this.root, iterationType = this.iterationType): N | null | undefined { // TODO support get right most by passing key in if (!beginRoot) return beginRoot; @@ -801,7 +801,7 @@ export class BinaryTree = BinaryTreeNode * possible values: * @returns The function `isSubtreeBST` returns a boolean value. */ - isSubtreeBST(beginRoot: N | null, iterationType = this.iterationType): boolean { + isSubtreeBST(beginRoot: N | null | undefined, iterationType = this.iterationType): boolean { // TODO there is a bug if (!beginRoot) return true; @@ -846,21 +846,21 @@ export class BinaryTree = BinaryTreeNode subTreeTraverse>( callback?: C, - beginRoot?: BTNKey | N | null, + beginRoot?: BTNKey | N | null | undefined, iterationType?: IterationType, includeNull?: false ): ReturnType[]; subTreeTraverse>( callback?: C, - beginRoot?: BTNKey | N | null, + beginRoot?: BTNKey | N | null | undefined, iterationType?: IterationType, includeNull?: undefined ): ReturnType[]; - subTreeTraverse>( + subTreeTraverse>( callback?: C, - beginRoot?: BTNKey | N | null, + beginRoot?: BTNKey | N | null | undefined, iterationType?: IterationType, includeNull?: true ): ReturnType[]; @@ -872,7 +872,7 @@ export class BinaryTree = BinaryTreeNode * subtree traversal. It takes a single argument, which is the current node being traversed, and * returns a value. The return values from each callback invocation will be collected and returned as * an array. - * @param {BTNKey | N | null} beginRoot - The `beginRoot` parameter is the starting point + * @param {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting point * for traversing the subtree. It can be either a node object, a key value of a node, or `null` to * start from the root of the tree. * @param iterationType - The `iterationType` parameter determines the type of traversal to be @@ -880,19 +880,19 @@ export class BinaryTree = BinaryTreeNode * @param includeNull - The choice to output null values during binary tree traversal should be provided. * @returns The function `subTreeTraverse` returns an array of `ReturnType>`. */ - subTreeTraverse>( + subTreeTraverse>( callback: C = this.defaultOneParamCallback as C, - beginRoot: BTNKey | N | null = this.root, + beginRoot: BTNKey | N | null | undefined = this.root, iterationType = this.iterationType, includeNull = false ): ReturnType[] { if (typeof beginRoot === 'number') beginRoot = this.getNode(beginRoot); - const ans: (ReturnType> | null)[] = []; + const ans: (ReturnType> | null | undefined)[] = []; if (!beginRoot) return ans; if (iterationType === IterationType.RECURSIVE) { - const _traverse = (cur: N | null) => { + const _traverse = (cur: N | null | undefined) => { if (cur !== undefined) { ans.push(callback(cur)); if (includeNull) { @@ -907,7 +907,7 @@ export class BinaryTree = BinaryTreeNode _traverse(beginRoot); } else { - const stack: (N | null)[] = [beginRoot]; + const stack: (N | null | undefined)[] = [beginRoot]; while (stack.length > 0) { const cur = stack.pop(); @@ -929,7 +929,7 @@ export class BinaryTree = BinaryTreeNode dfs>( callback?: C, pattern?: DFSOrderPattern, - beginRoot?: N | null, + beginRoot?: N | null | undefined, iterationType?: IterationType, includeNull?: false ): ReturnType[]; @@ -937,15 +937,15 @@ export class BinaryTree = BinaryTreeNode dfs>( callback?: C, pattern?: DFSOrderPattern, - beginRoot?: N | null, + beginRoot?: N | null | undefined, iterationType?: IterationType, includeNull?: undefined ): ReturnType[]; - dfs>( + dfs>( callback?: C, pattern?: DFSOrderPattern, - beginRoot?: N | null, + beginRoot?: N | null | undefined, iterationType?: IterationType, includeNull?: true ): ReturnType[]; @@ -958,7 +958,7 @@ export class BinaryTree = BinaryTreeNode * is `this.defaultOneParamCallback`, which is a callback function defined elsewhere in the code. * @param {DFSOrderPattern} [pattern=in] - The `pattern` parameter determines the order in which the * nodes are visited during the depth-first search. There are three possible values for `pattern`: - * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node for the depth-first + * @param {N | null | undefined} beginRoot - The `beginRoot` parameter is the starting node for the depth-first * search. It determines where the search will begin in the tree or graph structure. If `beginRoot` * is `null`, an empty array will be returned. * @param {IterationType} iterationType - The `iterationType` parameter determines the type of @@ -966,48 +966,48 @@ export class BinaryTree = BinaryTreeNode * @param includeNull - The choice to output null values during binary tree traversal should be provided. * @returns The function `dfs` returns an array of `ReturnType>` values. */ - dfs>( + dfs>( callback: C = this.defaultOneParamCallback as C, pattern: DFSOrderPattern = 'in', - beginRoot: N | null = this.root, + beginRoot: N | null | undefined = this.root, iterationType: IterationType = IterationType.ITERATIVE, includeNull = false ): ReturnType[] { if (!beginRoot) return []; const ans: ReturnType[] = []; if (iterationType === IterationType.RECURSIVE) { - const _traverse = (node: N | null) => { + const _traverse = (node: N | null | undefined) => { switch (pattern) { case 'in': if (includeNull) { - if (node !== null && node.left !== undefined) _traverse(node.left); + if (node && node.left !== undefined) _traverse(node.left); ans.push(callback(node)); - if (node !== null && node.right !== undefined) _traverse(node.right); + if (node && node.right !== undefined) _traverse(node.right); } else { - if (node !== null && node.left) _traverse(node.left); + if (node && node.left) _traverse(node.left); ans.push(callback(node)); - if (node !== null && node.right) _traverse(node.right); + if (node && node.right) _traverse(node.right); } break; case 'pre': if (includeNull) { ans.push(callback(node)); - if (node !== null && node.left !== undefined) _traverse(node.left); - if (node !== null && node.right !== undefined) _traverse(node.right); + if (node && node.left !== undefined) _traverse(node.left); + if (node && node.right !== undefined) _traverse(node.right); } else { ans.push(callback(node)); - if (node !== null && node.left) _traverse(node.left); - if (node !== null && node.right) _traverse(node.right); + if (node && node.left) _traverse(node.left); + if (node && node.right) _traverse(node.right); } break; case 'post': if (includeNull) { - if (node !== null && node.left !== undefined) _traverse(node.left); - if (node !== null && node.right !== undefined) _traverse(node.right); + if (node && node.left !== undefined) _traverse(node.left); + if (node && node.right !== undefined) _traverse(node.right); ans.push(callback(node)); } else { - if (node !== null && node.left) _traverse(node.left); - if (node !== null && node.right) _traverse(node.right); + if (node && node.left) _traverse(node.left); + if (node && node.right) _traverse(node.right); ans.push(callback(node)); } @@ -1062,21 +1062,21 @@ export class BinaryTree = BinaryTreeNode bfs>( callback?: C, - beginRoot?: N | null, + beginRoot?: N | null | undefined, iterationType?: IterationType, includeNull?: false ): ReturnType[]; bfs>( callback?: C, - beginRoot?: N | null, + beginRoot?: N | null | undefined, iterationType?: IterationType, includeNull?: undefined ): ReturnType[]; - bfs>( + bfs>( callback?: C, - beginRoot?: N | null, + beginRoot?: N | null | undefined, iterationType?: IterationType, includeNull?: true ): ReturnType[]; @@ -1087,7 +1087,7 @@ export class BinaryTree = BinaryTreeNode * @param callback - The `callback` parameter is a function that will be called for each node in the * breadth-first search. It takes a node of type `N` as its argument and returns a value of type * `ReturnType>`. The default value for this parameter is `this.defaultOneParamCallback - * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node for the breadth-first + * @param {N | null | undefined} beginRoot - The `beginRoot` parameter is the starting node for the breadth-first * search. It determines from which node the search will begin. If `beginRoot` is `null`, the search * will not be performed and an empty array will be returned. * @param iterationType - The `iterationType` parameter determines the type of iteration to be used @@ -1095,9 +1095,9 @@ export class BinaryTree = BinaryTreeNode * @param includeNull - The choice to output null values during binary tree traversal should be provided. * @returns The function `bfs` returns an array of `ReturnType>[]`. */ - bfs>( + bfs>( callback: C = this.defaultOneParamCallback as C, - beginRoot: N | null = this.root, + beginRoot: N | null | undefined = this.root, iterationType = this.iterationType, includeNull = false ): ReturnType[] { @@ -1106,7 +1106,7 @@ export class BinaryTree = BinaryTreeNode const ans: ReturnType>[] = []; if (iterationType === IterationType.RECURSIVE) { - const queue: Queue = new Queue([beginRoot]); + const queue: Queue = new Queue([beginRoot]); const traverse = (level: number) => { if (queue.size === 0) return; @@ -1127,7 +1127,7 @@ export class BinaryTree = BinaryTreeNode traverse(0); } else { - const queue = new Queue([beginRoot]); + const queue = new Queue([beginRoot]); while (queue.size > 0) { const levelSize = queue.size; @@ -1150,21 +1150,21 @@ export class BinaryTree = BinaryTreeNode listLevels>( callback?: C, - beginRoot?: N | null, + beginRoot?: N | null | undefined, iterationType?: IterationType, includeNull?: false ): ReturnType[][]; listLevels>( callback?: C, - beginRoot?: N | null, + beginRoot?: N | null | undefined, iterationType?: IterationType, includeNull?: undefined ): ReturnType[][]; - listLevels>( + listLevels>( callback?: C, - beginRoot?: N | null, + beginRoot?: N | null | undefined, iterationType?: IterationType, includeNull?: true ): ReturnType[][]; @@ -1175,7 +1175,7 @@ export class BinaryTree = BinaryTreeNode * @param {C} callback - The `callback` parameter is a function that will be called on each node in * the tree. It takes a node as input and returns a value. The return type of the callback function * is determined by the generic type `C`. - * @param {N | null} beginRoot - The `beginRoot` parameter represents the starting node of the binary tree + * @param {N | null | undefined} beginRoot - The `beginRoot` parameter represents the starting node of the binary tree * traversal. It can be any node in the binary tree. If no node is provided, the traversal will start * from the root node of the binary tree. * @param iterationType - The `iterationType` parameter determines whether the tree traversal is done @@ -1185,9 +1185,9 @@ export class BinaryTree = BinaryTreeNode * level in a binary tree. Each inner array contains the return type of the provided callback * function `C` applied to the nodes at that level. */ - listLevels>( + listLevels>( callback: C = this.defaultOneParamCallback as C, - beginRoot: N | null = this.root, + beginRoot: N | null | undefined = this.root, iterationType = this.iterationType, includeNull = false ): ReturnType[][] { @@ -1195,7 +1195,7 @@ export class BinaryTree = BinaryTreeNode const levelsNodes: ReturnType[][] = []; if (iterationType === IterationType.RECURSIVE) { - const _recursive = (node: N | null, level: number) => { + const _recursive = (node: N | null | undefined, level: number) => { if (!levelsNodes[level]) levelsNodes[level] = []; levelsNodes[level].push(callback(node)); if (includeNull) { @@ -1209,7 +1209,7 @@ export class BinaryTree = BinaryTreeNode _recursive(beginRoot, 0); } else { - const stack: [N | null, number][] = [[beginRoot, 0]]; + const stack: [N | null | undefined, number][] = [[beginRoot, 0]]; while (stack.length > 0) { const head = stack.pop()!; @@ -1279,7 +1279,7 @@ export class BinaryTree = BinaryTreeNode * @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 * following values: - * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node for the Morris + * @param {N | null | undefined} beginRoot - The `beginRoot` parameter is the starting node for the Morris * traversal. It specifies the root node of the tree from which the traversal should begin. If * `beginRoot` is `null`, an empty array will be returned. * @returns The `morris` function returns an array of `ReturnType>` values. @@ -1287,7 +1287,7 @@ export class BinaryTree = BinaryTreeNode morris>( callback: C = this.defaultOneParamCallback as C, pattern: DFSOrderPattern = 'in', - beginRoot: N | null = this.root + beginRoot: N | null | undefined = this.root ): ReturnType[] { if (beginRoot === null) return []; const ans: ReturnType>[] = []; @@ -1304,7 +1304,7 @@ export class BinaryTree = BinaryTreeNode } return pre; }; - const _printEdge = (node: N | null) => { + const _printEdge = (node: N | null | undefined) => { const tail: N | null | undefined = _reverseEdge(node); let cur: N | null | undefined = tail; while (cur) { @@ -1438,7 +1438,7 @@ export class BinaryTree = BinaryTreeNode /** * The function `_addTo` adds a new node to a binary tree if there is an available position. - * @param {N | null} newNode - The `newNode` parameter represents the node that you want to add to + * @param {N | null | undefined} newNode - The `newNode` parameter represents the node that you want to add to * the binary tree. It can be either a node object or `null`. * @param {N} parent - The `parent` parameter represents the parent node to which the new node will * be added as a child. @@ -1447,7 +1447,7 @@ export class BinaryTree = BinaryTreeNode * the binary tree. If neither the left nor right child is available, the function returns undefined. * If the parent node is null, the function also returns undefined. */ - protected _addTo(newNode: N | null, parent: N): N | null | undefined { + protected _addTo(newNode: N | null | undefined, parent: N): N | null | undefined { if (parent) { // When all leaf nodes are null, it will no longer be possible to add new entity nodes to this binary tree. // In this scenario, null nodes serve as "sentinel nodes," "virtual nodes," or "placeholder nodes." @@ -1474,10 +1474,10 @@ export class BinaryTree = BinaryTreeNode /** * 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 {N | null} v - The parameter `v` is of type `N | null`, which means it can either be of + * @param {N | null | undefined} v - The parameter `v` is of type `N | null | undefined`, which means it can either be of * type `N` or `null`. */ - protected _setRoot(v: N | null) { + protected _setRoot(v: N | null | undefined) { if (v) { v.parent = undefined; } diff --git a/src/data-structures/binary-tree/bst.ts b/src/data-structures/binary-tree/bst.ts index 21fdc07..d626560 100644 --- a/src/data-structures/binary-tree/bst.ts +++ b/src/data-structures/binary-tree/bst.ts @@ -12,8 +12,53 @@ import {IBinaryTree} from '../../interfaces'; import {Queue} from '../queue'; export class BSTNode = BSTNodeNested> extends BinaryTreeNode { + override parent: N | undefined; constructor(key: BTNKey, value?: V) { super(key, value); + this.parent = undefined; + this._left = undefined; + this._right = undefined; + } + + protected override _left: N | undefined; + + /** + * Get the left child node. + */ + override get left(): N | undefined { + return this._left; + } + + /** + * Set the left child node. + * @param {N | undefined} v - The left child node. + */ + override set left(v: N | undefined) { + if (v) { + v.parent = this as unknown as N; + } + this._left = v; + } + + + protected override _right: N | undefined; + + /** + * Get the right child node. + */ + override get right(): N | undefined { + return this._right; + } + + /** + * Set the right child node. + * @param {N | undefined} v - The right child node. + */ + override set right(v: N | undefined) { + if (v) { + v.parent = this as unknown as N; + } + this._right = v; } } @@ -29,6 +74,7 @@ export class BST = BSTNode> */ constructor(options?: BSTOptions) { super(options); + this._root = undefined; if (options !== undefined) { const {comparator} = options; if (comparator !== undefined) { @@ -36,6 +82,14 @@ export class BST = BSTNode> } } } + protected override _root: N | undefined = undefined; + + /** + * Get the root node of the binary tree. + */ + override get root(): N | undefined { + return this._root; + } /** * The function creates a new binary search tree node with the given key and value. @@ -52,33 +106,37 @@ export class BST = BSTNode> /** * The `add` function in a binary search tree class inserts a new node with a given key and value * into the tree. - * @param {BTNKey | N | null} keyOrNode - The `keyOrNode` parameter can be either a - * `BTNKey` (which can be a number or a string), a `BSTNode` object, or `null`. + * @param {BTNKey | N | undefined} keyOrNode - The `keyOrNode` parameter can be either a + * `BTNKey` (which can be a number or a string), a `BSTNode` object, or `undefined`. * @param [value] - The `value` parameter is the value to be assigned to the new node being added to the * binary search tree. * @returns the inserted node (N) if it was successfully added to the binary search tree. If the node - * was not added or if the parameters were invalid, it returns null or undefined. + * was not added or if the parameters were invalid, it returns undefined or undefined. */ - override add(keyOrNode: BTNKey | N | null, value?: V): N | null | undefined { + override add(keyOrNode: BTNKey | N | null | undefined, value?: V): N | undefined { + if (keyOrNode === 8) { + debugger + } + if (keyOrNode === null) return undefined; // TODO support node as a parameter - let inserted: N | null = null; - let newNode: N | null = null; + let inserted:N | undefined = undefined; + let newNode:N | undefined = undefined; if (keyOrNode instanceof BSTNode) { newNode = keyOrNode; } else if (typeof keyOrNode === 'number') { newNode = this.createNode(keyOrNode, value); - } else if (keyOrNode === null) { - newNode = null; + } else { + newNode = undefined; } - if (this.root === null) { - this._setRoot(newNode); + if (this.root === undefined) { + this._root = newNode; this._size = this.size + 1; inserted = this.root; } else { let cur = this.root; let traversing = true; while (traversing) { - if (cur !== null && newNode !== null) { + if (cur !== undefined && newNode !== undefined) { if (this._compare(cur.key, newNode.key) === CP.eq) { if (newNode) { cur.value = newNode.value; @@ -131,29 +189,29 @@ export class BST = BSTNode> * @param {[BTNKey | N, V][]} keysOrNodes - The `arr` parameter in the `addMany` function * represents an array of keys or nodes that need to be added to the binary search tree. It can be an * array of `BTNKey` or `N` (which represents the node type in the binary search tree) or - * `null + * `undefined * @param {V[]} data - The values of tree nodes * @param {boolean} isBalanceAdd - If true the nodes will be balance inserted in binary search method. * @param iterationType - The `iterationType` parameter determines the type of iteration to be used. * It can have two possible values: - * @returns The `addMany` function returns an array of `N`, `null`, or `undefined` values. + * @returns The `addMany` function returns an array of `N`, `undefined`, or `undefined` values. */ override addMany( - keysOrNodes: (BTNKey | null)[] | (N | null)[], + keysOrNodes: (BTNKey | undefined)[] | (N | undefined)[], data?: V[], isBalanceAdd = true, iterationType = this.iterationType - ): (N | null | undefined)[] { + ): (N | undefined)[] { // TODO this addMany function is inefficient, it should be optimized - function hasNoNull(arr: (BTNKey | null)[] | (N | null)[]): arr is BTNKey[] | N[] { - return arr.indexOf(null) === -1; + function hasNoNull(arr: (BTNKey | undefined)[] | (N | undefined)[]): arr is BTNKey[] | N[] { + return arr.indexOf(undefined) === -1; } if (!isBalanceAdd || !hasNoNull(keysOrNodes)) { - return super.addMany(keysOrNodes, data); + return super.addMany(keysOrNodes, data).map(n => n ?? undefined); } - const inserted: (N | null | undefined)[] = []; + const inserted: (N | undefined)[] = []; const combinedArr: [BTNKey | N, V][] = keysOrNodes.map( (value: BTNKey | N, index) => [value, data?.[index]] as [BTNKey | N, V] ); @@ -169,7 +227,7 @@ export class BST = BSTNode> return false; } - let sortedKeysOrNodes: (number | N | null)[] = [], + let sortedKeysOrNodes: (number | N | undefined)[] = [], sortedData: (V | undefined)[] | undefined = []; if (isNodeOrNullTuple(combinedArr)) { @@ -181,7 +239,7 @@ export class BST = BSTNode> } sortedKeysOrNodes = sorted.map(([keyOrNode]) => keyOrNode); sortedData = sorted.map(([, value]) => value); - const recursive = (arr: (BTNKey | null | N)[], data?: (V | undefined)[]) => { + const recursive = (arr: (BTNKey | undefined | N)[], data?: (V | undefined)[]) => { if (arr.length === 0) return; const mid = Math.floor((arr.length - 1) / 2); @@ -220,7 +278,7 @@ export class BST = BSTNode> * The function `lastKey` returns the key of the rightmost node if the comparison result is less * than, the key of the leftmost node if the comparison result is greater than, and the key of the * rightmost node otherwise. - * @param {N | null} beginRoot - The `beginRoot` parameter is the starting point for finding the last + * @param {N | undefined} beginRoot - The `beginRoot` parameter is the starting point for finding the last * key in a binary tree. It represents the root node of the subtree from which the search for the * last key should begin. If no specific `beginRoot` is provided, the search will start from the root * of the entire binary @@ -231,7 +289,7 @@ export class BST = BSTNode> * the key of the leftmost node if the comparison result is greater than, and the key of the * rightmost node otherwise. If no node is found, it returns 0. */ - lastKey(beginRoot: N | null = this.root, iterationType = this.iterationType): BTNKey { + lastKey(beginRoot: N | undefined = this.root, iterationType = this.iterationType): BTNKey { if (this._compare(0, 1) === CP.lt) return this.getRightMost(beginRoot, iterationType)?.key ?? 0; else if (this._compare(0, 1) === CP.gt) return this.getLeftMost(beginRoot, iterationType)?.key ?? 0; else return this.getRightMost(beginRoot, iterationType)?.key ?? 0; @@ -251,18 +309,18 @@ export class BST = BSTNode> * the first node that matches the nodeProperty. If set to true, the function will return an array * containing only that node. If set to false (default), the function will continue the traversal and * return an array containing all nodes that match the node - * @param {N | null} beginRoot - The `beginRoot` parameter is the starting node for the traversal. It + * @param {N | undefined} beginRoot - The `beginRoot` parameter is the starting node for the traversal. It * specifies the root node of the binary tree from which the traversal should begin. If `beginRoot` - * is `null`, an empty array will be returned. + * is `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 one of the following values: * @returns an array of nodes (N[]). */ override getNodes>( - identifier: ReturnType | null, + identifier: ReturnType | undefined, callback: C = this.defaultOneParamCallback as C, onlyOne = false, - beginRoot: N | null = this.root, + beginRoot: N | undefined = this.root, iterationType = this.iterationType ): N[] { if (!beginRoot) return []; @@ -324,10 +382,10 @@ export class BST = BSTNode> * @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 can take one * of the following values: - * @param {BTNKey | N | null} targetNode - The `targetNode` parameter in the + * @param {BTNKey | N | undefined} targetNode - The `targetNode` parameter in the * `lesserOrGreaterTraverse` function is used to specify the node from which the traversal should * start. It can be either a reference to a specific node (`N`), the key of a node - * (`BTNKey`), or `null` to + * (`BTNKey`), or `undefined` to * @param iterationType - The `iterationType` parameter determines whether the traversal should be * done recursively or iteratively. It can have two possible values: * @returns The function `lesserOrGreaterTraverse` returns an array of `ReturnType>`. @@ -335,10 +393,10 @@ export class BST = BSTNode> lesserOrGreaterTraverse>( callback: C = this.defaultOneParamCallback as C, lesserOrGreater: CP = CP.lt, - targetNode: BTNKey | N | null = this.root, + targetNode: BTNKey | N | undefined = this.root, iterationType = this.iterationType ): ReturnType[] { - if (typeof targetNode === 'number') targetNode = this.getNode(targetNode); + if (typeof targetNode === 'number') targetNode = this.getNode(targetNode) ?? undefined; const ans: ReturnType>[] = []; if (!targetNode) return ans; const targetKey = targetNode.key; @@ -417,6 +475,7 @@ export class BST = BSTNode> if (l <= r) { const m = l + Math.floor((r - l) / 2); const midNode = sorted[m]; + debugger this.add(midNode.key, midNode.value); stack.push([m + 1, r]); stack.push([l, m - 1]); @@ -439,7 +498,7 @@ export class BST = BSTNode> let balanced = true; if (iterationType === IterationType.RECURSIVE) { - const _height = (cur: N | null | undefined): number => { + const _height = (cur: N | undefined): number => { if (!cur) return 0; const leftHeight = _height(cur.left), rightHeight = _height(cur.right); @@ -449,8 +508,8 @@ export class BST = BSTNode> _height(this.root); } else { const stack: N[] = []; - let node: N | null | undefined = this.root, - last: N | null = null; + let node: N | undefined = this.root, + last:N | undefined = undefined; const depths: Map = new Map(); while (stack.length > 0 || node) { @@ -467,7 +526,7 @@ export class BST = BSTNode> if (Math.abs(left - right) > 1) return false; depths.set(node, 1 + Math.max(left, right)); last = node; - node = null; + node = undefined; } } else node = node.right; } diff --git a/src/data-structures/binary-tree/tree-multiset.ts b/src/data-structures/binary-tree/tree-multiset.ts index 7be1720..bb0c505 100644 --- a/src/data-structures/binary-tree/tree-multiset.ts +++ b/src/data-structures/binary-tree/tree-multiset.ts @@ -71,23 +71,24 @@ export class TreeMultiset = TreeMultis /** * The `add` function adds a new node to a binary search tree, updating the count if the key already * exists, and balancing the tree if necessary. - * @param {BTNKey | N | null} keyOrNode - The `keyOrNode` parameter can be either a + * @param {BTNKey | N | undefined} keyOrNode - The `keyOrNode` parameter can be either a * `BTNKey` (which represents the key of the node to be added), a `N` (which represents a - * node to be added), or `null` (which represents a null node). + * node to be added), or `undefined` (which represents a undefined node). * @param [value] - The `value` parameter represents the value associated with the key that is being * added to the binary tree. * @param [count=1] - The `count` parameter represents the number of occurrences of the key/value * pair that will be added to the binary tree. It has a default value of 1, which means that if no * count is specified, the default count will be 1. - * @returns The function `add` returns a value of type `N | null | undefined`. + * @returns The function `add` returns a value of type `N | undefined | undefined`. */ - override add(keyOrNode: BTNKey | N | null, value?: V, count = 1): N | null | undefined { - let inserted: N | null | undefined = undefined, - newNode: N | null; + override add(keyOrNode: BTNKey | N | null | undefined, value?: V, count = 1): N | undefined { + if(keyOrNode === null) return undefined; + let inserted: N | undefined = undefined, + newNode: N | undefined; if (keyOrNode instanceof TreeMultisetNode) { newNode = this.createNode(keyOrNode.key, keyOrNode.value, keyOrNode.count); - } else if (keyOrNode === null) { - newNode = null; + } else if (keyOrNode === undefined) { + newNode = undefined; } else { newNode = this.createNode(keyOrNode, value, count); } @@ -138,7 +139,7 @@ export class TreeMultiset = TreeMultis } } } else { - // TODO may need to support null inserted + // TODO may need to support undefined inserted } } else { traversing = false; @@ -151,17 +152,17 @@ export class TreeMultiset = TreeMultis /** * The function adds a new node to a binary tree if there is an available slot in the parent node. - * @param {N | null} newNode - The `newNode` parameter represents the node that needs to be added to - * the tree. It can be either a node object (`N`) or `null`. + * @param {N | undefined} newNode - The `newNode` parameter represents the node that needs to be added to + * the tree. It can be either a node object (`N`) or `undefined`. * @param {N} parent - The `parent` parameter represents the parent node to which the new node will * be added as a child. * @returns The method `_addTo` returns either the `parent.left`, `parent.right`, or `undefined`. */ - override _addTo(newNode: N | null, parent: N): N | null | undefined { + override _addTo(newNode: N | undefined, parent: N): N | undefined { if (parent) { if (parent.left === undefined) { parent.left = newNode; - if (newNode !== null) { + if (newNode !== undefined) { this._size = this.size + 1; this._setCount(this.count + newNode.count); } @@ -169,7 +170,7 @@ export class TreeMultiset = TreeMultis return parent.left; } else if (parent.right === undefined) { parent.right = newNode; - if (newNode !== null) { + if (newNode !== undefined) { this._size = this.size + 1; this._setCount(this.count + newNode.count); } @@ -185,15 +186,15 @@ export class TreeMultiset = TreeMultis /** * The `addMany` function adds multiple keys or nodes to a TreeMultiset and returns an array of the * inserted nodes. - * @param {(BTNKey | null)[] | (N | null)[]} keysOrNodes - An array of keys or nodes to be + * @param {(BTNKey | undefined)[] | (N | undefined)[]} keysOrNodes - An array of keys or nodes to be * added to the multiset. Each element can be either a BTNKey or a TreeMultisetNode. * @param {V[]} [data] - The `data` parameter is an optional array of values that correspond * to the keys or nodes being added to the multiset. It is used to associate additional data with * each key or node. - * @returns The function `addMany` returns an array of `N`, `null`, or `undefined` values. + * @returns The function `addMany` returns an array of `N`, `undefined`, or `undefined` values. */ - override addMany(keysOrNodes: (BTNKey | null)[] | (N | null)[], data?: V[]): (N | null | undefined)[] { - const inserted: (N | null | undefined)[] = []; + override addMany(keysOrNodes: (BTNKey | undefined)[] | (N | undefined)[], data?: V[]): (N | undefined)[] { + const inserted: (N | undefined | undefined)[] = []; for (let i = 0; i < keysOrNodes.length; i++) { const keyOrNode = keysOrNodes[i]; @@ -203,7 +204,7 @@ export class TreeMultiset = TreeMultis continue; } - if (keyOrNode === null) { + if (keyOrNode === undefined) { inserted.push(this.add(NaN, undefined, 0)); continue; } @@ -283,11 +284,11 @@ export class TreeMultiset = TreeMultis const bstDeletedResult: BinaryTreeDeletedResult[] = []; if (!this.root) return bstDeletedResult; - const curr: N | null = this.getNode(identifier, callback); + const curr: N | undefined = this.getNode(identifier, callback) ?? undefined; if (!curr) return bstDeletedResult; - const parent: N | null = curr?.parent ? curr.parent : null; - let needBalanced: N | null = null, + const parent: N | undefined = curr?.parent ? curr.parent : undefined; + let needBalanced: N | undefined = undefined, orgCurrent = curr; if (curr.count > 1 && !ignoreCount) { @@ -307,7 +308,7 @@ export class TreeMultiset = TreeMultis needBalanced = parent; } } else { - const leftSubTreeRightMost = curr.left ? this.getRightMost(curr.left) : null; + const leftSubTreeRightMost = curr.left ? this.getRightMost(curr.left) : undefined; if (leftSubTreeRightMost) { const parentOfLeftSubTreeMax = leftSubTreeRightMost.parent; orgCurrent = this._swap(curr, leftSubTreeRightMost); diff --git a/src/types/data-structures/binary-tree/binary-tree.ts b/src/types/data-structures/binary-tree/binary-tree.ts index c9da335..dc843c2 100644 --- a/src/types/data-structures/binary-tree/binary-tree.ts +++ b/src/types/data-structures/binary-tree/binary-tree.ts @@ -24,7 +24,7 @@ export enum FamilyPosition { export type BTNKey = number; -export type BinaryTreeDeletedResult = { deleted: N | null | undefined; needBalanced: N | null }; +export type BinaryTreeDeletedResult = { deleted: N | null | undefined; needBalanced: N | null | undefined }; export type BinaryTreeNodeNested = BinaryTreeNode>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/test/unit/data-structures/binary-tree/avl-tree.test.ts b/test/unit/data-structures/binary-tree/avl-tree.test.ts index 7518a9b..1af0ce6 100644 --- a/test/unit/data-structures/binary-tree/avl-tree.test.ts +++ b/test/unit/data-structures/binary-tree/avl-tree.test.ts @@ -36,7 +36,6 @@ describe('AVL Tree Test', () => { const dfs = tree.dfs(node => node, 'in'); expect(dfs[0].key).toBe(1); expect(dfs[dfs.length - 1].key).toBe(16); - tree.perfectlyBalance(); const bfs = tree.bfs(node => node); expect(tree.isPerfectlyBalanced()).toBe(true); @@ -266,4 +265,24 @@ describe('AVLTree', () => { // You can add more specific assertions to check the tree's balance and structure. }); + + describe('BinaryTree APIs test', () => { + const avl = new AVLTree<{id: number; text: string}>(); + beforeEach(() => { + avl.clear(); + }); + + it('add', () => { + avl.add(1); + const node2 = new AVLTreeNode(2); + avl.add(node2); + const node3 = new AVLTreeNode(3, {id: 3, text: 'text3'}); + avl.add(node3); + avl.add(node3, {id: 3, text: 'text33'}); + + const bfsRes = avl.bfs(node => node); + expect(bfsRes[0]?.key).toBe(2); + }); + }); + }); 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 5d8d7f0..ae49e6b 100644 --- a/test/unit/data-structures/binary-tree/binary-tree.test.ts +++ b/test/unit/data-structures/binary-tree/binary-tree.test.ts @@ -1,4 +1,4 @@ -import {AVLTree, AVLTreeNode, BinaryTree, BinaryTreeNode, IterationType} from '../../../../src'; +import {BinaryTree, BinaryTreeNode, IterationType} from '../../../../src'; // import {isDebugTest} from '../../../config'; // const isDebug = isDebugTest; @@ -177,10 +177,10 @@ describe('BinaryTree', () => { expect(tree.subTreeTraverse(node => node.key, tree.getNode(6), IterationType.ITERATIVE)).toEqual([6, 3, 7]); expect(tree.subTreeTraverse(node => node.key, tree.getNode(6), IterationType.RECURSIVE)).toEqual([6, 3, 7]); expect( - tree.subTreeTraverse(node => (node === null ? null : node.key), tree.getNode(6), IterationType.ITERATIVE, true) + tree.subTreeTraverse(node => (node ? node.key : null ), tree.getNode(6), IterationType.ITERATIVE, true) ).toEqual([6, 3, 7, null]); expect( - tree.subTreeTraverse(node => (node === null ? null : node.key), tree.getNode(6), IterationType.RECURSIVE, true) + tree.subTreeTraverse(node => (node ? node.key : null ), tree.getNode(6), IterationType.RECURSIVE, true) ).toEqual([6, 3, 7, null]); }); @@ -193,7 +193,7 @@ describe('BinaryTree', () => { tree.clear(); expect(tree.size).toBe(0); - expect(tree.root).toBeNull(); + expect(tree.root).toBeUndefined(); }); }); @@ -248,35 +248,16 @@ describe('BinaryTree Morris Traversal', () => { }); }); -describe('BinaryTree APIs test', () => { - const avl = new AVLTree<{id: number; text: string}>(); - beforeEach(() => { - avl.clear(); - }); - - it('add', () => { - avl.add(1); - const node2 = new AVLTreeNode(2); - avl.add(node2); - const node3 = new AVLTreeNode(3, {id: 3, text: 'text3'}); - avl.add(node3); - avl.add(node3, {id: 3, text: 'text33'}); - - const bfsRes = avl.bfs(node => node); - expect(bfsRes[0]?.key).toBe(2); - }); -}); - describe('BinaryTree traversals', () => { const tree = new BinaryTree(); const arr = [35, 20, 40, 15, 29, null, 50, null, 16, 28, 30, 45, 55]; tree.refill(arr); expect( - tree.bfs(node => node, tree.root, IterationType.ITERATIVE, true).map(node => (node === null ? null : node.key)) + tree.bfs(node => node, tree.root, IterationType.ITERATIVE, true).map(node => (node ? node.key : null )) ).toEqual([35, 20, 40, 15, 29, null, 50, null, 16, 28, 30, 45, 55]); expect( - tree.bfs(node => node, tree.root, IterationType.RECURSIVE, true).map(node => (node === null ? null : node.key)) + tree.bfs(node => node, tree.root, IterationType.RECURSIVE, true).map(node => (node ? node.key : null )) ).toEqual([35, 20, 40, 15, 29, null, 50, null, 16, 28, 30, 45, 55]); expect( tree.bfs(node => node, tree.root, IterationType.ITERATIVE).map(node => (node === null ? null : node.key)) @@ -292,12 +273,12 @@ describe('BinaryTree traversals', () => { expect( tree .dfs(node => node, 'pre', tree.root, IterationType.ITERATIVE, true) - .map(node => (node === null ? null : node.key)) + .map(node => (node ? node.key : null )) ).toEqual([35, 20, 15, null, 16, 29, 28, 30, 40, null, 50, 45, 55]); expect( tree .dfs(node => node, 'pre', tree.root, IterationType.RECURSIVE, true) - .map(node => (node === null ? null : node.key)) + .map(node => (node ? node.key : null )) ).toEqual([35, 20, 15, null, 16, 29, 28, 30, 40, null, 50, 45, 55]); expect(tree.dfs(node => node.key, 'in')).toEqual([15, 16, 20, 28, 29, 30, 35, 40, 45, 50, 55]); @@ -320,13 +301,13 @@ describe('BinaryTree traversals', () => { [15, 29, 50], [16, 28, 30, 45, 55] ]); - expect(tree.listLevels(node => (node === null ? null : node.key), tree.root, IterationType.ITERATIVE, true)).toEqual([ + expect(tree.listLevels(node => (node ? node.key : null ), tree.root, IterationType.ITERATIVE, true)).toEqual([ [35], [20, 40], [15, 29, null, 50], [null, 16, 28, 30, 45, 55] ]); - expect(tree.listLevels(node => (node === null ? null : node.key), tree.root, IterationType.RECURSIVE, true)).toEqual([ + expect(tree.listLevels(node => ( node ? node.key : null ), tree.root, IterationType.RECURSIVE, true)).toEqual([ [35], [20, 40], [15, 29, null, 50], @@ -348,7 +329,7 @@ describe('BinaryTree', () => { it('should create an empty BinaryTree', () => { expect(tree.size).toBe(0); expect(tree.isEmpty()).toBe(true); - expect(tree.root).toBe(null); + expect(tree.root).toBe(undefined); }); it('should add nodes to the tree', () => { @@ -370,7 +351,7 @@ describe('BinaryTree', () => { expect(tree.size).toBe(0); expect(tree.isEmpty()).toBe(true); - expect(tree.root).toBe(null); + expect(tree.root).toBe(undefined); }); it('should get nodes by key', () => { diff --git a/test/unit/data-structures/binary-tree/bst.test.ts b/test/unit/data-structures/binary-tree/bst.test.ts index e82bf9c..ef80c31 100644 --- a/test/unit/data-structures/binary-tree/bst.test.ts +++ b/test/unit/data-structures/binary-tree/bst.test.ts @@ -840,14 +840,14 @@ describe('BST Performance test', function () { it('should subTreeTraverse, null should be ignored', () => { const bst = new BST(); - bst.addMany([4, 2, 6, null, 1, 3, null, 5, null, 7]); + bst.addMany([4, 2, 6, 1, 3, 5, 7]); expect(bst.subTreeTraverse(node => node.key, bst.getNode(6), IterationType.ITERATIVE)).toEqual([6, 5, 7]); expect(bst.subTreeTraverse(node => node.key, bst.getNode(6), IterationType.RECURSIVE)).toEqual([6, 5, 7]); expect( - bst.subTreeTraverse(node => (node === null ? null : node.key), bst.getNode(6), IterationType.ITERATIVE, true) + bst.subTreeTraverse(node => (node?.key ?? undefined), bst.getNode(6), IterationType.ITERATIVE, true) ).toEqual([6, 5, 7]); expect( - bst.subTreeTraverse(node => (node === null ? null : node.key), bst.getNode(6), IterationType.RECURSIVE, true) + bst.subTreeTraverse(node => (node?.key ?? undefined), bst.getNode(6), IterationType.RECURSIVE, true) ).toEqual([6, 5, 7]); }); });