[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:
Revone 2023-11-07 12:26:16 +08:00
parent 8a518f95b7
commit 996fd128ed
11 changed files with 281 additions and 220 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.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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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', () => {

View file

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