mirror of
https://github.com/zrwusa/data-structure-typed.git
synced 2024-11-23 12:54:04 +00:00
[binary-tree] Perfectly solved the null problem, in BST, AVLTree, and TreeMultiset, only 'undefined' is used as the empty node.
This commit is contained in:
parent
8a518f95b7
commit
996fd128ed
|
@ -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
|
||||
|
||||
|
|
24
README.md
24
README.md
|
@ -636,40 +636,40 @@ optimal approach to data structure design.
|
|||
[//]: # (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>31.93</td><td>31.32</td><td>2.30e-4</td></tr><tr><td>10,000 add & delete randomly</td><td>69.12</td><td>14.47</td><td>0.00</td></tr><tr><td>10,000 addMany</td><td>41.14</td><td>24.31</td><td>1.60e-4</td></tr><tr><td>10,000 get</td><td>28.68</td><td>34.86</td><td>7.65e-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>30.33</td><td>32.97</td><td>3.56e-4</td></tr><tr><td>10,000 add & delete randomly</td><td>66.10</td><td>15.13</td><td>0.00</td></tr><tr><td>10,000 addMany</td><td>39.44</td><td>25.35</td><td>3.62e-4</td></tr><tr><td>10,000 get</td><td>27.06</td><td>36.96</td><td>2.52e-4</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>13.12</td><td>76.21</td><td>3.40e-4</td></tr><tr><td>1,000 add & delete randomly</td><td>16.33</td><td>61.22</td><td>4.17e-4</td></tr><tr><td>1,000 addMany</td><td>10.96</td><td>91.22</td><td>3.99e-4</td></tr><tr><td>1,000 get</td><td>18.65</td><td>53.63</td><td>4.20e-4</td></tr><tr><td>1,000 dfs</td><td>71.82</td><td>13.92</td><td>0.00</td></tr><tr><td>1,000 bfs</td><td>58.95</td><td>16.96</td><td>0.00</td></tr><tr><td>1,000 morris</td><td>37.46</td><td>26.70</td><td>4.60e-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>1,000 add randomly</td><td>12.90</td><td>77.52</td><td>1.09e-4</td></tr><tr><td>1,000 add & delete randomly</td><td>16.13</td><td>61.99</td><td>1.61e-4</td></tr><tr><td>1,000 addMany</td><td>10.74</td><td>93.09</td><td>1.00e-4</td></tr><tr><td>1,000 get</td><td>18.09</td><td>55.28</td><td>1.90e-4</td></tr><tr><td>1,000 dfs</td><td>71.12</td><td>14.06</td><td>7.83e-4</td></tr><tr><td>1,000 bfs</td><td>57.24</td><td>17.47</td><td>4.17e-4</td></tr><tr><td>1,000 morris</td><td>37.29</td><td>26.81</td><td>3.77e-4</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>32.98</td><td>30.32</td><td>0.00</td></tr><tr><td>10,000 add & delete randomly</td><td>74.47</td><td>13.43</td><td>0.00</td></tr><tr><td>10,000 addMany</td><td>29.93</td><td>33.41</td><td>6.02e-4</td></tr><tr><td>10,000 get</td><td>29.92</td><td>33.42</td><td>8.61e-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>31.58</td><td>31.67</td><td>0.00</td></tr><tr><td>10,000 add & delete randomly</td><td>71.09</td><td>14.07</td><td>8.99e-4</td></tr><tr><td>10,000 addMany</td><td>29.68</td><td>33.69</td><td>0.00</td></tr><tr><td>10,000 get</td><td>28.55</td><td>35.03</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'>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>80.49</td><td>12.42</td><td>0.01</td></tr><tr><td>100,000 add & 1000 delete randomly</td><td>89.97</td><td>11.11</td><td>0.01</td></tr><tr><td>100,000 getNode</td><td>68.63</td><td>14.57</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>100,000 add randomly</td><td>84.64</td><td>11.82</td><td>0.01</td></tr><tr><td>100,000 add & 1000 delete randomly</td><td>81.32</td><td>12.30</td><td>0.01</td></tr><tr><td>100,000 getNode</td><td>61.18</td><td>16.35</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'>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>9878.72</td><td>1.87e-6</td></tr><tr><td>1,000 addEdge</td><td>6.34</td><td>157.78</td><td>2.53e-4</td></tr><tr><td>1,000 getVertex</td><td>0.05</td><td>2.12e+4</td><td>1.05e-6</td></tr><tr><td>1,000 getEdge</td><td>23.08</td><td>43.33</td><td>0.00</td></tr><tr><td>tarjan</td><td>217.75</td><td>4.59</td><td>0.01</td></tr><tr><td>tarjan all</td><td>219.23</td><td>4.56</td><td>0.01</td></tr><tr><td>topologicalSort</td><td>175.73</td><td>5.69</td><td>0.02</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>9637.47</td><td>3.79e-6</td></tr><tr><td>1,000 addEdge</td><td>6.09</td><td>164.18</td><td>1.31e-4</td></tr><tr><td>1,000 getVertex</td><td>0.05</td><td>2.14e+4</td><td>1.35e-6</td></tr><tr><td>1,000 getEdge</td><td>23.91</td><td>41.82</td><td>0.01</td></tr><tr><td>tarjan</td><td>218.65</td><td>4.57</td><td>0.01</td></tr><tr><td>tarjan all</td><td>221.67</td><td>4.51</td><td>0.00</td></tr><tr><td>topologicalSort</td><td>184.34</td><td>5.42</td><td>0.02</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.64</td><td>215.44</td><td>6.89e-5</td></tr><tr><td>10,000 fib add & pop</td><td>357.37</td><td>2.80</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 add & pop</td><td>4.63</td><td>215.77</td><td>4.49e-5</td></tr><tr><td>10,000 fib add & pop</td><td>355.19</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>239.34</td><td>4.18</td><td>0.04</td></tr><tr><td>1,000,000 unshift & shift</td><td>168.74</td><td>5.93</td><td>0.04</td></tr><tr><td>1,000,000 insertBefore</td><td>324.74</td><td>3.08</td><td>0.06</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>213.53</td><td>4.68</td><td>0.02</td></tr><tr><td>1,000,000 unshift & shift</td><td>162.97</td><td>6.14</td><td>0.02</td></tr><tr><td>1,000,000 insertBefore</td><td>335.19</td><td>2.98</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>213.86</td><td>4.68</td><td>0.01</td></tr><tr><td>10,000 insertBefore</td><td>254.02</td><td>3.94</td><td>0.02</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>231.35</td><td>4.32</td><td>0.02</td></tr><tr><td>10,000 insertBefore</td><td>251.49</td><td>3.98</td><td>0.01</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.39</td><td>87.76</td><td>2.14e-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.48</td><td>87.14</td><td>1.91e-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>233.91</td><td>4.28</td><td>0.05</td></tr><tr><td>1,000,000 shift</td><td>25.61</td><td>39.05</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>215.14</td><td>4.65</td><td>0.05</td></tr><tr><td>1,000,000 shift</td><td>25.15</td><td>39.76</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>43.88</td><td>22.79</td><td>0.01</td></tr><tr><td>1,000,000 push & shift</td><td>81.71</td><td>12.24</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>44.15</td><td>22.65</td><td>0.01</td></tr><tr><td>1,000,000 push & shift</td><td>80.87</td><td>12.37</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>59.93</td><td>16.69</td><td>0.01</td></tr><tr><td>100,000 getWords</td><td>93.10</td><td>10.74</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>100,000 push</td><td>61.38</td><td>16.29</td><td>0.01</td></tr><tr><td>100,000 getWords</td><td>104.27</td><td>9.59</td><td>0.02</td></tr></table></div>
|
||||
</div>
|
||||
|
||||
[//]: # (End of Replace Section)
|
|
@ -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",
|
||||
|
|
|
@ -49,13 +49,14 @@ export class AVLTree<V = any, N extends AVLTreeNode<V, N> = AVLTreeNode<V, AVLTr
|
|||
/**
|
||||
* The function overrides the add method of a binary tree node and balances the tree after inserting
|
||||
* a new node.
|
||||
* @param {BTNKey | N | null} keyOrNode - The `keyOrNode` parameter can accept either a
|
||||
* @param {BTNKey | N | undefined} keyOrNode - The `keyOrNode` parameter can accept either a
|
||||
* `BTNKey` or a `N` (which represents a node in the binary tree) or `null`.
|
||||
* @param [value] - The `value` parameter is the value that you want to assign to the new node that you
|
||||
* are adding to the binary search tree.
|
||||
* @returns The method is returning the inserted node (`N`), `null`, 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 === null) return undefined;
|
||||
const inserted = super.add(keyOrNode, value);
|
||||
if (inserted) this._balancePath(inserted);
|
||||
return inserted;
|
||||
|
@ -226,7 +227,7 @@ export class AVLTree<V = any, N extends AVLTreeNode<V, N> = AVLTreeNode<V, AVLTr
|
|||
protected _balanceLR(A: N): void {
|
||||
const parentOfA = A.parent;
|
||||
const B = A.left;
|
||||
let C = null;
|
||||
let C = undefined;
|
||||
if (B) {
|
||||
C = B.right;
|
||||
}
|
||||
|
@ -309,7 +310,7 @@ export class AVLTree<V = any, N extends AVLTreeNode<V, N> = AVLTreeNode<V, AVLTr
|
|||
protected _balanceRL(A: N): void {
|
||||
const parentOfA = A.parent;
|
||||
const B = A.right;
|
||||
let C = null;
|
||||
let C = undefined;
|
||||
if (B) {
|
||||
C = B.left;
|
||||
}
|
||||
|
|
|
@ -123,12 +123,12 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<N | null>([root]);
|
||||
while (queue.size > 0) {
|
||||
|
@ -236,7 +236,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V>): boolean {
|
||||
refill(keysOrNodes: (BTNKey | null | undefined)[] | (N | null | undefined)[], data?: Array<V>): boolean {
|
||||
this.clear();
|
||||
return keysOrNodes.length === this.addMany(keysOrNodes, data).length;
|
||||
}
|
||||
|
||||
delete<C extends BTNCallback<N, BTNKey>>(identifier: BTNKey, callback?: C): BinaryTreeDeletedResult<N>[];
|
||||
|
||||
delete<C extends BTNCallback<N, N>>(identifier: N | null, callback?: C): BinaryTreeDeletedResult<N>[];
|
||||
delete<C extends BTNCallback<N, N>>(identifier: N | null | undefined, callback?: C): BinaryTreeDeletedResult<N>[];
|
||||
|
||||
delete<C extends BTNCallback<N>>(identifier: ReturnType<C>, callback: C): BinaryTreeDeletedResult<N>[];
|
||||
|
||||
|
@ -287,7 +287,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
* `this.defaultOneParamCallback`, which
|
||||
*/
|
||||
delete<C extends BTNCallback<N>>(
|
||||
identifier: ReturnType<C> | null,
|
||||
identifier: ReturnType<C> | null | undefined,
|
||||
callback: C = this.defaultOneParamCallback as C
|
||||
): BinaryTreeDeletedResult<N>[] {
|
||||
const bstDeletedResult: BinaryTreeDeletedResult<N>[] = [];
|
||||
|
@ -297,8 +297,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
} else {
|
||||
const stack: N[] = [];
|
||||
let node: N | null | undefined = beginRoot,
|
||||
last: N | null = null;
|
||||
last: N | null | undefined = null;
|
||||
const depths: Map<N, number> = new Map();
|
||||
|
||||
while (stack.length > 0 || node) {
|
||||
|
@ -465,11 +465,11 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
identifier: BTNKey,
|
||||
callback?: C,
|
||||
onlyOne?: boolean,
|
||||
beginRoot?: N | null,
|
||||
beginRoot?: N | null | undefined,
|
||||
iterationType?: IterationType
|
||||
): N[];
|
||||
|
||||
getNodes<C extends BTNCallback<N, N>>(
|
||||
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<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
identifier: ReturnType<C>,
|
||||
callback: C,
|
||||
onlyOne?: boolean,
|
||||
beginRoot?: N | null,
|
||||
beginRoot?: N | null | undefined,
|
||||
iterationType?: IterationType
|
||||
): N[];
|
||||
|
||||
|
@ -511,7 +511,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
* @returns The function `getNodes` returns an array of nodes (`N[]`).
|
||||
*/
|
||||
getNodes<C extends BTNCallback<N>>(
|
||||
identifier: ReturnType<C> | null,
|
||||
identifier: ReturnType<C> | 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<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
has<C extends BTNCallback<N, BTNKey>>(
|
||||
identifier: BTNKey,
|
||||
callback?: C,
|
||||
beginRoot?: N | null,
|
||||
beginRoot?: N | null | undefined,
|
||||
iterationType?: IterationType
|
||||
): boolean;
|
||||
|
||||
has<C extends BTNCallback<N, N>>(
|
||||
identifier: N | null,
|
||||
identifier: N | null | undefined,
|
||||
callback?: C,
|
||||
beginRoot?: N | null,
|
||||
beginRoot?: N | null | undefined,
|
||||
iterationType?: IterationType
|
||||
): boolean;
|
||||
|
||||
has<C extends BTNCallback<N>>(
|
||||
identifier: ReturnType<C> | null,
|
||||
identifier: ReturnType<C> | null | undefined,
|
||||
callback: C,
|
||||
beginRoot?: N | null,
|
||||
beginRoot?: N | null | undefined,
|
||||
iterationType?: IterationType
|
||||
): boolean;
|
||||
|
||||
|
@ -598,7 +598,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
* @returns a boolean value.
|
||||
*/
|
||||
has<C extends BTNCallback<N>>(
|
||||
identifier: ReturnType<C> | null,
|
||||
identifier: ReturnType<C> | null | undefined,
|
||||
callback: C = this.defaultOneParamCallback as C,
|
||||
beginRoot = this.root,
|
||||
iterationType = this.iterationType
|
||||
|
@ -611,23 +611,23 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
getNode<C extends BTNCallback<N, BTNKey>>(
|
||||
identifier: BTNKey,
|
||||
callback?: C,
|
||||
beginRoot?: N | null,
|
||||
beginRoot?: N | null | undefined,
|
||||
iterationType?: IterationType
|
||||
): N | null;
|
||||
): N | null | undefined;
|
||||
|
||||
getNode<C extends BTNCallback<N, N>>(
|
||||
identifier: N | null,
|
||||
identifier: N | null | undefined,
|
||||
callback?: C,
|
||||
beginRoot?: N | null,
|
||||
beginRoot?: N | null | undefined,
|
||||
iterationType?: IterationType
|
||||
): N | null;
|
||||
): N | null | undefined;
|
||||
|
||||
getNode<C extends BTNCallback<N>>(
|
||||
identifier: ReturnType<C>,
|
||||
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<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
* @returns either the found node (of type N) or null if no node is found.
|
||||
*/
|
||||
getNode<C extends BTNCallback<N>>(
|
||||
identifier: ReturnType<C> | null,
|
||||
identifier: ReturnType<C> | 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<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
get<C extends BTNCallback<N, BTNKey>>(
|
||||
identifier: BTNKey,
|
||||
callback?: C,
|
||||
beginRoot?: N | null,
|
||||
beginRoot?: N | null | undefined,
|
||||
iterationType?: IterationType
|
||||
): V | undefined;
|
||||
|
||||
get<C extends BTNCallback<N, N>>(
|
||||
identifier: N | null,
|
||||
identifier: N | null | undefined,
|
||||
callback?: C,
|
||||
beginRoot?: N | null,
|
||||
beginRoot?: N | null | undefined,
|
||||
iterationType?: IterationType
|
||||
): V | undefined;
|
||||
|
||||
get<C extends BTNCallback<N>>(
|
||||
identifier: ReturnType<C>,
|
||||
callback: C,
|
||||
beginRoot?: N | null,
|
||||
beginRoot?: N | null | undefined,
|
||||
iterationType?: IterationType
|
||||
): V | undefined;
|
||||
|
||||
|
@ -692,7 +692,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
* @returns either the found value (of type V) or undefined if no node value is found.
|
||||
*/
|
||||
get<C extends BTNCallback<N>>(
|
||||
identifier: ReturnType<C> | null,
|
||||
identifier: ReturnType<C> | null | undefined,
|
||||
callback: C = this.defaultOneParamCallback as C,
|
||||
beginRoot = this.root,
|
||||
iterationType = this.iterationType
|
||||
|
@ -728,7 +728,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
|
||||
subTreeTraverse<C extends BTNCallback<N>>(
|
||||
callback?: C,
|
||||
beginRoot?: BTNKey | N | null,
|
||||
beginRoot?: BTNKey | N | null | undefined,
|
||||
iterationType?: IterationType,
|
||||
includeNull?: false
|
||||
): ReturnType<C>[];
|
||||
|
||||
subTreeTraverse<C extends BTNCallback<N>>(
|
||||
callback?: C,
|
||||
beginRoot?: BTNKey | N | null,
|
||||
beginRoot?: BTNKey | N | null | undefined,
|
||||
iterationType?: IterationType,
|
||||
includeNull?: undefined
|
||||
): ReturnType<C>[];
|
||||
|
||||
subTreeTraverse<C extends BTNCallback<N | null>>(
|
||||
subTreeTraverse<C extends BTNCallback<N | null | undefined>>(
|
||||
callback?: C,
|
||||
beginRoot?: BTNKey | N | null,
|
||||
beginRoot?: BTNKey | N | null | undefined,
|
||||
iterationType?: IterationType,
|
||||
includeNull?: true
|
||||
): ReturnType<C>[];
|
||||
|
@ -872,7 +872,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<BTNCallback<N>>`.
|
||||
*/
|
||||
subTreeTraverse<C extends BTNCallback<N | null>>(
|
||||
subTreeTraverse<C extends BTNCallback<N | null | undefined>>(
|
||||
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<C>[] {
|
||||
if (typeof beginRoot === 'number') beginRoot = this.getNode(beginRoot);
|
||||
|
||||
const ans: (ReturnType<BTNCallback<N>> | null)[] = [];
|
||||
const ans: (ReturnType<BTNCallback<N>> | 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
dfs<C extends BTNCallback<N>>(
|
||||
callback?: C,
|
||||
pattern?: DFSOrderPattern,
|
||||
beginRoot?: N | null,
|
||||
beginRoot?: N | null | undefined,
|
||||
iterationType?: IterationType,
|
||||
includeNull?: false
|
||||
): ReturnType<C>[];
|
||||
|
@ -937,15 +937,15 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
dfs<C extends BTNCallback<N>>(
|
||||
callback?: C,
|
||||
pattern?: DFSOrderPattern,
|
||||
beginRoot?: N | null,
|
||||
beginRoot?: N | null | undefined,
|
||||
iterationType?: IterationType,
|
||||
includeNull?: undefined
|
||||
): ReturnType<C>[];
|
||||
|
||||
dfs<C extends BTNCallback<N | null>>(
|
||||
dfs<C extends BTNCallback<N | null | undefined>>(
|
||||
callback?: C,
|
||||
pattern?: DFSOrderPattern,
|
||||
beginRoot?: N | null,
|
||||
beginRoot?: N | null | undefined,
|
||||
iterationType?: IterationType,
|
||||
includeNull?: true
|
||||
): ReturnType<C>[];
|
||||
|
@ -958,7 +958,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<BTNCallback<N>>` values.
|
||||
*/
|
||||
dfs<C extends BTNCallback<N | null>>(
|
||||
dfs<C extends BTNCallback<N | null | undefined>>(
|
||||
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<C>[] {
|
||||
if (!beginRoot) return [];
|
||||
const ans: ReturnType<C>[] = [];
|
||||
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<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
|
||||
bfs<C extends BTNCallback<N>>(
|
||||
callback?: C,
|
||||
beginRoot?: N | null,
|
||||
beginRoot?: N | null | undefined,
|
||||
iterationType?: IterationType,
|
||||
includeNull?: false
|
||||
): ReturnType<C>[];
|
||||
|
||||
bfs<C extends BTNCallback<N>>(
|
||||
callback?: C,
|
||||
beginRoot?: N | null,
|
||||
beginRoot?: N | null | undefined,
|
||||
iterationType?: IterationType,
|
||||
includeNull?: undefined
|
||||
): ReturnType<C>[];
|
||||
|
||||
bfs<C extends BTNCallback<N | null>>(
|
||||
bfs<C extends BTNCallback<N | null | undefined>>(
|
||||
callback?: C,
|
||||
beginRoot?: N | null,
|
||||
beginRoot?: N | null | undefined,
|
||||
iterationType?: IterationType,
|
||||
includeNull?: true
|
||||
): ReturnType<C>[];
|
||||
|
@ -1087,7 +1087,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = 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<BTNCallback<N>>`. 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<V = any, N extends BinaryTreeNode<V, N> = 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<BTNCallback<N>>[]`.
|
||||
*/
|
||||
bfs<C extends BTNCallback<N | null>>(
|
||||
bfs<C extends BTNCallback<N | null | undefined>>(
|
||||
callback: C = this.defaultOneParamCallback as C,
|
||||
beginRoot: N | null = this.root,
|
||||
beginRoot: N | null | undefined = this.root,
|
||||
iterationType = this.iterationType,
|
||||
includeNull = false
|
||||
): ReturnType<C>[] {
|
||||
|
@ -1106,7 +1106,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
const ans: ReturnType<BTNCallback<N>>[] = [];
|
||||
|
||||
if (iterationType === IterationType.RECURSIVE) {
|
||||
const queue: Queue<N | null> = new Queue<N | null>([beginRoot]);
|
||||
const queue: Queue<N | null | undefined> = new Queue<N | null | undefined>([beginRoot]);
|
||||
|
||||
const traverse = (level: number) => {
|
||||
if (queue.size === 0) return;
|
||||
|
@ -1127,7 +1127,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
|
||||
traverse(0);
|
||||
} else {
|
||||
const queue = new Queue<N | null>([beginRoot]);
|
||||
const queue = new Queue<N | null | undefined>([beginRoot]);
|
||||
while (queue.size > 0) {
|
||||
const levelSize = queue.size;
|
||||
|
||||
|
@ -1150,21 +1150,21 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
|
||||
listLevels<C extends BTNCallback<N>>(
|
||||
callback?: C,
|
||||
beginRoot?: N | null,
|
||||
beginRoot?: N | null | undefined,
|
||||
iterationType?: IterationType,
|
||||
includeNull?: false
|
||||
): ReturnType<C>[][];
|
||||
|
||||
listLevels<C extends BTNCallback<N>>(
|
||||
callback?: C,
|
||||
beginRoot?: N | null,
|
||||
beginRoot?: N | null | undefined,
|
||||
iterationType?: IterationType,
|
||||
includeNull?: undefined
|
||||
): ReturnType<C>[][];
|
||||
|
||||
listLevels<C extends BTNCallback<N | null>>(
|
||||
listLevels<C extends BTNCallback<N | null | undefined>>(
|
||||
callback?: C,
|
||||
beginRoot?: N | null,
|
||||
beginRoot?: N | null | undefined,
|
||||
iterationType?: IterationType,
|
||||
includeNull?: true
|
||||
): ReturnType<C>[][];
|
||||
|
@ -1175,7 +1175,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<C extends BTNCallback<N | null>>(
|
||||
listLevels<C extends BTNCallback<N | null | undefined>>(
|
||||
callback: C = this.defaultOneParamCallback as C,
|
||||
beginRoot: N | null = this.root,
|
||||
beginRoot: N | null | undefined = this.root,
|
||||
iterationType = this.iterationType,
|
||||
includeNull = false
|
||||
): ReturnType<C>[][] {
|
||||
|
@ -1195,7 +1195,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
const levelsNodes: ReturnType<C>[][] = [];
|
||||
|
||||
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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<BTNCallback<N>>` values.
|
||||
|
@ -1287,7 +1287,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
morris<C extends BTNCallback<N>>(
|
||||
callback: C = this.defaultOneParamCallback as C,
|
||||
pattern: DFSOrderPattern = 'in',
|
||||
beginRoot: N | null = this.root
|
||||
beginRoot: N | null | undefined = this.root
|
||||
): ReturnType<C>[] {
|
||||
if (beginRoot === null) return [];
|
||||
const ans: ReturnType<BTNCallback<N>>[] = [];
|
||||
|
@ -1304,7 +1304,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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<V = any, N extends BinaryTreeNode<V, N> = 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;
|
||||
}
|
||||
|
|
|
@ -12,8 +12,53 @@ import {IBinaryTree} from '../../interfaces';
|
|||
import {Queue} from '../queue';
|
||||
|
||||
export class BSTNode<V = any, N extends BSTNode<V, N> = BSTNodeNested<V>> extends BinaryTreeNode<V, N> {
|
||||
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<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
|
|||
*/
|
||||
constructor(options?: BSTOptions) {
|
||||
super(options);
|
||||
this._root = undefined;
|
||||
if (options !== undefined) {
|
||||
const {comparator} = options;
|
||||
if (comparator !== undefined) {
|
||||
|
@ -36,6 +82,14 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
|
|||
}
|
||||
}
|
||||
}
|
||||
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<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
|
|||
/**
|
||||
* 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<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
|
|||
* @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<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
|
|||
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<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
|
|||
}
|
||||
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<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
|
|||
* 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<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
|
|||
* 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<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
|
|||
* 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<C extends BTNCallback<N>>(
|
||||
identifier: ReturnType<C> | null,
|
||||
identifier: ReturnType<C> | 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<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
|
|||
* @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<BTNCallback<N>>`.
|
||||
|
@ -335,10 +393,10 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
|
|||
lesserOrGreaterTraverse<C extends BTNCallback<N>>(
|
||||
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<C>[] {
|
||||
if (typeof targetNode === 'number') targetNode = this.getNode(targetNode);
|
||||
if (typeof targetNode === 'number') targetNode = this.getNode(targetNode) ?? undefined;
|
||||
const ans: ReturnType<BTNCallback<N>>[] = [];
|
||||
if (!targetNode) return ans;
|
||||
const targetKey = targetNode.key;
|
||||
|
@ -417,6 +475,7 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
|
|||
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<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
|
|||
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<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
|
|||
_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<N, number> = new Map();
|
||||
|
||||
while (stack.length > 0 || node) {
|
||||
|
@ -467,7 +526,7 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -71,23 +71,24 @@ export class TreeMultiset<V = any, N extends TreeMultisetNode<V, N> = 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<V = any, N extends TreeMultisetNode<V, N> = 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<V = any, N extends TreeMultisetNode<V, N> = 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<V = any, N extends TreeMultisetNode<V, N> = 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<V = any, N extends TreeMultisetNode<V, N> = 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<V = any, N extends TreeMultisetNode<V, N> = TreeMultis
|
|||
continue;
|
||||
}
|
||||
|
||||
if (keyOrNode === null) {
|
||||
if (keyOrNode === undefined) {
|
||||
inserted.push(this.add(NaN, undefined, 0));
|
||||
continue;
|
||||
}
|
||||
|
@ -283,11 +284,11 @@ export class TreeMultiset<V = any, N extends TreeMultisetNode<V, N> = TreeMultis
|
|||
const bstDeletedResult: BinaryTreeDeletedResult<N>[] = [];
|
||||
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<V = any, N extends TreeMultisetNode<V, N> = 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);
|
||||
|
|
|
@ -24,7 +24,7 @@ export enum FamilyPosition {
|
|||
|
||||
export type BTNKey = number;
|
||||
|
||||
export type BinaryTreeDeletedResult<N> = { deleted: N | null | undefined; needBalanced: N | null };
|
||||
export type BinaryTreeDeletedResult<N> = { deleted: N | null | undefined; needBalanced: N | null | undefined };
|
||||
|
||||
export type BinaryTreeNodeNested<T> = BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -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<number>();
|
||||
|
||||
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', () => {
|
||||
|
|
|
@ -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]);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue