From a1cfac93da6bf3df2a0e9d98116c16a3f65130db Mon Sep 17 00:00:00 2001 From: Revone Date: Fri, 10 Nov 2023 23:44:24 +0800 Subject: [PATCH] test: Testing coverage has increased to 91.2%. --- CHANGELOG.md | 2 +- README.md | 24 +-- package.json | 2 +- .../binary-tree/binary-tree.ts | 154 +++++++++--------- .../binary-tree/avl-tree.test.ts | 3 +- .../binary-tree/binary-tree.test.ts | 57 ++++++- 6 files changed, 144 insertions(+), 98 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d365a930..8866bc12 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.8](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) +## [v1.42.9](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming) ### Changes diff --git a/README.md b/README.md index 119337bf..6ea2f89a 100644 --- a/README.md +++ b/README.md @@ -728,40 +728,40 @@ optimal approach to data structure design. [//]: # (No deletion!!! Start of Replace Section)
avl-tree
-
test nametime taken (ms)executions per secsample deviation
10,000 add randomly32.9130.386.85e-4
10,000 add & delete randomly73.8413.540.00
10,000 addMany43.7922.840.00
10,000 get29.0734.407.13e-4
+
test nametime taken (ms)executions per secsample deviation
10,000 add randomly33.6029.760.00
10,000 add & delete randomly72.3913.810.01
10,000 addMany41.0624.350.00
10,000 get28.0135.710.00
binary-tree
-
test nametime taken (ms)executions per secsample deviation
1,000 add randomly12.6579.062.71e-4
1,000 add & delete randomly16.4360.860.00
1,000 addMany10.2597.591.46e-4
1,000 get18.0255.481.61e-4
1,000 dfs156.296.400.00
1,000 bfs56.0617.845.29e-4
1,000 morris260.473.840.00
+
test nametime taken (ms)executions per secsample deviation
1,000 add randomly12.6479.096.90e-4
1,000 add & delete randomly16.0362.385.30e-4
1,000 addMany10.4495.780.00
1,000 get18.1954.983.11e-4
1,000 dfs154.716.460.00
1,000 bfs56.9717.558.92e-4
1,000 morris260.713.840.00
bst
-
test nametime taken (ms)executions per secsample deviation
10,000 add randomly31.6731.589.08e-4
10,000 add & delete randomly73.3013.640.01
10,000 addMany30.3532.950.00
10,000 get29.4933.917.80e-4
+
test nametime taken (ms)executions per secsample deviation
10,000 add randomly29.5733.812.75e-4
10,000 add & delete randomly70.7814.130.00
10,000 addMany29.1034.366.84e-4
10,000 get28.7534.786.05e-4
rb-tree
-
test nametime taken (ms)executions per secsample deviation
100,000 add randomly90.8511.010.01
100,000 add & delete randomly238.184.200.07
100,000 getNode111.049.010.03
+
test nametime taken (ms)executions per secsample deviation
100,000 add randomly88.5511.290.01
100,000 add & delete randomly220.414.540.01
100,000 getNode37.5226.652.68e-4
directed-graph
-
test nametime taken (ms)executions per secsample deviation
1,000 addVertex0.109609.825.99e-6
1,000 addEdge6.43155.614.69e-4
1,000 getVertex0.052.10e+42.90e-6
1,000 getEdge23.9841.700.01
tarjan225.874.430.02
tarjan all229.794.350.03
topologicalSort192.075.210.03
+
test nametime taken (ms)executions per secsample deviation
1,000 addVertex0.109804.121.07e-6
1,000 addEdge6.06165.111.66e-4
1,000 getVertex0.052.17e+43.48e-7
1,000 getEdge23.2643.000.00
tarjan223.274.480.01
tarjan all224.274.460.00
topologicalSort179.195.580.00
heap
-
test nametime taken (ms)executions per secsample deviation
10,000 add & pop4.67214.007.34e-5
10,000 fib add & pop370.252.700.00
+
test nametime taken (ms)executions per secsample deviation
10,000 add & pop4.62216.393.75e-5
10,000 fib add & pop354.572.820.00
doubly-linked-list
-
test nametime taken (ms)executions per secsample deviation
1,000,000 unshift208.214.800.03
1,000,000 unshift & shift172.475.800.03
1,000,000 insertBefore319.073.130.07
+
test nametime taken (ms)executions per secsample deviation
1,000,000 unshift225.574.430.02
1,000,000 unshift & shift164.916.060.02
1,000,000 insertBefore342.062.920.09
singly-linked-list
-
test nametime taken (ms)executions per secsample deviation
10,000 push & pop222.144.500.01
10,000 insertBefore246.454.060.01
+
test nametime taken (ms)executions per secsample deviation
10,000 push & pop224.204.460.02
10,000 insertBefore244.964.080.00
max-priority-queue
-
test nametime taken (ms)executions per secsample deviation
10,000 refill & poll11.6186.102.55e-4
+
test nametime taken (ms)executions per secsample deviation
10,000 refill & poll11.4587.321.74e-4
deque
-
test nametime taken (ms)executions per secsample deviation
1,000,000 push219.764.550.05
1,000,000 shift25.5739.100.00
+
test nametime taken (ms)executions per secsample deviation
1,000,000 push222.744.490.08
1,000,000 shift26.4837.770.00
queue
-
test nametime taken (ms)executions per secsample deviation
1,000,000 push46.2021.640.01
1,000,000 push & shift93.6010.680.01
+
test nametime taken (ms)executions per secsample deviation
1,000,000 push45.5021.980.01
1,000,000 push & shift80.1012.480.00
trie
-
test nametime taken (ms)executions per secsample deviation
100,000 push57.9417.260.01
100,000 getWords118.458.440.03
+
test nametime taken (ms)executions per secsample deviation
100,000 push56.9917.550.01
100,000 getWords98.4310.160.01
[//]: # (No deletion!!! End of Replace Section) \ No newline at end of file diff --git a/package.json b/package.json index b35f5fd3..e464d1ba 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "data-structure-typed", - "version": "1.42.9", + "version": "1.43.0", "description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.", "main": "dist/cjs/src/index.js", "module": "dist/mjs/src/index.js", diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index de329200..a32019d1 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -108,8 +108,7 @@ export class BinaryTreeNode = BinaryTree * @template N - The type of the binary tree's nodes. */ export class BinaryTree = BinaryTreeNode>> - implements IBinaryTree -{ + implements IBinaryTree { iterationType: IterationType = IterationType.ITERATIVE; /** @@ -173,21 +172,18 @@ export class BinaryTree = BinaryTreeNode */ 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]); + const queue = new Queue([root]); while (queue.size > 0) { - const cur = queue.shift(); - if (cur) { - if (newNode && cur.key === newNode.key) { - cur.value = newNode.value; - return; - } - const inserted = this._addTo(newNode, cur); - if (inserted !== undefined) return inserted; - if (cur.left) queue.push(cur.left); - if (cur.right) queue.push(cur.right); - } else return; + const cur = queue.shift()!; + if (newNode && cur.key === newNode.key) { + cur.value = newNode.value; + return; + } + const inserted = this._addTo(newNode, cur); + if (inserted !== undefined) return inserted; + if (cur.left) queue.push(cur.left); + if (cur.right) queue.push(cur.right); } - return; }; let inserted: N | null | undefined, needInsert: N | null | undefined; @@ -224,7 +220,7 @@ export class BinaryTree = BinaryTreeNode /** * Time Complexity: O(k * n) "n" is the number of nodes in the tree, and "k" is the number of keys to be inserted. * Space Complexity: O(1) - * + * * The `addMany` function takes an array of keys or nodes and an optional array of values, and adds * each key-value pair to a data structure. * @param {(BTNKey | N |null | undefined)[]} keysOrNodes - An array of keys or nodes to be added to @@ -235,7 +231,7 @@ export class BinaryTree = BinaryTreeNode * keys or nodes during the add operation. * @returns The function `addMany` returns an array of `N`, `null`, or `undefined` values. */ - addMany(keysOrNodes: (BTNKey | N |null | undefined)[], values?: (V | undefined)[]): (N | null | undefined)[] { + addMany(keysOrNodes: (BTNKey | N | null | undefined)[], values?: (V | undefined)[]): (N | null | undefined)[] { // TODO not sure addMany not be run multi times return keysOrNodes.map((keyOrNode, i) => { if (keyOrNode instanceof BinaryTreeNode) { @@ -259,7 +255,7 @@ export class BinaryTree = BinaryTreeNode /** * Time Complexity: O(k * n) "n" is the number of nodes in the tree, and "k" is the number of keys to be inserted. * Space Complexity: O(1) - * + * * The `refill` function clears the binary tree and adds multiple nodes with the given IDs or nodes and optional data. * @param {(BTNKey | N)[]} keysOrNodes - The `keysOrNodes` parameter is an array that can contain either * `BTNKey` or `N` values. @@ -287,7 +283,7 @@ export class BinaryTree = BinaryTreeNode /** * 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 @@ -305,7 +301,7 @@ export class BinaryTree = BinaryTreeNode ): BiTreeDeleteResult[] { const deletedResult: BiTreeDeleteResult[] = []; if (!this.root) return deletedResult; - if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C; + if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C; const curr = this.getNode(identifier, callback); if (!curr) return deletedResult; @@ -328,17 +324,20 @@ export class BinaryTree = BinaryTreeNode needBalanced = parent; } } else { - const leftSubTreeRightMost = curr.left ? this.getRightMost(curr.left) : null; - if (leftSubTreeRightMost) { - const parentOfLeftSubTreeMax = leftSubTreeRightMost.parent; - orgCurrent = this._swap(curr, leftSubTreeRightMost); - if (parentOfLeftSubTreeMax) { - if (parentOfLeftSubTreeMax.right === leftSubTreeRightMost) - parentOfLeftSubTreeMax.right = leftSubTreeRightMost.left; - else parentOfLeftSubTreeMax.left = leftSubTreeRightMost.left; - needBalanced = parentOfLeftSubTreeMax; + if (curr.left) { + const leftSubTreeRightMost = this.getRightMost(curr.left); + if (leftSubTreeRightMost) { + const parentOfLeftSubTreeMax = leftSubTreeRightMost.parent; + orgCurrent = this._swap(curr, leftSubTreeRightMost); + if (parentOfLeftSubTreeMax) { + if (parentOfLeftSubTreeMax.right === leftSubTreeRightMost) + parentOfLeftSubTreeMax.right = leftSubTreeRightMost.left; + else parentOfLeftSubTreeMax.left = leftSubTreeRightMost.left; + needBalanced = parentOfLeftSubTreeMax; + } } } + } this._size = this.size - 1; @@ -354,7 +353,7 @@ export class BinaryTree = BinaryTreeNode /** * Time Complexity: O(n) * Space Complexity: O(1) - * + * * The function calculates the depth of a given node in a binary tree. * @param {BTNKey | N | null | undefined} distNode - The `distNode` parameter represents the node in * the binary tree whose depth we want to find. It can be of type `BTNKey`, `N`, `null`, or @@ -388,7 +387,7 @@ export class BinaryTree = BinaryTreeNode /** * Time Complexity: O(n) * Space Complexity: O(log n) - * + * * The function `getHeight` calculates the maximum height of a binary tree using either recursive or * iterative traversal. * @param {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter represents the @@ -413,11 +412,7 @@ export class BinaryTree = BinaryTreeNode return _getMaxHeight(beginRoot); } else { - if (!beginRoot) { - return -1; - } - - const stack: {node: N; depth: number}[] = [{node: beginRoot, depth: 0}]; + const stack: { node: N; depth: number }[] = [{node: beginRoot, depth: 0}]; let maxHeight = 0; while (stack.length > 0) { @@ -425,7 +420,7 @@ export class BinaryTree = BinaryTreeNode if (node.left) stack.push({node: node.left, depth: depth + 1}); if (node.right) stack.push({node: node.right, depth: depth + 1}); - + maxHeight = Math.max(maxHeight, depth); } @@ -442,7 +437,7 @@ export class BinaryTree = BinaryTreeNode /** * Time Complexity: O(n) * Space Complexity: O(log n) - * + * * The `getMinHeight` function calculates the minimum height of a binary tree using either a * recursive or iterative approach. * @param {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter represents the @@ -455,7 +450,7 @@ export class BinaryTree = BinaryTreeNode getMinHeight(beginRoot: BTNKey | N | null | undefined = this.root, iterationType = this.iterationType): number { beginRoot = this.ensureNotKey(beginRoot); if (!beginRoot) return -1; - + if (iterationType === IterationType.RECURSIVE) { const _getMinHeight = (cur: N | null | undefined): number => { if (!cur) return 0; @@ -503,7 +498,7 @@ export class BinaryTree = BinaryTreeNode /** * Time Complexity: O(n) * Space Complexity: O(log n) - * + * * The function checks if a binary tree is perfectly balanced by comparing the minimum height and the * height of the tree. * @param {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting point @@ -548,7 +543,7 @@ export class BinaryTree = BinaryTreeNode /** * Time Complexity: O(n) * Space Complexity: O(log n). - * + * * The function `getNodes` retrieves nodes from a binary tree based on a given identifier and * callback function. * @param {ReturnType | null | undefined} identifier - The `identifier` parameter is the value @@ -577,11 +572,10 @@ export class BinaryTree = BinaryTreeNode beginRoot: BTNKey | N | null | undefined = this.root, iterationType = this.iterationType ): N[] { - if (!beginRoot) return []; - if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C; + if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C; beginRoot = this.ensureNotKey(beginRoot); if (!beginRoot) return []; - + const ans: N[] = []; if (iterationType === IterationType.RECURSIVE) { @@ -642,7 +636,7 @@ export class BinaryTree = BinaryTreeNode /** * Time Complexity: O(n) - * + * * The function checks if a Binary Tree Node with a specific identifier exists in the tree. * @param {ReturnType | null | undefined} identifier - The `identifier` parameter is the value * that you want to search for in the binary tree. It can be of any type that is returned by the @@ -666,7 +660,7 @@ export class BinaryTree = BinaryTreeNode beginRoot: BTNKey | N | null | undefined = this.root, iterationType = this.iterationType ): boolean { - if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C; + if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C; return this.getNodes(identifier, callback, true, beginRoot, iterationType).length > 0; } @@ -700,7 +694,7 @@ export class BinaryTree = BinaryTreeNode /** * Time Complexity: O(n) * Space Complexity: O(log n) - * + * * The function `getNode` returns the first node that matches the given identifier and callback * function. * @param {ReturnType | null | undefined} identifier - The `identifier` parameter is the value @@ -724,7 +718,7 @@ export class BinaryTree = BinaryTreeNode beginRoot: BTNKey | N | null | undefined = this.root, iterationType = this.iterationType ): N | null | undefined { - if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C; + if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C; return this.getNodes(identifier, callback, true, beginRoot, iterationType)[0] ?? null; } @@ -737,7 +731,7 @@ export class BinaryTree = BinaryTreeNode /** * 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 {BTNKey} key - The `key` parameter is the key value that we are searching for in the tree. @@ -772,7 +766,7 @@ export class BinaryTree = BinaryTreeNode } } } - + /** * The function `ensureNotKey` returns the node corresponding to the given key if it is a valid node * key, otherwise it returns the key itself. @@ -787,7 +781,7 @@ export class BinaryTree = BinaryTreeNode ensureNotKey(key: BTNKey | N | null | undefined, iterationType = IterationType.ITERATIVE): N | null | undefined { return this.isNodeKey(key) ? this.getNodeByKey(key, iterationType) : key; } - + get>( identifier: BTNKey, callback?: C, @@ -813,11 +807,11 @@ export class BinaryTree = BinaryTreeNode * Time Complexity: O(n) * Space Complexity: O(log n) */ - + /** * 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. * @param {ReturnType | null | undefined} identifier - The `identifier` parameter is the value @@ -839,14 +833,14 @@ export class BinaryTree = BinaryTreeNode get>( identifier: ReturnType | null | undefined, callback: C = this._defaultOneParamCallback as C, - beginRoot:BTNKey | N | null | undefined = this.root, + beginRoot: BTNKey | N | null | undefined = this.root, iterationType = this.iterationType ): V | undefined { - if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C; + if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C; return this.getNode(identifier, callback, beginRoot, iterationType)?.value ?? undefined; } - + /** * Clear the binary tree, removing all nodes. */ @@ -871,7 +865,7 @@ export class BinaryTree = BinaryTreeNode /** * 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 {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter represents the @@ -886,9 +880,9 @@ export class BinaryTree = BinaryTreeNode // TODO to support get path through passing key const result: N[] = []; beginRoot = this.ensureNotKey(beginRoot); - + if (!beginRoot) return result; - + while (beginRoot.parent) { // Array.push + Array.reverse is more efficient than Array.unshift // TODO may consider using Deque, so far this is not the performance bottleneck @@ -907,7 +901,7 @@ export class BinaryTree = BinaryTreeNode /** * 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 {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting point @@ -949,7 +943,7 @@ export class BinaryTree = BinaryTreeNode /** * Time Complexity: O(log n) * Space Complexity: O(1) - * + * * The function `getRightMost` returns the rightmost node in a binary tree, either recursively or * iteratively. * @param {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter represents the @@ -992,7 +986,7 @@ export class BinaryTree = BinaryTreeNode /** * Time Complexity: O(n) * Space Complexity: O(1) - * + * * The function `isSubtreeBST` checks if a given binary tree is a valid binary search tree. * @param {BTNKey | N | 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. @@ -1040,7 +1034,7 @@ export class BinaryTree = BinaryTreeNode /** * Time Complexity: O(n) * Space Complexity: O(1) - * + * * The function checks if a binary tree is a binary search tree. * @param iterationType - The parameter "iterationType" is used to specify the type of iteration to * be used when checking if the binary tree is a binary search tree (BST). It is an optional @@ -1074,15 +1068,15 @@ export class BinaryTree = BinaryTreeNode includeNull?: true ): ReturnType[]; - /** + /** * Time complexity: O(n) * Space complexity: O(log n) */ - + /** * Time complexity: O(n) * Space complexity: O(log n) - * + * * The function `subTreeTraverse` traverses a binary tree and applies a callback function to each * node, either recursively or iteratively. * @param {C} callback - The `callback` parameter is a function that will be called for each node in @@ -1146,7 +1140,7 @@ export class BinaryTree = BinaryTreeNode } return ans; } - + /** * 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. @@ -1171,7 +1165,7 @@ export class BinaryTree = BinaryTreeNode * @param {any} node - The parameter `node` is of type `any`, which means it can be any data type. * @returns a boolean value. */ - isNodeOrNull(node: any): node is (N | null){ + isNodeOrNull(node: any): node is (N | null) { return this.isRealNode(node) || node === null; } @@ -1181,7 +1175,7 @@ export class BinaryTree = BinaryTreeNode * data type. * @returns a boolean value indicating whether the potentialKey is of type number or not. */ - isNodeKey(potentialKey: any) : potentialKey is number { + isNodeKey(potentialKey: any): potentialKey is number { return typeof potentialKey === 'number'; } @@ -1213,11 +1207,11 @@ export class BinaryTree = BinaryTreeNode * 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. @@ -1291,7 +1285,7 @@ export class BinaryTree = BinaryTreeNode _traverse(beginRoot); } else { // 0: visit, 1: print - const stack: {opt: 0 | 1; node: N | null | undefined}[] = [{opt: 0, node: beginRoot}]; + const stack: { opt: 0 | 1; node: N | null | undefined }[] = [{opt: 0, node: beginRoot}]; while (stack.length > 0) { const cur = stack.pop(); @@ -1362,7 +1356,7 @@ export class BinaryTree = BinaryTreeNode /** * 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. * @param {C} callback - The `callback` parameter is a function that will be called for each node in @@ -1460,11 +1454,11 @@ export class BinaryTree = BinaryTreeNode * Space complexity: O(n) */ - + /** * Time complexity: O(n) * 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. @@ -1529,7 +1523,7 @@ export class BinaryTree = BinaryTreeNode return levelsNodes; } - getPredecessor(node: N ): N + getPredecessor(node: N): N /** @@ -1538,7 +1532,7 @@ export class BinaryTree = BinaryTreeNode * `null`, or `undefined`. * @returns The function `getPredecessor` returns a value of type `N | undefined`. */ - getPredecessor(node: BTNKey | N | null | undefined): N | undefined{ + getPredecessor(node: BTNKey | N | null | undefined): N | undefined { node = this.ensureNotKey(node); if (!this.isRealNode(node)) return undefined; @@ -1697,7 +1691,7 @@ export class BinaryTree = BinaryTreeNode * @returns The `*[Symbol.iterator]` method returns a generator object that yields the keys of the * binary tree nodes in a specific order. */ - *[Symbol.iterator](node = this.root): Generator { + * [Symbol.iterator](node = this.root): Generator { if (!node) { return; } @@ -1736,7 +1730,7 @@ export class BinaryTree = BinaryTreeNode * @param {N} destNode - The destination node to swap. * @returns {N} - The destination node after the swap. */ - protected _swap(srcNode: BTNKey | N | null | undefined, destNode:BTNKey | N | null | undefined): N | undefined{ + protected _swap(srcNode: BTNKey | N | null | undefined, destNode: BTNKey | N | null | undefined): N | undefined { srcNode = this.ensureNotKey(srcNode); destNode = this.ensureNotKey(destNode); @@ -1826,7 +1820,7 @@ export class BinaryTree = BinaryTreeNode } }; - const _displayAux = (node: N | null | undefined): [string[], number, number, number] => { + const _displayAux = (node: N | null | undefined): [string[], number, number, number] => { if (!this.isRealNode(node)) { return [[], 0, 0, 0]; } 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 1af0ce6b..e21e1a32 100644 --- a/test/unit/data-structures/binary-tree/avl-tree.test.ts +++ b/test/unit/data-structures/binary-tree/avl-tree.test.ts @@ -7,6 +7,7 @@ describe('AVL Tree Test', () => { for (const i of arr) tree.add(i, i); + tree.add(null); const node6 = tree.getNode(6); expect(node6 && tree.getHeight(node6)).toBe(3); @@ -42,7 +43,7 @@ describe('AVL Tree Test', () => { expect(bfs[0].key).toBe(8); expect(bfs[bfs.length - 1].key).toBe(16); - expect(tree.delete(11)[0].deleted?.key).toBe(11); + expect(tree.delete(tree.getNode(11))[0].deleted?.key).toBe(11); expect(tree.isAVLBalanced()).toBe(true); expect(node15 && tree.getHeight(node15)).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 32b04aea..077a02c1 100644 --- a/test/unit/data-structures/binary-tree/binary-tree.test.ts +++ b/test/unit/data-structures/binary-tree/binary-tree.test.ts @@ -1,5 +1,6 @@ import {BinaryTree, BinaryTreeNode, IterationType} from '../../../../src'; import {getRandomIntArray} from "../../../utils"; +import {FamilyPosition} from "binary-tree-typed"; // import {isDebugTest} from '../../../config'; // const isDebug = isDebugTest; @@ -65,8 +66,25 @@ describe('BinaryTreeNode', () => { root.right = rightChild; expect(leftChild.familyPosition).toBe('LEFT'); + leftChild.right = new BinaryTreeNode(4); expect(rightChild.familyPosition).toBe('RIGHT'); expect(root.familyPosition).toBe('ROOT'); + expect(leftChild.familyPosition).toBe('ROOT_LEFT'); + rightChild.left = new BinaryTreeNode(5); + expect(rightChild.familyPosition).toBe('ROOT_RIGHT'); + + }); + + it('should determine only right child family position correctly', () => { + const root = new BinaryTreeNode(1); + const rightChild = new BinaryTreeNode(3); + const isolated = new BinaryTreeNode(2); + + root.right = rightChild; + + expect(rightChild.familyPosition).toBe('RIGHT'); + expect(isolated.familyPosition).toBe(FamilyPosition.ISOLATED); + expect(root.familyPosition).toBe('ROOT'); }); }); @@ -87,19 +105,43 @@ describe('BinaryTree', () => { expect(tree.size).toBe(1); }); - it('should delete a node', () => { + it('should delete nodes', () => { + expect(tree.getHeight(tree.root, IterationType.ITERATIVE)).toBe(-1) + expect(tree.getMinHeight()).toBe(-1) const node = tree.add(1); expect(tree.size).toBe(1); + const leftChild = new BinaryTreeNode(2); + const rightChild = new BinaryTreeNode(3); + tree.add(leftChild); + tree.add(rightChild); + const root = tree.root; + + + expect(leftChild.familyPosition).toBe('LEFT'); + tree.add(null); + tree.add(new BinaryTreeNode(4)); + expect(rightChild.familyPosition).toBe('RIGHT'); + expect(root?.familyPosition).toBe('ROOT'); + expect(leftChild.familyPosition).toBe('ROOT_LEFT'); + tree.add(new BinaryTreeNode(5)); + expect(rightChild.familyPosition).toBe('ROOT_RIGHT'); + + tree.delete(new BinaryTreeNode(200)); + tree.delete(rightChild) + if (node) { - const result = tree.delete(node, node => node); + const result = tree.delete(node); expect(result).toHaveLength(1); - expect(tree.size).toBe(0); + expect(tree.size).toBe(3); + expect(tree.getMinHeight(tree.root, IterationType.RECURSIVE)).toBe(1) } + }); it('should add and find nodes', () => { tree.add(1, 1); + tree.add(undefined); tree.add(2, 2); tree.add(3, 3); @@ -191,6 +233,15 @@ describe('BinaryTree', () => { expect(tree.isSubtreeBST(tree.getNode(4), IterationType.ITERATIVE)).toBe(true); }); + it('should isSubtreeBST', () => { + tree.addMany([4, 2, 6, 1, 3, 5, 7, 4]); + + expect(tree.isSubtreeBST(tree.getNode(4), IterationType.RECURSIVE)).toBe(true); + expect(tree.isSubtreeBST(tree.getNode(4), IterationType.ITERATIVE)).toBe(true); + expect(tree.getNodes(2, undefined, false, null)).toEqual([]) + expect(tree.getNodes(tree.getNodeByKey(2), undefined, false, tree.root)).toEqual([tree.getNodeByKey(2)]) + }); + it('should subTreeTraverse', () => { tree.addMany([4, 2, 6, null, 1, 3, null, 5, null, 7]); expect(tree.subTreeTraverse(node => node.key, tree.getNode(6), IterationType.ITERATIVE)).toEqual([6, 3, 7]);