test: Testing coverage has increased to 91.2%.

This commit is contained in:
Revone 2023-11-10 23:44:24 +08:00
parent fd416c5d6e
commit a1cfac93da
6 changed files with 147 additions and 101 deletions

View file

@ -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

View file

@ -728,40 +728,40 @@ optimal approach to data structure design.
[//]: # (No deletion!!! Start of Replace Section)
<div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>avl-tree</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 add randomly</td><td>32.91</td><td>30.38</td><td>6.85e-4</td></tr><tr><td>10,000 add & delete randomly</td><td>73.84</td><td>13.54</td><td>0.00</td></tr><tr><td>10,000 addMany</td><td>43.79</td><td>22.84</td><td>0.00</td></tr><tr><td>10,000 get</td><td>29.07</td><td>34.40</td><td>7.13e-4</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 add randomly</td><td>33.60</td><td>29.76</td><td>0.00</td></tr><tr><td>10,000 add & delete randomly</td><td>72.39</td><td>13.81</td><td>0.01</td></tr><tr><td>10,000 addMany</td><td>41.06</td><td>24.35</td><td>0.00</td></tr><tr><td>10,000 get</td><td>28.01</td><td>35.71</td><td>0.00</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>binary-tree</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000 add randomly</td><td>12.65</td><td>79.06</td><td>2.71e-4</td></tr><tr><td>1,000 add & delete randomly</td><td>16.43</td><td>60.86</td><td>0.00</td></tr><tr><td>1,000 addMany</td><td>10.25</td><td>97.59</td><td>1.46e-4</td></tr><tr><td>1,000 get</td><td>18.02</td><td>55.48</td><td>1.61e-4</td></tr><tr><td>1,000 dfs</td><td>156.29</td><td>6.40</td><td>0.00</td></tr><tr><td>1,000 bfs</td><td>56.06</td><td>17.84</td><td>5.29e-4</td></tr><tr><td>1,000 morris</td><td>260.47</td><td>3.84</td><td>0.00</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000 add randomly</td><td>12.64</td><td>79.09</td><td>6.90e-4</td></tr><tr><td>1,000 add & delete randomly</td><td>16.03</td><td>62.38</td><td>5.30e-4</td></tr><tr><td>1,000 addMany</td><td>10.44</td><td>95.78</td><td>0.00</td></tr><tr><td>1,000 get</td><td>18.19</td><td>54.98</td><td>3.11e-4</td></tr><tr><td>1,000 dfs</td><td>154.71</td><td>6.46</td><td>0.00</td></tr><tr><td>1,000 bfs</td><td>56.97</td><td>17.55</td><td>8.92e-4</td></tr><tr><td>1,000 morris</td><td>260.71</td><td>3.84</td><td>0.00</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>bst</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 add randomly</td><td>31.67</td><td>31.58</td><td>9.08e-4</td></tr><tr><td>10,000 add & delete randomly</td><td>73.30</td><td>13.64</td><td>0.01</td></tr><tr><td>10,000 addMany</td><td>30.35</td><td>32.95</td><td>0.00</td></tr><tr><td>10,000 get</td><td>29.49</td><td>33.91</td><td>7.80e-4</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 add randomly</td><td>29.57</td><td>33.81</td><td>2.75e-4</td></tr><tr><td>10,000 add & delete randomly</td><td>70.78</td><td>14.13</td><td>0.00</td></tr><tr><td>10,000 addMany</td><td>29.10</td><td>34.36</td><td>6.84e-4</td></tr><tr><td>10,000 get</td><td>28.75</td><td>34.78</td><td>6.05e-4</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>rb-tree</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>100,000 add randomly</td><td>90.85</td><td>11.01</td><td>0.01</td></tr><tr><td>100,000 add & delete randomly</td><td>238.18</td><td>4.20</td><td>0.07</td></tr><tr><td>100,000 getNode</td><td>111.04</td><td>9.01</td><td>0.03</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>100,000 add randomly</td><td>88.55</td><td>11.29</td><td>0.01</td></tr><tr><td>100,000 add & delete randomly</td><td>220.41</td><td>4.54</td><td>0.01</td></tr><tr><td>100,000 getNode</td><td>37.52</td><td>26.65</td><td>2.68e-4</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>directed-graph</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000 addVertex</td><td>0.10</td><td>9609.82</td><td>5.99e-6</td></tr><tr><td>1,000 addEdge</td><td>6.43</td><td>155.61</td><td>4.69e-4</td></tr><tr><td>1,000 getVertex</td><td>0.05</td><td>2.10e+4</td><td>2.90e-6</td></tr><tr><td>1,000 getEdge</td><td>23.98</td><td>41.70</td><td>0.01</td></tr><tr><td>tarjan</td><td>225.87</td><td>4.43</td><td>0.02</td></tr><tr><td>tarjan all</td><td>229.79</td><td>4.35</td><td>0.03</td></tr><tr><td>topologicalSort</td><td>192.07</td><td>5.21</td><td>0.03</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000 addVertex</td><td>0.10</td><td>9804.12</td><td>1.07e-6</td></tr><tr><td>1,000 addEdge</td><td>6.06</td><td>165.11</td><td>1.66e-4</td></tr><tr><td>1,000 getVertex</td><td>0.05</td><td>2.17e+4</td><td>3.48e-7</td></tr><tr><td>1,000 getEdge</td><td>23.26</td><td>43.00</td><td>0.00</td></tr><tr><td>tarjan</td><td>223.27</td><td>4.48</td><td>0.01</td></tr><tr><td>tarjan all</td><td>224.27</td><td>4.46</td><td>0.00</td></tr><tr><td>topologicalSort</td><td>179.19</td><td>5.58</td><td>0.00</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>heap</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 add & pop</td><td>4.67</td><td>214.00</td><td>7.34e-5</td></tr><tr><td>10,000 fib add & pop</td><td>370.25</td><td>2.70</td><td>0.00</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 add & pop</td><td>4.62</td><td>216.39</td><td>3.75e-5</td></tr><tr><td>10,000 fib add & pop</td><td>354.57</td><td>2.82</td><td>0.00</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>doubly-linked-list</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 unshift</td><td>208.21</td><td>4.80</td><td>0.03</td></tr><tr><td>1,000,000 unshift & shift</td><td>172.47</td><td>5.80</td><td>0.03</td></tr><tr><td>1,000,000 insertBefore</td><td>319.07</td><td>3.13</td><td>0.07</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 unshift</td><td>225.57</td><td>4.43</td><td>0.02</td></tr><tr><td>1,000,000 unshift & shift</td><td>164.91</td><td>6.06</td><td>0.02</td></tr><tr><td>1,000,000 insertBefore</td><td>342.06</td><td>2.92</td><td>0.09</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>singly-linked-list</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 push & pop</td><td>222.14</td><td>4.50</td><td>0.01</td></tr><tr><td>10,000 insertBefore</td><td>246.45</td><td>4.06</td><td>0.01</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 push & pop</td><td>224.20</td><td>4.46</td><td>0.02</td></tr><tr><td>10,000 insertBefore</td><td>244.96</td><td>4.08</td><td>0.00</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>max-priority-queue</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 refill & poll</td><td>11.61</td><td>86.10</td><td>2.55e-4</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 refill & poll</td><td>11.45</td><td>87.32</td><td>1.74e-4</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>deque</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 push</td><td>219.76</td><td>4.55</td><td>0.05</td></tr><tr><td>1,000,000 shift</td><td>25.57</td><td>39.10</td><td>0.00</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 push</td><td>222.74</td><td>4.49</td><td>0.08</td></tr><tr><td>1,000,000 shift</td><td>26.48</td><td>37.77</td><td>0.00</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>queue</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 push</td><td>46.20</td><td>21.64</td><td>0.01</td></tr><tr><td>1,000,000 push & shift</td><td>93.60</td><td>10.68</td><td>0.01</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 push</td><td>45.50</td><td>21.98</td><td>0.01</td></tr><tr><td>1,000,000 push & shift</td><td>80.10</td><td>12.48</td><td>0.00</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>trie</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>100,000 push</td><td>57.94</td><td>17.26</td><td>0.01</td></tr><tr><td>100,000 getWords</td><td>118.45</td><td>8.44</td><td>0.03</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>100,000 push</td><td>56.99</td><td>17.55</td><td>0.01</td></tr><tr><td>100,000 getWords</td><td>98.43</td><td>10.16</td><td>0.01</td></tr></table></div>
</div>
[//]: # (No deletion!!! End of Replace Section)

View file

@ -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",

View file

@ -108,8 +108,7 @@ export class BinaryTreeNode<V = any, N extends BinaryTreeNode<V, N> = BinaryTree
* @template N - The type of the binary tree's nodes.
*/
export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode<V, BinaryTreeNodeNested<V>>>
implements IBinaryTree<V, N>
{
implements IBinaryTree<V, N> {
iterationType: IterationType = IterationType.ITERATIVE;
/**
@ -173,21 +172,18 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = 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<N | null>([root]);
const queue = new Queue<N>([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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<C> | null | undefined} identifier - The identifier parameter is the value or
@ -305,7 +301,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
): BiTreeDeleteResult<N>[] {
const deletedResult: BiTreeDeleteResult<N>[] = [];
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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<C> | null | undefined} identifier - The `identifier` parameter is the value
@ -577,11 +572,10 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
/**
* Time Complexity: O(n)
*
*
* The function checks if a Binary Tree Node with a specific identifier exists in the tree.
* @param {ReturnType<C> | 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<C> | null | undefined} identifier - The `identifier` parameter is the value
@ -724,7 +718,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
ensureNotKey(key: BTNKey | N | null | undefined, iterationType = IterationType.ITERATIVE): N | null | undefined {
return this.isNodeKey(key) ? this.getNodeByKey(key, iterationType) : key;
}
get<C extends BTNCallback<N, BTNKey>>(
identifier: BTNKey,
callback?: C,
@ -813,11 +807,11 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = 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<C> | null | undefined} identifier - The `identifier` parameter is the value
@ -839,14 +833,14 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
get<C extends BTNCallback<N>>(
identifier: ReturnType<C> | 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
includeNull?: true
): ReturnType<C>[];
/**
* Time complexity: O(n)
* Space complexity: O(log n)
*/
/**
* 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return levelsNodes;
}
getPredecessor(node: N ): N
getPredecessor(node: N): N
/**
@ -1538,7 +1532,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<BTNKey, void, undefined> {
* [Symbol.iterator](node = this.root): Generator<BTNKey, void, undefined> {
if (!node) {
return;
}
@ -1736,7 +1730,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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];
}

View file

@ -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);

View file

@ -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<number>(4);
expect(rightChild.familyPosition).toBe('RIGHT');
expect(root.familyPosition).toBe('ROOT');
expect(leftChild.familyPosition).toBe('ROOT_LEFT');
rightChild.left = new BinaryTreeNode<number>(5);
expect(rightChild.familyPosition).toBe('ROOT_RIGHT');
});
it('should determine only right child family position correctly', () => {
const root = new BinaryTreeNode<number>(1);
const rightChild = new BinaryTreeNode<number>(3);
const isolated = new BinaryTreeNode<number>(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<number>(2);
const rightChild = new BinaryTreeNode<number>(3);
tree.add(leftChild);
tree.add(rightChild);
const root = tree.root;
expect(leftChild.familyPosition).toBe('LEFT');
tree.add(null);
tree.add(new BinaryTreeNode<number>(4));
expect(rightChild.familyPosition).toBe('RIGHT');
expect(root?.familyPosition).toBe('ROOT');
expect(leftChild.familyPosition).toBe('ROOT_LEFT');
tree.add(new BinaryTreeNode<number>(5));
expect(rightChild.familyPosition).toBe('ROOT_RIGHT');
tree.delete(new BinaryTreeNode<number>(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]);