mirror of
https://github.com/zrwusa/data-structure-typed.git
synced 2024-11-23 12:54:04 +00:00
[binary-tree] All traversal methods offer an includeNull parameter to support the output of null nodes.
This commit is contained in:
parent
3596ca53a7
commit
d6b394446a
|
@ -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.41.8](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming)
|
||||
## [v1.41.9](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming)
|
||||
|
||||
### Changes
|
||||
|
||||
|
|
24
README.md
24
README.md
|
@ -658,40 +658,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><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.29</td><td>33.01</td><td>3.64e-4</td></tr><tr><td>10,000 add & delete randomly</td><td>68.10</td><td>14.68</td><td>0.00</td></tr><tr><td>10,000 addMany</td><td>39.54</td><td>25.29</td><td>4.07e-4</td></tr><tr><td>10,000 get</td><td>26.72</td><td>37.42</td><td>3.77e-4</td></tr></table></div>
|
||||
<div class="content"><table><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.18</td><td>33.13</td><td>2.75e-4</td></tr><tr><td>10,000 add & delete randomly</td><td>65.65</td><td>15.23</td><td>0.00</td></tr><tr><td>10,000 addMany</td><td>39.56</td><td>25.28</td><td>3.25e-4</td></tr><tr><td>10,000 get</td><td>26.57</td><td>37.63</td><td>1.92e-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><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.88</td><td>77.63</td><td>1.02e-4</td></tr><tr><td>1,000 add & delete randomly</td><td>15.90</td><td>62.88</td><td>1.08e-4</td></tr><tr><td>1,000 addMany</td><td>10.59</td><td>94.41</td><td>8.39e-5</td></tr><tr><td>1,000 get</td><td>18.01</td><td>55.53</td><td>1.95e-4</td></tr><tr><td>1,000 dfs</td><td>69.11</td><td>14.47</td><td>6.47e-4</td></tr><tr><td>1,000 bfs</td><td>54.42</td><td>18.38</td><td>4.20e-4</td></tr><tr><td>1,000 morris</td><td>37.14</td><td>26.92</td><td>2.27e-4</td></tr></table></div>
|
||||
<div class="content"><table><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.00</td><td>76.93</td><td>3.84e-4</td></tr><tr><td>1,000 add & delete randomly</td><td>16.11</td><td>62.06</td><td>3.76e-4</td></tr><tr><td>1,000 addMany</td><td>10.63</td><td>94.04</td><td>1.30e-4</td></tr><tr><td>1,000 get</td><td>18.24</td><td>54.84</td><td>5.04e-4</td></tr><tr><td>1,000 dfs</td><td>69.77</td><td>14.33</td><td>4.07e-4</td></tr><tr><td>1,000 bfs</td><td>54.49</td><td>18.35</td><td>4.96e-4</td></tr><tr><td>1,000 morris</td><td>37.10</td><td>26.96</td><td>2.35e-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><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>28.48</td><td>35.11</td><td>2.29e-4</td></tr><tr><td>10,000 add & delete randomly</td><td>64.82</td><td>15.43</td><td>0.01</td></tr><tr><td>10,000 addMany</td><td>28.74</td><td>34.80</td><td>9.06e-4</td></tr><tr><td>10,000 get</td><td>27.38</td><td>36.52</td><td>1.82e-4</td></tr></table></div>
|
||||
<div class="content"><table><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.88</td><td>31.37</td><td>3.10e-4</td></tr><tr><td>10,000 add & delete randomly</td><td>73.08</td><td>13.68</td><td>0.01</td></tr><tr><td>10,000 addMany</td><td>28.80</td><td>34.73</td><td>0.00</td></tr><tr><td>10,000 get</td><td>27.59</td><td>36.25</td><td>2.19e-4</td></tr></table></div>
|
||||
</div><div class="json-to-html-collapse clearfix 0">
|
||||
<div class='collapsible level0' ><span class='json-to-html-label'>rb-tree</span></div>
|
||||
<div class="content"><table><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>72.30</td><td>13.83</td><td>0.00</td></tr><tr><td>100,000 add & 1000 delete randomly</td><td>81.37</td><td>12.29</td><td>0.01</td></tr><tr><td>100,000 getNode</td><td>59.48</td><td>16.81</td><td>9.29e-4</td></tr></table></div>
|
||||
<div class="content"><table><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>70.97</td><td>14.09</td><td>0.00</td></tr><tr><td>100,000 add & 1000 delete randomly</td><td>82.03</td><td>12.19</td><td>0.01</td></tr><tr><td>100,000 getNode</td><td>59.75</td><td>16.74</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><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>9786.77</td><td>5.56e-7</td></tr><tr><td>1,000 addEdge</td><td>6.02</td><td>166.04</td><td>1.27e-4</td></tr><tr><td>1,000 getVertex</td><td>0.05</td><td>2.18e+4</td><td>3.02e-7</td></tr><tr><td>1,000 getEdge</td><td>23.41</td><td>42.71</td><td>0.00</td></tr><tr><td>tarjan</td><td>223.51</td><td>4.47</td><td>0.01</td></tr><tr><td>tarjan all</td><td>224.89</td><td>4.45</td><td>0.00</td></tr><tr><td>topologicalSort</td><td>181.90</td><td>5.50</td><td>0.00</td></tr></table></div>
|
||||
<div class="content"><table><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>9894.62</td><td>1.57e-6</td></tr><tr><td>1,000 addEdge</td><td>6.17</td><td>162.15</td><td>0.00</td></tr><tr><td>1,000 getVertex</td><td>0.05</td><td>2.17e+4</td><td>4.06e-7</td></tr><tr><td>1,000 getEdge</td><td>23.50</td><td>42.56</td><td>0.00</td></tr><tr><td>tarjan</td><td>223.18</td><td>4.48</td><td>0.01</td></tr><tr><td>tarjan all</td><td>226.10</td><td>4.42</td><td>0.01</td></tr><tr><td>topologicalSort</td><td>186.20</td><td>5.37</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><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 add & pop</td><td>4.62</td><td>216.33</td><td>3.06e-5</td></tr><tr><td>10,000 fib add & pop</td><td>351.41</td><td>2.85</td><td>0.00</td></tr></table></div>
|
||||
<div class="content"><table><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.30</td><td>4.51e-5</td></tr><tr><td>10,000 fib add & pop</td><td>351.83</td><td>2.84</td><td>0.00</td></tr></table></div>
|
||||
</div><div class="json-to-html-collapse clearfix 0">
|
||||
<div class='collapsible level0' ><span class='json-to-html-label'>doubly-linked-list</span></div>
|
||||
<div class="content"><table><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>214.84</td><td>4.65</td><td>0.04</td></tr><tr><td>1,000,000 unshift & shift</td><td>167.11</td><td>5.98</td><td>0.04</td></tr><tr><td>1,000,000 insertBefore</td><td>335.78</td><td>2.98</td><td>0.07</td></tr></table></div>
|
||||
<div class="content"><table><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>216.19</td><td>4.63</td><td>0.04</td></tr><tr><td>1,000,000 unshift & shift</td><td>164.84</td><td>6.07</td><td>0.02</td></tr><tr><td>1,000,000 insertBefore</td><td>325.14</td><td>3.08</td><td>0.07</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><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>212.53</td><td>4.71</td><td>0.01</td></tr><tr><td>10,000 insertBefore</td><td>243.94</td><td>4.10</td><td>0.00</td></tr></table></div>
|
||||
<div class="content"><table><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.24</td><td>4.69</td><td>0.01</td></tr><tr><td>10,000 insertBefore</td><td>247.69</td><td>4.04</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><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.43</td><td>87.50</td><td>1.84e-4</td></tr></table></div>
|
||||
<div class="content"><table><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.50</td><td>86.97</td><td>1.99e-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><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>216.07</td><td>4.63</td><td>0.05</td></tr><tr><td>1,000,000 shift</td><td>24.97</td><td>40.05</td><td>0.00</td></tr></table></div>
|
||||
<div class="content"><table><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>223.30</td><td>4.48</td><td>0.08</td></tr><tr><td>1,000,000 shift</td><td>24.86</td><td>40.23</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><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>42.57</td><td>23.49</td><td>0.01</td></tr><tr><td>1,000,000 push & shift</td><td>79.94</td><td>12.51</td><td>9.99e-4</td></tr></table></div>
|
||||
<div class="content"><table><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>42.26</td><td>23.66</td><td>0.01</td></tr><tr><td>1,000,000 push & shift</td><td>79.22</td><td>12.62</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><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>54.02</td><td>18.51</td><td>0.00</td></tr><tr><td>100,000 getWords</td><td>82.83</td><td>12.07</td><td>0.00</td></tr></table></div>
|
||||
<div class="content"><table><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>52.92</td><td>18.90</td><td>0.00</td></tr><tr><td>100,000 getWords</td><td>83.37</td><td>11.99</td><td>0.00</td></tr></table></div>
|
||||
</div>
|
||||
|
||||
[//]: # (End of Replace Section)
|
|
@ -108,8 +108,7 @@ export class BinaryTreeNode<V = any, N extends BinaryTreeNode<V, N> = BinaryTree
|
|||
* @template N - The type of the binary tree's nodes.
|
||||
*/
|
||||
export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode<V, BinaryTreeNodeNested<V>>>
|
||||
implements IBinaryTree<V, N>
|
||||
{
|
||||
implements IBinaryTree<V, N> {
|
||||
iterationType: IterationType = IterationType.ITERATIVE;
|
||||
|
||||
/**
|
||||
|
@ -391,7 +390,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
return -1;
|
||||
}
|
||||
|
||||
const stack: {node: N; depth: number}[] = [{node: beginRoot, depth: 0}];
|
||||
const stack: { node: N; depth: number }[] = [{node: beginRoot, depth: 0}];
|
||||
let maxHeight = 0;
|
||||
|
||||
while (stack.length > 0) {
|
||||
|
@ -846,6 +845,27 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
return this.isSubtreeBST(this.root, iterationType);
|
||||
}
|
||||
|
||||
subTreeTraverse<C extends BTNCallback<N>>(
|
||||
callback?: C,
|
||||
beginRoot?: BTNKey | N | null,
|
||||
iterationType?: IterationType,
|
||||
includeNull?: false
|
||||
): ReturnType<C>[]
|
||||
|
||||
subTreeTraverse<C extends BTNCallback<N>>(
|
||||
callback?: C,
|
||||
beginRoot?: BTNKey | N | null,
|
||||
iterationType?: IterationType,
|
||||
includeNull?: undefined
|
||||
): ReturnType<C>[]
|
||||
|
||||
subTreeTraverse<C extends BTNCallback<N | null>>(
|
||||
callback?: C,
|
||||
beginRoot?: BTNKey | N | null,
|
||||
iterationType?: IterationType,
|
||||
includeNull?: true
|
||||
): ReturnType<C>[]
|
||||
|
||||
/**
|
||||
* The function `subTreeTraverse` traverses a binary tree and applies a callback function to each
|
||||
* node, either recursively or iteratively.
|
||||
|
@ -858,40 +878,79 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
* start from the root of the tree.
|
||||
* @param iterationType - The `iterationType` parameter determines the type of traversal to be
|
||||
* performed on the binary tree. It can have two possible values:
|
||||
* @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>>(
|
||||
subTreeTraverse<C extends BTNCallback<N | null>>(
|
||||
callback: C = this.defaultOneParamCallback as C,
|
||||
beginRoot: BTNKey | N | null = this.root,
|
||||
iterationType = this.iterationType
|
||||
iterationType = this.iterationType,
|
||||
includeNull = false
|
||||
): ReturnType<C>[] {
|
||||
if (typeof beginRoot === 'number') beginRoot = this.getNode(beginRoot);
|
||||
|
||||
const ans: ReturnType<BTNCallback<N>>[] = [];
|
||||
const ans: (ReturnType<BTNCallback<N>> | null)[] = [];
|
||||
if (!beginRoot) return ans;
|
||||
|
||||
if (iterationType === IterationType.RECURSIVE) {
|
||||
const _traverse = (cur: N) => {
|
||||
ans.push(callback(cur));
|
||||
cur.left && _traverse(cur.left);
|
||||
cur.right && _traverse(cur.right);
|
||||
const _traverse = (cur: N | null) => {
|
||||
if (cur !== undefined) {
|
||||
ans.push(callback(cur));
|
||||
if (includeNull) {
|
||||
cur !== null && cur.left !== undefined && _traverse(cur.left);
|
||||
cur !== null && cur.right !== undefined && _traverse(cur.right);
|
||||
} else {
|
||||
cur !== null && cur.left && _traverse(cur.left);
|
||||
cur !== null && cur.right && _traverse(cur.right);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_traverse(beginRoot);
|
||||
} else {
|
||||
const stack: N[] = [beginRoot];
|
||||
const stack: (N| null)[] = [beginRoot];
|
||||
|
||||
while (stack.length > 0) {
|
||||
const cur = stack.pop()!;
|
||||
|
||||
ans.push(callback(cur));
|
||||
cur.right && stack.push(cur.right);
|
||||
cur.left && stack.push(cur.left);
|
||||
const cur = stack.pop();
|
||||
if (cur !== undefined) {
|
||||
ans.push(callback(cur));
|
||||
if (includeNull) {
|
||||
cur !== null && cur.right !== undefined && stack.push(cur.right);
|
||||
cur !== null && cur.left !== undefined && stack.push(cur.left);
|
||||
} else {
|
||||
cur !== null && cur.right && stack.push(cur.right);
|
||||
cur !== null && cur.left && stack.push(cur.left);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
dfs<C extends BTNCallback<N>>(
|
||||
callback?: C,
|
||||
pattern?: DFSOrderPattern,
|
||||
beginRoot?: N | null,
|
||||
iterationType?: IterationType,
|
||||
includeNull?: false
|
||||
): ReturnType<C>[]
|
||||
|
||||
dfs<C extends BTNCallback<N>>(
|
||||
callback?: C,
|
||||
pattern?: DFSOrderPattern,
|
||||
beginRoot?: N | null,
|
||||
iterationType?: IterationType,
|
||||
includeNull?: undefined
|
||||
): ReturnType<C>[]
|
||||
|
||||
dfs<C extends BTNCallback<N | null>>(
|
||||
callback?: C,
|
||||
pattern?: DFSOrderPattern,
|
||||
beginRoot?: N | null,
|
||||
iterationType?: IterationType,
|
||||
includeNull?: true
|
||||
): ReturnType<C>[]
|
||||
|
||||
/**
|
||||
* The `dfs` function performs a depth-first search traversal on a binary tree, executing a callback
|
||||
* function on each node according to a specified order pattern.
|
||||
|
@ -905,34 +964,53 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
* is `null`, an empty array will be returned.
|
||||
* @param {IterationType} iterationType - The `iterationType` parameter determines the type of
|
||||
* iteration used in the depth-first search algorithm. It can have two possible values:
|
||||
* @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>>(
|
||||
dfs<C extends BTNCallback<N | null>>(
|
||||
callback: C = this.defaultOneParamCallback as C,
|
||||
pattern: DFSOrderPattern = 'in',
|
||||
beginRoot: N | null = this.root,
|
||||
iterationType: IterationType = IterationType.ITERATIVE
|
||||
iterationType: IterationType = IterationType.ITERATIVE,
|
||||
includeNull = false
|
||||
): ReturnType<C>[] {
|
||||
if (!beginRoot) return [];
|
||||
const ans: ReturnType<BTNCallback<N>>[] = [];
|
||||
const ans: ReturnType<C>[] = [];
|
||||
if (iterationType === IterationType.RECURSIVE) {
|
||||
const _traverse = (node: N) => {
|
||||
const _traverse = (node: N | null) => {
|
||||
switch (pattern) {
|
||||
case 'in':
|
||||
if (node.left) _traverse(node.left);
|
||||
ans.push(callback(node));
|
||||
if (node.right) _traverse(node.right);
|
||||
if (includeNull) {
|
||||
if (node !== null && node.left !== undefined) _traverse(node.left);
|
||||
ans.push(callback(node));
|
||||
if (node !== null && node.right !== undefined) _traverse(node.right);
|
||||
} else {
|
||||
if (node !== null && node.left) _traverse(node.left);
|
||||
ans.push(callback(node));
|
||||
if (node !== null && node.right) _traverse(node.right);
|
||||
}
|
||||
break;
|
||||
case 'pre':
|
||||
ans.push(callback(node));
|
||||
|
||||
if (node.left) _traverse(node.left);
|
||||
if (node.right) _traverse(node.right);
|
||||
if (includeNull) {
|
||||
ans.push(callback(node));
|
||||
if (node !== null && node.left !== undefined) _traverse(node.left);
|
||||
if (node !== null && 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);
|
||||
}
|
||||
break;
|
||||
case 'post':
|
||||
if (node.left) _traverse(node.left);
|
||||
if (node.right) _traverse(node.right);
|
||||
ans.push(callback(node));
|
||||
if (includeNull) {
|
||||
if (node !== null && node.left !== undefined) _traverse(node.left);
|
||||
if (node !== null && 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);
|
||||
ans.push(callback(node));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -941,34 +1019,39 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
_traverse(beginRoot);
|
||||
} else {
|
||||
// 0: visit, 1: print
|
||||
const stack: {opt: 0 | 1; node: N | null | undefined}[] = [{opt: 0, node: beginRoot}];
|
||||
const stack: { opt: 0 | 1; node: N | null | undefined }[] = [{opt: 0, node: beginRoot}];
|
||||
|
||||
while (stack.length > 0) {
|
||||
const cur = stack.pop();
|
||||
if (!cur || !cur.node) continue;
|
||||
if (cur === undefined) continue;
|
||||
if (includeNull) {
|
||||
if (cur.node === undefined) continue;
|
||||
} else {
|
||||
if (cur.node === null || cur.node === undefined) continue;
|
||||
}
|
||||
if (cur.opt === 1) {
|
||||
ans.push(callback(cur.node));
|
||||
} else {
|
||||
switch (pattern) {
|
||||
case 'in':
|
||||
stack.push({opt: 0, node: cur.node.right});
|
||||
cur.node && stack.push({opt: 0, node: cur.node.right});
|
||||
stack.push({opt: 1, node: cur.node});
|
||||
stack.push({opt: 0, node: cur.node.left});
|
||||
cur.node && stack.push({opt: 0, node: cur.node.left});
|
||||
break;
|
||||
case 'pre':
|
||||
stack.push({opt: 0, node: cur.node.right});
|
||||
stack.push({opt: 0, node: cur.node.left});
|
||||
cur.node && stack.push({opt: 0, node: cur.node.right});
|
||||
cur.node && stack.push({opt: 0, node: cur.node.left});
|
||||
stack.push({opt: 1, node: cur.node});
|
||||
break;
|
||||
case 'post':
|
||||
stack.push({opt: 1, node: cur.node});
|
||||
stack.push({opt: 0, node: cur.node.right});
|
||||
stack.push({opt: 0, node: cur.node.left});
|
||||
cur.node && stack.push({opt: 0, node: cur.node.right});
|
||||
cur.node && stack.push({opt: 0, node: cur.node.left});
|
||||
break;
|
||||
default:
|
||||
stack.push({opt: 0, node: cur.node.right});
|
||||
cur.node && stack.push({opt: 0, node: cur.node.right});
|
||||
stack.push({opt: 1, node: cur.node});
|
||||
stack.push({opt: 0, node: cur.node.left});
|
||||
cur.node && stack.push({opt: 0, node: cur.node.left});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -978,6 +1061,27 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
return ans;
|
||||
}
|
||||
|
||||
bfs<C extends BTNCallback<N>>(
|
||||
callback?: C,
|
||||
beginRoot?: N | null,
|
||||
iterationType?: IterationType,
|
||||
includeNull?: false
|
||||
): ReturnType<C>[]
|
||||
|
||||
bfs<C extends BTNCallback<N>>(
|
||||
callback?: C,
|
||||
beginRoot?: N | null,
|
||||
iterationType?: IterationType,
|
||||
includeNull?: undefined
|
||||
): ReturnType<C>[]
|
||||
|
||||
bfs<C extends BTNCallback<N | null>>(
|
||||
callback?: C,
|
||||
beginRoot?: N | null,
|
||||
iterationType?: IterationType,
|
||||
includeNull?: true
|
||||
): ReturnType<C>[]
|
||||
|
||||
/**
|
||||
* The bfs function performs a breadth-first search traversal on a binary tree, executing a callback
|
||||
* function on each node.
|
||||
|
@ -989,19 +1093,21 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
* will not be performed and an empty array will be returned.
|
||||
* @param iterationType - The `iterationType` parameter determines the type of iteration to be used
|
||||
* in the breadth-first search (BFS) algorithm. It can have two possible values:
|
||||
* @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>>(
|
||||
bfs<C extends BTNCallback<N | null>>(
|
||||
callback: C = this.defaultOneParamCallback as C,
|
||||
beginRoot: N | null = this.root,
|
||||
iterationType = this.iterationType
|
||||
iterationType = this.iterationType,
|
||||
includeNull = false
|
||||
): ReturnType<C>[] {
|
||||
if (!beginRoot) return [];
|
||||
|
||||
const ans: ReturnType<BTNCallback<N>>[] = [];
|
||||
|
||||
if (iterationType === IterationType.RECURSIVE) {
|
||||
const queue = new Queue<N>([beginRoot]);
|
||||
const queue: Queue<N | null> = new Queue<N | null>([beginRoot]);
|
||||
|
||||
const traverse = (level: number) => {
|
||||
if (queue.size === 0) return;
|
||||
|
@ -1009,15 +1115,21 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
const current = queue.shift()!;
|
||||
ans.push(callback(current));
|
||||
|
||||
if (current.left) queue.push(current.left);
|
||||
if (current.right) queue.push(current.right);
|
||||
if (includeNull) {
|
||||
if (current && current.left !== undefined) queue.push(current.left);
|
||||
if (current && current.right !== undefined) queue.push(current.right);
|
||||
} else {
|
||||
if (current.left) queue.push(current.left);
|
||||
if (current.right) queue.push(current.right);
|
||||
}
|
||||
|
||||
|
||||
traverse(level + 1);
|
||||
};
|
||||
|
||||
traverse(0);
|
||||
} else {
|
||||
const queue = new Queue<N>([beginRoot]);
|
||||
const queue = new Queue<N | null>([beginRoot]);
|
||||
while (queue.size > 0) {
|
||||
const levelSize = queue.size;
|
||||
|
||||
|
@ -1025,14 +1137,41 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
const current = queue.shift()!;
|
||||
ans.push(callback(current));
|
||||
|
||||
if (current.left) queue.push(current.left);
|
||||
if (current.right) queue.push(current.right);
|
||||
if (includeNull) {
|
||||
if (current !== null && current.left !== undefined) queue.push(current.left);
|
||||
if (current !== null && current.right !== undefined) queue.push(current.right);
|
||||
} else {
|
||||
if (current.left) queue.push(current.left);
|
||||
if (current.right) queue.push(current.right);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
listLevels<C extends BTNCallback<N>>(
|
||||
callback?: C ,
|
||||
beginRoot?: N | null ,
|
||||
iterationType?: IterationType,
|
||||
includeNull?: false
|
||||
): ReturnType<C>[][]
|
||||
|
||||
listLevels<C extends BTNCallback<N>>(
|
||||
callback?: C ,
|
||||
beginRoot?: N | null ,
|
||||
iterationType?: IterationType,
|
||||
includeNull?: undefined
|
||||
): ReturnType<C>[][]
|
||||
|
||||
listLevels<C extends BTNCallback<N | null>>(
|
||||
callback?: C ,
|
||||
beginRoot?: N | null ,
|
||||
iterationType?: IterationType,
|
||||
includeNull?: true
|
||||
): ReturnType<C>[][]
|
||||
|
||||
/**
|
||||
* The `listLevels` function takes a binary tree node and a callback function, and returns an array
|
||||
* of arrays representing the levels of the tree.
|
||||
|
@ -1044,29 +1183,36 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
* from the root node of the binary tree.
|
||||
* @param iterationType - The `iterationType` parameter determines whether the tree traversal is done
|
||||
* recursively or iteratively. It can have two possible values:
|
||||
* @param includeNull - The choice to output null values during binary tree traversal should be provided.
|
||||
* @returns The function `listLevels` returns an array of arrays, where each inner array represents a
|
||||
* 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>>(
|
||||
listLevels<C extends BTNCallback<N | null>>(
|
||||
callback: C = this.defaultOneParamCallback as C,
|
||||
beginRoot: N | null = this.root,
|
||||
iterationType = this.iterationType
|
||||
iterationType = this.iterationType,
|
||||
includeNull = false
|
||||
): ReturnType<C>[][] {
|
||||
if (!beginRoot) return [];
|
||||
const levelsNodes: ReturnType<C>[][] = [];
|
||||
|
||||
if (iterationType === IterationType.RECURSIVE) {
|
||||
const _recursive = (node: N, level: number) => {
|
||||
const _recursive = (node: N | null, level: number) => {
|
||||
if (!levelsNodes[level]) levelsNodes[level] = [];
|
||||
levelsNodes[level].push(callback(node));
|
||||
if (node.left) _recursive(node.left, level + 1);
|
||||
if (node.right) _recursive(node.right, level + 1);
|
||||
if (includeNull) {
|
||||
if (node && node.left !== undefined) _recursive(node.left, level + 1);
|
||||
if (node && node.right !== undefined) _recursive(node.right, level + 1);
|
||||
} else {
|
||||
if (node && node.left) _recursive(node.left, level + 1);
|
||||
if (node && node.right) _recursive(node.right, level + 1);
|
||||
}
|
||||
};
|
||||
|
||||
_recursive(beginRoot, 0);
|
||||
} else {
|
||||
const stack: [N, number][] = [[beginRoot, 0]];
|
||||
const stack: [N | null, number][] = [[beginRoot, 0]];
|
||||
|
||||
while (stack.length > 0) {
|
||||
const head = stack.pop()!;
|
||||
|
@ -1074,8 +1220,14 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
|
||||
if (!levelsNodes[level]) levelsNodes[level] = [];
|
||||
levelsNodes[level].push(callback(node));
|
||||
if (node.right) stack.push([node.right, level + 1]);
|
||||
if (node.left) stack.push([node.left, level + 1]);
|
||||
|
||||
if (includeNull) {
|
||||
if (node && node.right !== undefined) stack.push([node.right, level + 1]);
|
||||
if (node && node.left !== undefined) stack.push([node.left, level + 1]);
|
||||
} else {
|
||||
if (node && node.right) stack.push([node.right, level + 1]);
|
||||
if (node && node.left) stack.push([node.left, level + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1231,7 +1383,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|||
* @returns The `*[Symbol.iterator]` method returns a generator object that yields the keys of the
|
||||
* binary tree nodes in a specific order.
|
||||
*/
|
||||
*[Symbol.iterator](node = this.root): Generator<BTNKey, void, undefined> {
|
||||
* [Symbol.iterator](node = this.root): Generator<BTNKey, void, undefined> {
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -174,8 +174,11 @@ describe('BinaryTree', () => {
|
|||
});
|
||||
|
||||
it('should subTreeTraverse', () => {
|
||||
tree.addMany([4, 2, 6, 1, 3, 5, 7]);
|
||||
expect(tree.subTreeTraverse(node => node.key, tree.getNode(6), IterationType.RECURSIVE)).toEqual([6, 5, 7]);
|
||||
tree.addMany([4, 2, 6, null, 1, 3, null, 5, null, 7]);
|
||||
expect(tree.subTreeTraverse(node => node.key, tree.getNode(6), IterationType.ITERATIVE)).toEqual([6,3, 7]);
|
||||
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)).toEqual([6, 3, 7, null]);
|
||||
expect(tree.subTreeTraverse(node => node === null? null : node.key, tree.getNode(6), IterationType.RECURSIVE, true)).toEqual([6, 3, 7, null]);
|
||||
});
|
||||
|
||||
it('should clear the tree', () => {
|
||||
|
@ -266,10 +269,18 @@ describe('BinaryTree traversals', () => {
|
|||
|
||||
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)).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)).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)).toEqual([35, 20, 40, 15, 29, 50, 16, 28, 30, 45, 55]);
|
||||
expect(tree.bfs(node => node , tree.root, IterationType.RECURSIVE).map(node => node === null ? null : node.key)).toEqual([35, 20, 40, 15, 29, 50, 16, 28, 30, 45, 55]);
|
||||
|
||||
expect(tree.dfs(node => node.key, 'pre')).toEqual([35, 20, 15, 16, 29, 28, 30, 40, 50, 45, 55]);
|
||||
expect(tree.dfs(node => node.key, 'pre', tree.root, IterationType.RECURSIVE)).toEqual([
|
||||
35, 20, 15, 16, 29, 28, 30, 40, 50, 45, 55
|
||||
]);
|
||||
expect(tree.dfs(node => node, 'pre', tree.root, IterationType.ITERATIVE, true).map(node => node === null ? null : node.key)).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)).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]);
|
||||
expect(tree.dfs(node => node.key, 'post')).toEqual([16, 15, 28, 30, 29, 20, 45, 55, 50, 40, 35]);
|
||||
expect(tree.dfs(node => node.key, 'post', tree.root, IterationType.RECURSIVE)).toEqual([
|
||||
|
@ -282,9 +293,7 @@ describe('BinaryTree traversals', () => {
|
|||
35, 20, 40, 15, 29, 50, 16, 28, 30, 45, 55
|
||||
]);
|
||||
|
||||
const levels = tree.listLevels(node => node.key);
|
||||
expect(levels).toEqual([[35], [20, 40], [15, 29, 50], [16, 28, 30, 45, 55]]);
|
||||
isDebug && console.log(levels);
|
||||
expect(tree.listLevels(node => node.key)).toEqual([[35], [20, 40], [15, 29, 50], [16, 28, 30, 45, 55]]);
|
||||
|
||||
expect(tree.listLevels(node => node.key, tree.root, IterationType.RECURSIVE)).toEqual([
|
||||
[35],
|
||||
|
@ -292,9 +301,21 @@ describe('BinaryTree traversals', () => {
|
|||
[15, 29, 50],
|
||||
[16, 28, 30, 45, 55]
|
||||
]);
|
||||
isDebug && console.log(levels);
|
||||
expect(tree.listLevels(node => node === null ? null :node.key, 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([
|
||||
[35],
|
||||
[20, 40],
|
||||
[15, 29, null,50],
|
||||
[null, 16, 28, 30, 45, 55]
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
describe('BinaryTree', () => {
|
||||
let tree: BinaryTree<string>;
|
||||
|
||||
|
|
Loading…
Reference in a new issue