feat: The binary trees support storing values in a Map and provides parameters for Map mode. #111. Rename type definitions and parameter names to align with best practices.

This commit is contained in:
Revone 2024-11-01 19:40:19 +13:00
parent 8ae577315a
commit 28ff30ea4b
23 changed files with 1650 additions and 787 deletions

View file

@ -826,43 +826,43 @@ Version 11.7.9
[//]: # (No deletion!!! Start of Replace Section)
<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>100,000 add</td><td>6.66</td><td>150.18</td><td>2.19e-4</td></tr><tr><td>100,000 add & poll</td><td>35.35</td><td>28.29</td><td>8.55e-4</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>100,000 add</td><td>6.63</td><td>150.92</td><td>3.07e-4</td></tr><tr><td>100,000 add & poll</td><td>35.09</td><td>28.50</td><td>8.68e-4</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>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</td><td>83.70</td><td>11.95</td><td>4.47e-4</td></tr><tr><td>100,000 add randomly</td><td>85.05</td><td>11.76</td><td>0.00</td></tr><tr><td>100,000 get</td><td>112.86</td><td>8.86</td><td>0.00</td></tr><tr><td>100,000 iterator</td><td>23.62</td><td>42.34</td><td>0.00</td></tr><tr><td>100,000 add & delete orderly</td><td>153.38</td><td>6.52</td><td>0.01</td></tr><tr><td>100,000 add & delete randomly</td><td>232.75</td><td>4.30</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>100,000 add</td><td>89.65</td><td>11.15</td><td>0.00</td></tr><tr><td>100,000 add randomly</td><td>92.74</td><td>10.78</td><td>0.01</td></tr><tr><td>100,000 get</td><td>1.09</td><td>921.21</td><td>7.98e-5</td></tr><tr><td>100,000 iterator</td><td>25.76</td><td>38.82</td><td>0.00</td></tr><tr><td>100,000 add & delete orderly</td><td>159.43</td><td>6.27</td><td>0.02</td></tr><tr><td>100,000 add & delete randomly</td><td>239.83</td><td>4.17</td><td>0.00</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>queue</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 push</td><td>46.18</td><td>21.65</td><td>0.01</td></tr><tr><td>100,000 push & shift</td><td>5.40</td><td>185.33</td><td>0.00</td></tr><tr><td>Native JS Array 100,000 push & shift</td><td>2273.18</td><td>0.44</td><td>0.20</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 push</td><td>45.01</td><td>22.22</td><td>0.01</td></tr><tr><td>100,000 push & shift</td><td>6.24</td><td>160.17</td><td>0.01</td></tr><tr><td>Native JS Array 100,000 push & shift</td><td>2227.55</td><td>0.45</td><td>0.22</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>20.33</td><td>49.20</td><td>0.00</td></tr><tr><td>1,000,000 push & pop</td><td>26.35</td><td>37.95</td><td>0.00</td></tr><tr><td>1,000,000 push & shift</td><td>28.83</td><td>34.68</td><td>0.00</td></tr><tr><td>100,000 push & shift</td><td>2.55</td><td>392.71</td><td>3.48e-4</td></tr><tr><td>Native JS Array 100,000 push & shift</td><td>2285.23</td><td>0.44</td><td>0.25</td></tr><tr><td>100,000 unshift & shift</td><td>2.53</td><td>395.88</td><td>4.03e-4</td></tr><tr><td>Native JS Array 100,000 unshift & shift</td><td>4063.57</td><td>0.25</td><td>0.22</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>20.21</td><td>49.47</td><td>0.00</td></tr><tr><td>1,000,000 push & pop</td><td>26.85</td><td>37.24</td><td>0.01</td></tr><tr><td>1,000,000 push & shift</td><td>27.57</td><td>36.27</td><td>0.00</td></tr><tr><td>100,000 push & shift</td><td>2.61</td><td>382.64</td><td>4.60e-4</td></tr><tr><td>Native JS Array 100,000 push & shift</td><td>2152.90</td><td>0.46</td><td>0.22</td></tr><tr><td>100,000 unshift & shift</td><td>2.51</td><td>398.74</td><td>3.60e-4</td></tr><tr><td>Native JS Array 100,000 unshift & shift</td><td>4376.45</td><td>0.23</td><td>0.30</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>hash-map</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 set</td><td>210.30</td><td>4.76</td><td>0.03</td></tr><tr><td>Native JS Map 1,000,000 set</td><td>217.28</td><td>4.60</td><td>0.03</td></tr><tr><td>Native JS Set 1,000,000 add</td><td>175.11</td><td>5.71</td><td>0.02</td></tr><tr><td>1,000,000 set & get</td><td>231.89</td><td>4.31</td><td>0.05</td></tr><tr><td>Native JS Map 1,000,000 set & get</td><td>278.86</td><td>3.59</td><td>0.03</td></tr><tr><td>Native JS Set 1,000,000 add & has</td><td>237.24</td><td>4.22</td><td>0.01</td></tr><tr><td>1,000,000 ObjKey set & get</td><td>387.96</td><td>2.58</td><td>0.07</td></tr><tr><td>Native JS Map 1,000,000 ObjKey set & get</td><td>348.73</td><td>2.87</td><td>0.07</td></tr><tr><td>Native JS Set 1,000,000 ObjKey add & has</td><td>295.33</td><td>3.39</td><td>0.04</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 set</td><td>86.79</td><td>11.52</td><td>0.03</td></tr><tr><td>Native JS Map 1,000,000 set</td><td>207.96</td><td>4.81</td><td>0.01</td></tr><tr><td>Native JS Set 1,000,000 add</td><td>169.32</td><td>5.91</td><td>0.02</td></tr><tr><td>1,000,000 set & get</td><td>81.30</td><td>12.30</td><td>0.02</td></tr><tr><td>Native JS Map 1,000,000 set & get</td><td>272.31</td><td>3.67</td><td>0.01</td></tr><tr><td>Native JS Set 1,000,000 add & has</td><td>237.78</td><td>4.21</td><td>0.02</td></tr><tr><td>1,000,000 ObjKey set & get</td><td>374.05</td><td>2.67</td><td>0.06</td></tr><tr><td>Native JS Map 1,000,000 ObjKey set & get</td><td>345.51</td><td>2.89</td><td>0.06</td></tr><tr><td>Native JS Set 1,000,000 ObjKey add & has</td><td>286.45</td><td>3.49</td><td>0.05</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>43.24</td><td>23.13</td><td>6.15e-4</td></tr><tr><td>100,000 getWords</td><td>105.06</td><td>9.52</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>41.60</td><td>24.04</td><td>5.38e-4</td></tr><tr><td>100,000 getWords</td><td>81.04</td><td>12.34</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'>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>100,000 add</td><td>309.91</td><td>3.23</td><td>0.01</td></tr><tr><td>100,000 add randomly</td><td>368.42</td><td>2.71</td><td>0.00</td></tr><tr><td>100,000 get</td><td>171.25</td><td>5.84</td><td>0.00</td></tr><tr><td>100,000 iterator</td><td>26.14</td><td>38.25</td><td>0.00</td></tr><tr><td>100,000 add & delete orderly</td><td>511.40</td><td>1.96</td><td>0.00</td></tr><tr><td>100,000 add & delete randomly</td><td>687.43</td><td>1.45</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>100,000 add</td><td>299.03</td><td>3.34</td><td>0.00</td></tr><tr><td>100,000 add randomly</td><td>364.39</td><td>2.74</td><td>0.02</td></tr><tr><td>100,000 get</td><td>1.08</td><td>921.78</td><td>8.08e-5</td></tr><tr><td>100,000 iterator</td><td>27.60</td><td>36.23</td><td>0.00</td></tr><tr><td>100,000 add & delete orderly</td><td>488.82</td><td>2.05</td><td>0.00</td></tr><tr><td>100,000 add & delete randomly</td><td>649.46</td><td>1.54</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'>binary-tree-overall</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 RBTree add randomly</td><td>7.30</td><td>136.94</td><td>9.11e-5</td></tr><tr><td>10,000 RBTree get randomly</td><td>12.92</td><td>77.41</td><td>1.62e-4</td></tr><tr><td>10,000 RBTree add & delete randomly</td><td>22.42</td><td>44.60</td><td>3.28e-4</td></tr><tr><td>10,000 AVLTree add randomly</td><td>28.34</td><td>35.29</td><td>3.30e-4</td></tr><tr><td>10,000 AVLTree get randomly</td><td>12.94</td><td>77.27</td><td>8.60e-5</td></tr><tr><td>10,000 AVLTree add & delete randomly</td><td>52.35</td><td>19.10</td><td>5.13e-4</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 RBTree add randomly</td><td>7.76</td><td>128.90</td><td>1.09e-4</td></tr><tr><td>10,000 RBTree get randomly</td><td>0.11</td><td>9328.86</td><td>5.44e-6</td></tr><tr><td>10,000 RBTree add & delete randomly</td><td>21.72</td><td>46.04</td><td>2.07e-4</td></tr><tr><td>10,000 AVLTree add randomly</td><td>27.45</td><td>36.43</td><td>3.65e-4</td></tr><tr><td>10,000 AVLTree get randomly</td><td>0.11</td><td>9432.49</td><td>4.04e-7</td></tr><tr><td>10,000 AVLTree add & delete randomly</td><td>51.03</td><td>19.60</td><td>6.60e-4</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>directed-graph</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000 addVertex</td><td>0.09</td><td>1.07e+4</td><td>8.73e-7</td></tr><tr><td>1,000 addEdge</td><td>5.98</td><td>167.36</td><td>1.15e-4</td></tr><tr><td>1,000 getVertex</td><td>0.09</td><td>1.05e+4</td><td>8.10e-7</td></tr><tr><td>1,000 getEdge</td><td>23.42</td><td>42.69</td><td>0.00</td></tr><tr><td>tarjan</td><td>210.66</td><td>4.75</td><td>0.04</td></tr><tr><td>topologicalSort</td><td>152.36</td><td>6.56</td><td>0.01</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000 addVertex</td><td>0.10</td><td>1.03e+4</td><td>1.04e-6</td></tr><tr><td>1,000 addEdge</td><td>6.01</td><td>166.29</td><td>1.12e-4</td></tr><tr><td>1,000 getVertex</td><td>0.10</td><td>1.04e+4</td><td>1.71e-6</td></tr><tr><td>1,000 getEdge</td><td>23.72</td><td>42.15</td><td>0.00</td></tr><tr><td>tarjan</td><td>194.37</td><td>5.14</td><td>0.00</td></tr><tr><td>topologicalSort</td><td>152.91</td><td>6.54</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'>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 push</td><td>196.74</td><td>5.08</td><td>0.04</td></tr><tr><td>1,000,000 unshift</td><td>172.87</td><td>5.78</td><td>0.01</td></tr><tr><td>1,000,000 unshift & shift</td><td>151.32</td><td>6.61</td><td>0.01</td></tr><tr><td>1,000,000 addBefore</td><td>262.75</td><td>3.81</td><td>0.07</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 push</td><td>188.44</td><td>5.31</td><td>0.04</td></tr><tr><td>1,000,000 unshift</td><td>177.48</td><td>5.63</td><td>0.02</td></tr><tr><td>1,000,000 unshift & shift</td><td>161.09</td><td>6.21</td><td>0.04</td></tr><tr><td>1,000,000 addBefore</td><td>277.84</td><td>3.60</td><td>0.08</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>1,000,000 push & shift</td><td>164.52</td><td>6.08</td><td>0.03</td></tr><tr><td>10,000 push & pop</td><td>234.45</td><td>4.27</td><td>0.01</td></tr><tr><td>10,000 addBefore</td><td>275.79</td><td>3.63</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 & shift</td><td>193.99</td><td>5.15</td><td>0.05</td></tr><tr><td>10,000 push & pop</td><td>232.82</td><td>4.30</td><td>0.01</td></tr><tr><td>10,000 addBefore</td><td>285.44</td><td>3.50</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'>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>100,000 add</td><td>30.74</td><td>32.53</td><td>0.00</td></tr><tr><td>100,000 add & poll</td><td>88.16</td><td>11.34</td><td>4.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>100,000 add</td><td>30.02</td><td>33.31</td><td>2.68e-4</td></tr><tr><td>100,000 add & poll</td><td>89.21</td><td>11.21</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'>stack</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>42.80</td><td>23.37</td><td>0.01</td></tr><tr><td>1,000,000 push & pop</td><td>48.13</td><td>20.78</td><td>0.01</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 push</td><td>42.73</td><td>23.40</td><td>0.00</td></tr><tr><td>1,000,000 push & pop</td><td>50.52</td><td>19.79</td><td>0.02</td></tr></table></div>
</div>
[//]: # (No deletion!!! End of Replace Section)

48
package-lock.json generated
View file

@ -19,11 +19,11 @@
"@typescript-eslint/eslint-plugin": "^8.12.1",
"@typescript-eslint/parser": "^8.12.1",
"auto-changelog": "^2.5.0",
"avl-tree-typed": "^1.52.8",
"avl-tree-typed": "^1.52.9",
"benchmark": "^2.1.4",
"binary-tree-typed": "^1.52.8",
"bst-typed": "^1.52.8",
"data-structure-typed": "^1.52.8",
"binary-tree-typed": "^1.52.9",
"bst-typed": "^1.52.9",
"data-structure-typed": "^1.52.9",
"dependency-cruiser": "^16.5.0",
"doctoc": "^2.2.1",
"eslint": "^9.13.0",
@ -32,7 +32,7 @@
"eslint-import-resolver-typescript": "^3.6.3",
"eslint-plugin-import": "^2.31.0",
"fast-glob": "^3.3.2",
"heap-typed": "^1.52.8",
"heap-typed": "^1.52.9",
"istanbul-badges-readme": "^1.9.0",
"jest": "^29.7.0",
"js-sdsl": "^4.4.2",
@ -3437,13 +3437,13 @@
}
},
"node_modules/avl-tree-typed": {
"version": "1.52.8",
"resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.52.8.tgz",
"integrity": "sha512-8oU+KjIVtzF9U12NudYuQNBX/If1DL1bKrbqLtKk5RjEq1Jsl56/GIvuzbvKHnGgv9h7DpXHyJUCLjAz3zjhbg==",
"version": "1.52.9",
"resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.52.9.tgz",
"integrity": "sha512-TfapTNrlIquhf1iwrzhc5pEejEhE0CogxiNlaI0nqkv2Qz2OkhvfmAtJOG5ndiFBp4btNZYFGHb+S/zXkEX82A==",
"dev": true,
"license": "MIT",
"dependencies": {
"data-structure-typed": "^1.52.8"
"data-structure-typed": "^1.52.9"
}
},
"node_modules/babel-jest": {
@ -3602,13 +3602,13 @@
}
},
"node_modules/binary-tree-typed": {
"version": "1.52.8",
"resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.52.8.tgz",
"integrity": "sha512-tjUcMufU41Tmp+/6/cBHdSonA+gjhMUpfJqspJ06xp8A3gfWQpf9TjHdY9FxpeeTLPnREpU4SGGZqqIk372XVA==",
"version": "1.52.9",
"resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.52.9.tgz",
"integrity": "sha512-/q5l3wftn485Px+L40NKjKBPukL1XjotSQVCYB+wmz1S3P4H8FobBlEFo5j0UqaW9+TgzhSwecoBbIPsvshXAQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"data-structure-typed": "^1.52.8"
"data-structure-typed": "^1.52.9"
}
},
"node_modules/brace-expansion": {
@ -3691,13 +3691,13 @@
}
},
"node_modules/bst-typed": {
"version": "1.52.8",
"resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.52.8.tgz",
"integrity": "sha512-YMRUaz8jNxSymvKNNyeJR8HozHRgDWUw8PO0QLSvaW/c4Ed/KhpDSyBth52NClFnbJnNV2lTsd01k/VwuerimA==",
"version": "1.52.9",
"resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.52.9.tgz",
"integrity": "sha512-7jgOhrYST+HBZRGvmKx3UZRt6ddBr9Ib807gfJ9+jRVuXQIK9m3hW1MSwXMovWs8tKpF0JZMCqj+uk+S8B85qg==",
"dev": true,
"license": "MIT",
"dependencies": {
"data-structure-typed": "^1.52.8"
"data-structure-typed": "^1.52.9"
}
},
"node_modules/buffer-from": {
@ -4069,9 +4069,9 @@
}
},
"node_modules/data-structure-typed": {
"version": "1.52.8",
"resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.52.8.tgz",
"integrity": "sha512-2YNk0YSjwK0IA8b+g68bmbWtc82M4IzIqo/VUSY16lO3LZ+AajxPkBK68VHPP07ckNNLhdLbh04RoQd3dMNNiw==",
"version": "1.52.9",
"resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.52.9.tgz",
"integrity": "sha512-tIAf4CqOdDz5XJZBtTjWwhOgLOwiMS+1kH9dN44x12klBcKavpUDUjncvrcAqLsVP5xTZSeehJ5teNa6YNgWQQ==",
"dev": true,
"license": "MIT"
},
@ -5946,13 +5946,13 @@
}
},
"node_modules/heap-typed": {
"version": "1.52.8",
"resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.52.8.tgz",
"integrity": "sha512-Zzq+V9IQMf8o2FrIeqc0kRxRyDxOyUPX5dXRi095LnpOFRzUXZoSl2hggbHfsjKEaKwLDRoJuS9t77alqmK4NQ==",
"version": "1.52.9",
"resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.52.9.tgz",
"integrity": "sha512-YdCJFzKob73n5sDovGkL2Y/jqVe+vY9dXcDyx4ToZoneJqJ83IMVDl/qlGb/ujDMlTXqJR4/jiIT5s00jxS7jQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"data-structure-typed": "^1.52.8"
"data-structure-typed": "^1.52.9"
}
},
"node_modules/html-escaper": {

View file

@ -68,11 +68,11 @@
"@typescript-eslint/eslint-plugin": "^8.12.1",
"@typescript-eslint/parser": "^8.12.1",
"auto-changelog": "^2.5.0",
"avl-tree-typed": "^1.52.8",
"avl-tree-typed": "^1.52.9",
"benchmark": "^2.1.4",
"binary-tree-typed": "^1.52.8",
"bst-typed": "^1.52.8",
"data-structure-typed": "^1.52.8",
"binary-tree-typed": "^1.52.9",
"bst-typed": "^1.52.9",
"data-structure-typed": "^1.52.9",
"dependency-cruiser": "^16.5.0",
"doctoc": "^2.2.1",
"eslint": "^9.13.0",
@ -81,7 +81,7 @@
"eslint-import-resolver-typescript": "^3.6.3",
"eslint-plugin-import": "^2.31.0",
"fast-glob": "^3.3.2",
"heap-typed": "^1.52.8",
"heap-typed": "^1.52.9",
"istanbul-badges-readme": "^1.9.0",
"jest": "^29.7.0",
"js-sdsl": "^4.4.2",

View file

@ -10,10 +10,9 @@ import type {
AVLTreeMultiMapNodeNested,
AVLTreeMultiMapOptions,
BinaryTreeDeleteResult,
BSTNKeyOrNode,
BTNKeyOrNodeOrEntry,
IterationType,
BTNEntry
BSTNOptKeyOrNode,
BTNRep,
IterationType
} from '../../types';
import { IBinaryTree } from '../../interfaces';
import { AVLTree, AVLTreeNode } from './avl-tree';
@ -64,7 +63,7 @@ export class AVLTreeMultiMapNode<
export class AVLTreeMultiMap<
K = any,
V = any,
R = BTNEntry<K, V>,
R = object,
NODE extends AVLTreeMultiMapNode<K, V, NODE> = AVLTreeMultiMapNode<K, V, AVLTreeMultiMapNodeNested<K, V>>,
TREE extends AVLTreeMultiMap<K, V, R, NODE, TREE> = AVLTreeMultiMap<
K,
@ -79,18 +78,18 @@ export class AVLTreeMultiMap<
{
/**
* The constructor initializes a new AVLTreeMultiMap object with optional initial elements.
* @param keysOrNodesOrEntriesOrRaws - The `keysOrNodesOrEntriesOrRaws` parameter is an
* @param keysNodesEntriesOrRaws - The `keysNodesEntriesOrRaws` parameter is an
* iterable object that can contain either keys, nodes, entries, or raw elements.
* @param [options] - The `options` parameter is an optional object that can be used to customize the
* behavior of the AVLTreeMultiMap. It can include properties such as `compareKeys` and
* `compareValues` functions to define custom comparison logic for keys and values, respectively.
*/
constructor(
keysOrNodesOrEntriesOrRaws: Iterable<R | BTNKeyOrNodeOrEntry<K, V, NODE>> = [],
keysNodesEntriesOrRaws: Iterable<R | BTNRep<K, V, NODE>> = [],
options?: AVLTreeMultiMapOptions<K, V, R>
) {
super([], options);
if (keysOrNodesOrEntriesOrRaws) this.addMany(keysOrNodesOrEntriesOrRaws);
if (keysNodesEntriesOrRaws) this.addMany(keysNodesEntriesOrRaws);
}
protected _count = 0;
@ -143,6 +142,7 @@ export class AVLTreeMultiMap<
override createTree(options?: AVLTreeMultiMapOptions<K, V, R>): TREE {
return new AVLTreeMultiMap<K, V, R, NODE, TREE>([], {
iterationType: this.iterationType,
isMapMode: this._isMapMode,
comparator: this._comparator,
toEntryFn: this._toEntryFn,
...options
@ -151,20 +151,20 @@ export class AVLTreeMultiMap<
/**
* The function checks if the input is an instance of AVLTreeMultiMapNode.
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R} keyOrNodeOrEntryOrRaw - The parameter
* `keyOrNodeOrEntryOrRaw` can be of type `R` or `BTNKeyOrNodeOrEntry<K, V, NODE>`.
* @returns a boolean value indicating whether the input parameter `keyOrNodeOrEntryOrRaw` is
* @param {BTNRep<K, V, NODE> | R} keyNodeEntryOrRaw - The parameter
* `keyNodeEntryOrRaw` can be of type `R` or `BTNRep<K, V, NODE>`.
* @returns a boolean value indicating whether the input parameter `keyNodeEntryOrRaw` is
* an instance of the `AVLTreeMultiMapNode` class.
*/
override isNode(keyOrNodeOrEntryOrRaw: BTNKeyOrNodeOrEntry<K, V, NODE> | R): keyOrNodeOrEntryOrRaw is NODE {
return keyOrNodeOrEntryOrRaw instanceof AVLTreeMultiMapNode;
override isNode(keyNodeEntryOrRaw: BTNRep<K, V, NODE> | R): keyNodeEntryOrRaw is NODE {
return keyNodeEntryOrRaw instanceof AVLTreeMultiMapNode;
}
/**
* The function `keyValueOrEntryOrRawElementToNode` converts a key, value, entry, or raw element into
* The function `keyValueNodeEntryRawToNodeAndValue` converts a key, value, entry, or raw element into
* a node object.
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R} keyOrNodeOrEntryOrRaw - The
* `keyOrNodeOrEntryOrRaw` parameter can be of type `R` or `BTNKeyOrNodeOrEntry<K, V, NODE>`.
* @param {BTNRep<K, V, NODE> | R} keyNodeEntryOrRaw - The
* `keyNodeEntryOrRaw` parameter can be of type `R` or `BTNRep<K, V, NODE>`.
* @param {V} [value] - The `value` parameter is an optional value that can be passed to the
* `override` function. It represents the value associated with the key in the data structure. If no
* value is provided, it will default to `undefined`.
@ -172,28 +172,33 @@ export class AVLTreeMultiMap<
* times the key-value pair should be added to the data structure. If not provided, it defaults to 1.
* @returns either a NODE object or undefined.
*/
override keyValueOrEntryOrRawElementToNode(
keyOrNodeOrEntryOrRaw: BTNKeyOrNodeOrEntry<K, V, NODE> | R,
override keyValueNodeEntryRawToNodeAndValue(
keyNodeEntryOrRaw: BTNRep<K, V, NODE> | R,
value?: V,
count = 1
): NODE | undefined {
if (keyOrNodeOrEntryOrRaw === undefined || keyOrNodeOrEntryOrRaw === null) return;
if (this.isNode(keyOrNodeOrEntryOrRaw)) return keyOrNodeOrEntryOrRaw;
): [NODE | undefined, V | undefined] {
if (keyNodeEntryOrRaw === undefined || keyNodeEntryOrRaw === null) return [undefined, undefined];
if (this.isNode(keyNodeEntryOrRaw)) return [keyNodeEntryOrRaw, value];
if (this.isEntry(keyOrNodeOrEntryOrRaw)) {
const [key, entryValue] = keyOrNodeOrEntryOrRaw;
if (key === undefined || key === null) return;
if (this.isKey(key)) return this.createNode(key, value ?? entryValue, count);
if (this.isEntry(keyNodeEntryOrRaw)) {
const [key, entryValue] = keyNodeEntryOrRaw;
if (key === undefined || key === null) return [undefined, undefined];
const finalValue = value ?? entryValue;
return [this.createNode(key, finalValue, count), finalValue];
}
if (this._toEntryFn) {
const [key, entryValue] = this._toEntryFn(keyOrNodeOrEntryOrRaw as R);
if (this.isKey(key)) return this.createNode(key, value ?? entryValue, count);
if (this.isKey(keyNodeEntryOrRaw)) return [this.createNode(keyNodeEntryOrRaw, value, count), value];
if (this.isRaw(keyNodeEntryOrRaw)) {
if (this._toEntryFn) {
const [key, entryValue] = this._toEntryFn(keyNodeEntryOrRaw as R);
const finalValue = value ?? entryValue;
if (this.isKey(key)) return [this.createNode(key, finalValue, count), finalValue];
}
return [undefined, undefined];
}
if (this.isKey(keyOrNodeOrEntryOrRaw)) return this.createNode(keyOrNodeOrEntryOrRaw, value, count);
return;
return [undefined, undefined];
}
/**
@ -202,9 +207,9 @@ export class AVLTreeMultiMap<
*
* The function overrides the add method of a TypeScript class to add a new node to a data structure
* and update the count.
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R} keyOrNodeOrEntryOrRaw - The
* `keyOrNodeOrEntryOrRaw` parameter can accept a value of type `R`, which can be any type. It
* can also accept a value of type `BTNKeyOrNodeOrEntry<K, V, NODE>`, which represents a key, node,
* @param {BTNRep<K, V, NODE> | R} keyNodeEntryOrRaw - The
* `keyNodeEntryOrRaw` parameter can accept a value of type `R`, which can be any type. It
* can also accept a value of type `BTNRep<K, V, NODE>`, which represents a key, node,
* entry, or raw element
* @param {V} [value] - The `value` parameter represents the value associated with the key in the
* data structure. It is an optional parameter, so it can be omitted if not needed.
@ -213,12 +218,12 @@ export class AVLTreeMultiMap<
* be added once. However, you can specify a different value for `count` if you want to add
* @returns a boolean value.
*/
override add(keyOrNodeOrEntryOrRaw: BTNKeyOrNodeOrEntry<K, V, NODE> | R, value?: V, count = 1): boolean {
const newNode = this.keyValueOrEntryOrRawElementToNode(keyOrNodeOrEntryOrRaw, value, count);
override add(keyNodeEntryOrRaw: BTNRep<K, V, NODE> | R, value?: V, count = 1): boolean {
const [newNode, newValue] = this.keyValueNodeEntryRawToNodeAndValue(keyNodeEntryOrRaw, value, count);
if (newNode === undefined) return false;
const orgNodeCount = newNode?.count || 0;
const inserted = super.add(newNode);
const inserted = super.add(newNode, newValue);
if (inserted) {
this._count += orgNodeCount;
}
@ -231,7 +236,7 @@ export class AVLTreeMultiMap<
*
* The function overrides the delete method in a binary tree data structure, handling deletion of
* nodes and maintaining balance in the tree.
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R} keyOrNodeOrEntryOrRaw - The `predicate`
* @param {BTNRep<K, V, NODE> | R} keyNodeEntryOrRaw - The `predicate`
* parameter in the `delete` method is used to specify the condition for deleting a node from the
* binary tree. It can be a key, node, or entry that determines which
* node(s) should be deleted.
@ -244,14 +249,11 @@ export class AVLTreeMultiMap<
* method returns an array of `BinaryTreeDeleteResult` objects, each containing information about the
* deleted node and whether balancing is needed in the tree.
*/
override delete(
keyOrNodeOrEntryOrRaw: BTNKeyOrNodeOrEntry<K, V, NODE> | R,
ignoreCount = false
): BinaryTreeDeleteResult<NODE>[] {
override delete(keyNodeEntryOrRaw: BTNRep<K, V, NODE> | R, ignoreCount = false): BinaryTreeDeleteResult<NODE>[] {
const deletedResult: BinaryTreeDeleteResult<NODE>[] = [];
if (!this.root) return deletedResult;
const curr: NODE | undefined = this.getNode(keyOrNodeOrEntryOrRaw) ?? undefined;
const curr: NODE | undefined = this.getNode(keyNodeEntryOrRaw) ?? undefined;
if (!curr) return deletedResult;
const parent: NODE | undefined = curr?.parent ? curr.parent : undefined;
@ -339,7 +341,8 @@ export class AVLTreeMultiMap<
if (l > r) return;
const m = l + Math.floor((r - l) / 2);
const midNode = sorted[m];
this.add(midNode.key, midNode.value, midNode.count);
if (this._isMapMode) this.add(midNode.key, undefined, midNode.count);
else this.add(midNode.key, midNode.value, midNode.count);
buildBalanceBST(l, m - 1);
buildBalanceBST(m + 1, r);
};
@ -355,7 +358,8 @@ export class AVLTreeMultiMap<
if (l <= r) {
const m = l + Math.floor((r - l) / 2);
const midNode = sorted[m];
this.add(midNode.key, midNode.value, midNode.count);
if (this._isMapMode) this.add(midNode.key, undefined, midNode.count);
else this.add(midNode.key, midNode.value, midNode.count);
stack.push([m + 1, r]);
stack.push([l, m - 1]);
}
@ -374,7 +378,9 @@ export class AVLTreeMultiMap<
*/
override clone(): TREE {
const cloned = this.createTree();
this.bfs(node => cloned.add(node.key, node.value, node.count));
if (this._isMapMode) this.bfs(node => cloned.add(node.key, undefined, node.count));
else this.bfs(node => cloned.add(node.key, node.value, node.count));
if (this._isMapMode) cloned._store = this._store;
return cloned;
}
@ -384,16 +390,16 @@ export class AVLTreeMultiMap<
*
* The `_swapProperties` function swaps the properties (key, value, count, height) between two nodes
* in a binary search tree.
* @param {R | BSTNKeyOrNode<K, NODE>} srcNode - The `srcNode` parameter represents the source node
* @param {R | BSTNOptKeyOrNode<K, NODE>} srcNode - The `srcNode` parameter represents the source node
* that will be swapped with the `destNode`.
* @param {R | BSTNKeyOrNode<K, NODE>} destNode - The `destNode` parameter represents the destination
* @param {R | BSTNOptKeyOrNode<K, NODE>} destNode - The `destNode` parameter represents the destination
* node where the properties will be swapped with the source node.
* @returns The method is returning the `destNode` after swapping its properties with the `srcNode`.
* If either `srcNode` or `destNode` is undefined, it returns `undefined`.
*/
protected override _swapProperties(
srcNode: R | BSTNKeyOrNode<K, NODE>,
destNode: R | BSTNKeyOrNode<K, NODE>
srcNode: R | BSTNOptKeyOrNode<K, NODE>,
destNode: R | BSTNOptKeyOrNode<K, NODE>
): NODE | undefined {
srcNode = this.ensureNode(srcNode);
destNode = this.ensureNode(destNode);
@ -404,12 +410,12 @@ export class AVLTreeMultiMap<
tempNode.height = height;
destNode.key = srcNode.key;
destNode.value = srcNode.value;
if (!this._isMapMode) destNode.value = srcNode.value;
destNode.count = srcNode.count;
destNode.height = srcNode.height;
srcNode.key = tempNode.key;
srcNode.value = tempNode.value;
if (!this._isMapMode) srcNode.value = tempNode.value;
srcNode.count = tempNode.count;
srcNode.height = tempNode.height;
}

View file

@ -11,9 +11,8 @@ import type {
AVLTreeNodeNested,
AVLTreeOptions,
BinaryTreeDeleteResult,
BSTNKeyOrNode,
BTNKeyOrNodeOrEntry,
BTNEntry
BSTNOptKeyOrNode,
BTNRep
} from '../../types';
import { IBinaryTree } from '../../interfaces';
@ -67,7 +66,7 @@ export class AVLTreeNode<
export class AVLTree<
K = any,
V = any,
R = BTNEntry<K, V>,
R = object,
NODE extends AVLTreeNode<K, V, NODE> = AVLTreeNode<K, V, AVLTreeNodeNested<K, V>>,
TREE extends AVLTree<K, V, R, NODE, TREE> = AVLTree<K, V, R, NODE, AVLTreeNested<K, V, R, NODE>>
>
@ -77,7 +76,7 @@ export class AVLTree<
/**
* This is a constructor function for an AVLTree class that initializes the tree with keys, nodes,
* entries, or raw elements.
* @param keysOrNodesOrEntriesOrRaws - The `keysOrNodesOrEntriesOrRaws` parameter is an
* @param keysNodesEntriesOrRaws - The `keysNodesEntriesOrRaws` parameter is an
* iterable object that can contain either keys, nodes, entries, or raw elements. These elements will
* be used to initialize the AVLTree.
* @param [options] - The `options` parameter is an optional object that can be used to customize the
@ -85,12 +84,9 @@ export class AVLTree<
* keys), `allowDuplicates` (a boolean indicating whether duplicate keys are allowed), and
* `nodeBuilder` (
*/
constructor(
keysOrNodesOrEntriesOrRaws: Iterable<R | BTNKeyOrNodeOrEntry<K, V, NODE>> = [],
options?: AVLTreeOptions<K, V, R>
) {
constructor(keysNodesEntriesOrRaws: Iterable<R | BTNRep<K, V, NODE>> = [], options?: AVLTreeOptions<K, V, R>) {
super([], options);
if (keysOrNodesOrEntriesOrRaws) super.addMany(keysOrNodesOrEntriesOrRaws);
if (keysNodesEntriesOrRaws) super.addMany(keysNodesEntriesOrRaws);
}
/**
@ -116,6 +112,7 @@ export class AVLTree<
override createTree(options?: AVLTreeOptions<K, V, R>): TREE {
return new AVLTree<K, V, R, NODE, TREE>([], {
iterationType: this.iterationType,
isMapMode: this._isMapMode,
comparator: this._comparator,
toEntryFn: this._toEntryFn,
...options
@ -124,13 +121,13 @@ export class AVLTree<
/**
* The function checks if the input is an instance of AVLTreeNode.
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R} keyOrNodeOrEntryOrRaw - The parameter
* `keyOrNodeOrEntryOrRaw` can be of type `R` or `BTNKeyOrNodeOrEntry<K, V, NODE>`.
* @returns a boolean value indicating whether the input parameter `keyOrNodeOrEntryOrRaw` is
* @param {BTNRep<K, V, NODE> | R} keyNodeEntryOrRaw - The parameter
* `keyNodeEntryOrRaw` can be of type `R` or `BTNRep<K, V, NODE>`.
* @returns a boolean value indicating whether the input parameter `keyNodeEntryOrRaw` is
* an instance of the `AVLTreeNode` class.
*/
override isNode(keyOrNodeOrEntryOrRaw: BTNKeyOrNodeOrEntry<K, V, NODE> | R): keyOrNodeOrEntryOrRaw is NODE {
return keyOrNodeOrEntryOrRaw instanceof AVLTreeNode;
override isNode(keyNodeEntryOrRaw: BTNRep<K, V, NODE> | R): keyNodeEntryOrRaw is NODE {
return keyNodeEntryOrRaw instanceof AVLTreeNode;
}
/**
@ -139,17 +136,17 @@ export class AVLTree<
*
* The function overrides the add method of a class and inserts a key-value pair into a data
* structure, then balances the path.
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R} keyOrNodeOrEntryOrRaw - The parameter
* `keyOrNodeOrEntryOrRaw` can accept values of type `R`, `BTNKeyOrNodeOrEntry<K, V, NODE>`, or
* @param {BTNRep<K, V, NODE> | R} keyNodeEntryOrRaw - The parameter
* `keyNodeEntryOrRaw` can accept values of type `R`, `BTNRep<K, V, NODE>`, or
* `RawElement`.
* @param {V} [value] - The `value` parameter is an optional value that you want to associate with
* the key or node being added to the data structure.
* @returns The method is returning a boolean value.
*/
override add(keyOrNodeOrEntryOrRaw: BTNKeyOrNodeOrEntry<K, V, NODE> | R, value?: V): boolean {
if (keyOrNodeOrEntryOrRaw === null) return false;
const inserted = super.add(keyOrNodeOrEntryOrRaw, value);
if (inserted) this._balancePath(keyOrNodeOrEntryOrRaw);
override add(keyNodeEntryOrRaw: BTNRep<K, V, NODE> | R, value?: V): boolean {
if (keyNodeEntryOrRaw === null) return false;
const inserted = super.add(keyNodeEntryOrRaw, value);
if (inserted) this._balancePath(keyNodeEntryOrRaw);
return inserted;
}
@ -159,15 +156,15 @@ export class AVLTree<
*
* The function overrides the delete method in a TypeScript class, performs deletion, and then
* balances the tree if necessary.
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R} keyOrNodeOrEntryOrRaw - The `keyOrNodeOrEntryOrRaw`
* @param {BTNRep<K, V, NODE> | R} keyNodeEntryOrRaw - The `keyNodeEntryOrRaw`
* parameter in the `override delete` method can be one of the following types:
* @returns The `delete` method is being overridden in this code snippet. It first calls the `delete`
* method from the superclass (presumably a parent class) with the provided `predicate`, which could
* be a key, node, entry, or a custom predicate. The result of this deletion operation is stored in
* `deletedResults`, which is an array of `BinaryTreeDeleteResult` objects.
*/
override delete(keyOrNodeOrEntryOrRaw: BTNKeyOrNodeOrEntry<K, V, NODE> | R): BinaryTreeDeleteResult<NODE>[] {
const deletedResults = super.delete(keyOrNodeOrEntryOrRaw);
override delete(keyNodeEntryOrRaw: BTNRep<K, V, NODE> | R): BinaryTreeDeleteResult<NODE>[] {
const deletedResults = super.delete(keyNodeEntryOrRaw);
for (const { needBalanced } of deletedResults) {
if (needBalanced) {
this._balancePath(needBalanced);
@ -182,16 +179,16 @@ export class AVLTree<
*
* The `_swapProperties` function swaps the key, value, and height properties between two nodes in a
* binary search tree.
* @param {R | BSTNKeyOrNode<K, NODE>} srcNode - The `srcNode` parameter represents either a node
* @param {R | BSTNOptKeyOrNode<K, NODE>} srcNode - The `srcNode` parameter represents either a node
* object (`NODE`) or a key-value pair (`R`) that is being swapped with another node.
* @param {R | BSTNKeyOrNode<K, NODE>} destNode - The `destNode` parameter is either an instance of
* `R` or an instance of `BSTNKeyOrNode<K, NODE>`.
* @param {R | BSTNOptKeyOrNode<K, NODE>} destNode - The `destNode` parameter is either an instance of
* `R` or an instance of `BSTNOptKeyOrNode<K, NODE>`.
* @returns The method is returning the `destNodeEnsured` object if both `srcNodeEnsured` and
* `destNodeEnsured` are truthy. Otherwise, it returns `undefined`.
*/
protected override _swapProperties(
srcNode: R | BSTNKeyOrNode<K, NODE>,
destNode: R | BSTNKeyOrNode<K, NODE>
srcNode: R | BSTNOptKeyOrNode<K, NODE>,
destNode: R | BSTNOptKeyOrNode<K, NODE>
): NODE | undefined {
const srcNodeEnsured = this.ensureNode(srcNode);
const destNodeEnsured = this.ensureNode(destNode);
@ -204,11 +201,11 @@ export class AVLTree<
tempNode.height = height;
destNodeEnsured.key = srcNodeEnsured.key;
destNodeEnsured.value = srcNodeEnsured.value;
if (!this._isMapMode) destNodeEnsured.value = srcNodeEnsured.value;
destNodeEnsured.height = srcNodeEnsured.height;
srcNodeEnsured.key = tempNode.key;
srcNodeEnsured.value = tempNode.value;
if (!this._isMapMode) srcNodeEnsured.value = tempNode.value;
srcNodeEnsured.height = tempNode.height;
}
@ -432,10 +429,10 @@ export class AVLTree<
*
* The `_balancePath` function is used to update the heights of nodes and perform rotation operations
* to restore balance in an AVL tree after inserting a node.
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R} node - The `node` parameter can be of type `R` or
* `BTNKeyOrNodeOrEntry<K, V, NODE>`.
* @param {BTNRep<K, V, NODE> | R} node - The `node` parameter can be of type `R` or
* `BTNRep<K, V, NODE>`.
*/
protected _balancePath(node: BTNKeyOrNodeOrEntry<K, V, NODE> | R): void {
protected _balancePath(node: BTNRep<K, V, NODE> | R): void {
node = this.ensureNode(node);
const path = this.getPathToRoot(node => node, node, false); // first O(log n) + O(log n)
for (let i = 0; i < path.length; i++) {

File diff suppressed because it is too large Load diff

View file

@ -7,18 +7,17 @@
*/
import type {
BSTNested,
BSTNKeyOrNode,
BSTNodeNested,
BSTNOptKeyOrNode,
BSTOptions,
BTNCallback,
BTNEntry,
BTNKeyOrNodeOrEntry,
BTNPredicate,
BTNRep,
Comparator,
CP,
DFSOrderPattern,
IterationType,
OptBSTN
NodeCallback,
NodePredicate,
OptNode
} from '../../types';
import { BinaryTree, BinaryTreeNode } from './binary-tree';
import { IBinaryTree } from '../../interfaces';
@ -45,16 +44,16 @@ export class BSTNode<K = any, V = any, NODE extends BSTNode<K, V, NODE> = BSTNod
* The function returns the value of the `_left` property.
* @returns The `_left` property of the current object is being returned.
*/
override get left(): OptBSTN<NODE> {
override get left(): OptNode<NODE> {
return this._left;
}
/**
* The function sets the left child of a node and updates the parent reference of the child.
* @param {OptBSTN<NODE>} v - The parameter `v` is of type `OptBSTN<NODE>`. It can either be an
* @param {OptNode<NODE>} v - The parameter `v` is of type `OptNode<NODE>`. It can either be an
* instance of the `NODE` class or `undefined`.
*/
override set left(v: OptBSTN<NODE>) {
override set left(v: OptNode<NODE>) {
if (v) {
v.parent = this as unknown as NODE;
}
@ -68,16 +67,16 @@ export class BSTNode<K = any, V = any, NODE extends BSTNode<K, V, NODE> = BSTNod
* @returns The method is returning the value of the `_right` property, which is of type `NODE` or
* `undefined`.
*/
override get right(): OptBSTN<NODE> {
override get right(): OptNode<NODE> {
return this._right;
}
/**
* The function sets the right child of a node and updates the parent reference of the child.
* @param {OptBSTN<NODE>} v - The parameter `v` is of type `OptBSTN<NODE>`. It can either be a
* @param {OptNode<NODE>} v - The parameter `v` is of type `OptNode<NODE>`. It can either be a
* `NODE` object or `undefined`.
*/
override set right(v: OptBSTN<NODE>) {
override set right(v: OptNode<NODE>) {
if (v) {
v.parent = this as unknown as NODE;
}
@ -97,7 +96,7 @@ export class BSTNode<K = any, V = any, NODE extends BSTNode<K, V, NODE> = BSTNod
export class BST<
K = any,
V = any,
R = BTNEntry<K, V>,
R = object,
NODE extends BSTNode<K, V, NODE> = BSTNode<K, V, BSTNodeNested<K, V>>,
TREE extends BST<K, V, R, NODE, TREE> = BST<K, V, R, NODE, BSTNested<K, V, R, NODE>>
>
@ -106,16 +105,13 @@ export class BST<
{
/**
* This is the constructor function for a Binary Search Tree class in TypeScript.
* @param keysOrNodesOrEntriesOrRaws - The `keysOrNodesOrEntriesOrRaws` parameter is an
* @param keysNodesEntriesOrRaws - The `keysNodesEntriesOrRaws` parameter is an
* iterable that can contain either keys, nodes, entries, or raw elements. These elements will be
* added to the binary search tree during the construction of the object.
* @param [options] - An optional object that contains additional options for the Binary Search Tree.
* It can include a comparator function that defines the order of the elements in the tree.
*/
constructor(
keysOrNodesOrEntriesOrRaws: Iterable<R | BTNKeyOrNodeOrEntry<K, V, NODE>> = [],
options?: BSTOptions<K, V, R>
) {
constructor(keysNodesEntriesOrRaws: Iterable<R | BTNRep<K, V, NODE>> = [], options?: BSTOptions<K, V, R>) {
super([], options);
if (options) {
@ -123,7 +119,7 @@ export class BST<
if (comparator) this._comparator = comparator;
}
if (keysOrNodesOrEntriesOrRaws) this.addMany(keysOrNodesOrEntriesOrRaws);
if (keysNodesEntriesOrRaws) this.addMany(keysNodesEntriesOrRaws);
}
protected override _root?: NODE = undefined;
@ -132,7 +128,7 @@ export class BST<
* The function returns the root node of a tree structure.
* @returns The `_root` property of the object, which is of type `NODE` or `undefined`.
*/
override get root(): OptBSTN<NODE> {
override get root(): OptNode<NODE> {
return this._root;
}
@ -158,6 +154,7 @@ export class BST<
override createTree(options?: BSTOptions<K, V, R>): TREE {
return new BST<K, V, R, NODE, TREE>([], {
iterationType: this.iterationType,
isMapMode: this._isMapMode,
comparator: this._comparator,
toEntryFn: this._toEntryFn,
...options
@ -166,18 +163,20 @@ export class BST<
/**
* The function overrides a method and converts a key, value pair or entry or raw element to a node.
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R} keyOrNodeOrEntryOrRaw - A variable that can be of
* type R or BTNKeyOrNodeOrEntry<K, V, NODE>. It represents either a key, a node, an entry, or a raw
* @param {BTNRep<K, V, NODE> | R} keyNodeEntryOrRaw - A variable that can be of
* type R or BTNRep<K, V, NODE>. It represents either a key, a node, an entry, or a raw
* element.
* @param {V} [value] - The `value` parameter is an optional value of type `V`. It represents the
* value associated with a key in a key-value pair.
* @returns either a NODE object or undefined.
*/
override keyValueOrEntryOrRawElementToNode(
keyOrNodeOrEntryOrRaw: BTNKeyOrNodeOrEntry<K, V, NODE> | R,
override keyValueNodeEntryRawToNodeAndValue(
keyNodeEntryOrRaw: BTNRep<K, V, NODE> | R,
value?: V
): OptBSTN<NODE> {
return super.keyValueOrEntryOrRawElementToNode(keyOrNodeOrEntryOrRaw, value) ?? undefined;
): [OptNode<NODE>, V | undefined] {
const [node, tValue] = super.keyValueNodeEntryRawToNodeAndValue(keyNodeEntryOrRaw, value);
if (node === null) return [undefined, undefined];
return [node, tValue ?? value];
}
/**
@ -186,8 +185,8 @@ export class BST<
*
* The function ensures the existence of a node in a data structure and returns it, or undefined if
* it doesn't exist.
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R} keyOrNodeOrEntryOrRaw - The parameter
* `keyOrNodeOrEntryOrRaw` can accept a value of type `R`, which represents the key, node,
* @param {BTNRep<K, V, NODE> | R} keyNodeEntryOrRaw - The parameter
* `keyNodeEntryOrRaw` can accept a value of type `R`, which represents the key, node,
* entry, or raw element that needs to be ensured in the tree.
* @param {IterationType} [iterationType=ITERATIVE] - The `iterationType` parameter is an optional
* parameter that specifies the type of iteration to be used when ensuring a node. It has a default
@ -196,21 +195,21 @@ export class BST<
* not be ensured.
*/
override ensureNode(
keyOrNodeOrEntryOrRaw: BTNKeyOrNodeOrEntry<K, V, NODE> | R,
keyNodeEntryOrRaw: BTNRep<K, V, NODE> | R,
iterationType: IterationType = this.iterationType
): OptBSTN<NODE> {
return super.ensureNode(keyOrNodeOrEntryOrRaw, iterationType) ?? undefined;
): OptNode<NODE> {
return super.ensureNode(keyNodeEntryOrRaw, iterationType) ?? undefined;
}
/**
* The function checks if the input is an instance of the BSTNode class.
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R} keyOrNodeOrEntryOrRaw - The parameter
* `keyOrNodeOrEntryOrRaw` can be of type `R` or `BTNKeyOrNodeOrEntry<K, V, NODE>`.
* @returns a boolean value indicating whether the input parameter `keyOrNodeOrEntryOrRaw` is
* @param {BTNRep<K, V, NODE> | R} keyNodeEntryOrRaw - The parameter
* `keyNodeEntryOrRaw` can be of type `R` or `BTNRep<K, V, NODE>`.
* @returns a boolean value indicating whether the input parameter `keyNodeEntryOrRaw` is
* an instance of the `BSTNode` class.
*/
override isNode(keyOrNodeOrEntryOrRaw: BTNKeyOrNodeOrEntry<K, V, NODE> | R): keyOrNodeOrEntryOrRaw is NODE {
return keyOrNodeOrEntryOrRaw instanceof BSTNode;
override isNode(keyNodeEntryOrRaw: BTNRep<K, V, NODE> | R): keyNodeEntryOrRaw is NODE {
return keyNodeEntryOrRaw instanceof BSTNode;
}
/**
@ -230,18 +229,19 @@ export class BST<
* Space Complexity: O(1)
*
* The `add` function in TypeScript adds a new node to a binary search tree based on the key value.
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R} keyOrNodeOrEntryOrRaw - The parameter
* `keyOrNodeOrEntryOrRaw` can accept a value of type `R` or `BTNKeyOrNodeOrEntry<K, V, NODE>`.
* @param {BTNRep<K, V, NODE> | R} keyNodeEntryOrRaw - The parameter
* `keyNodeEntryOrRaw` can accept a value of type `R` or `BTNRep<K, V, NODE>`.
* @param {V} [value] - The `value` parameter is an optional value that can be associated with the
* key in the binary search tree. If provided, it will be stored in the node along with the key.
* @returns a boolean value.
*/
override add(keyOrNodeOrEntryOrRaw: BTNKeyOrNodeOrEntry<K, V, NODE> | R, value?: V): boolean {
const newNode = this.keyValueOrEntryOrRawElementToNode(keyOrNodeOrEntryOrRaw, value);
override add(keyNodeEntryOrRaw: BTNRep<K, V, NODE> | R, value?: V): boolean {
const [newNode, newValue] = this.keyValueNodeEntryRawToNodeAndValue(keyNodeEntryOrRaw, value);
if (newNode === undefined) return false;
if (this._root === undefined) {
this._setRoot(newNode);
if (this._isMapMode) this._setValue(newNode?.key, newValue);
this._size++;
return true;
}
@ -254,6 +254,7 @@ export class BST<
} else if (this.comparator(current.key, newNode.key) > 0) {
if (current.left === undefined) {
current.left = newNode;
if (this._isMapMode) this._setValue(newNode?.key, newValue);
this._size++;
return true;
}
@ -261,6 +262,7 @@ export class BST<
} else {
if (current.right === undefined) {
current.right = newNode;
if (this._isMapMode) this._setValue(newNode?.key, newValue);
this._size++;
return true;
}
@ -277,7 +279,7 @@ export class BST<
*
* The `addMany` function in TypeScript adds multiple keys or nodes to a data structure and returns
* an array indicating whether each key or node was successfully inserted.
* @param keysOrNodesOrEntriesOrRaws - An iterable containing keys, nodes, entries, or raw
* @param keysNodesEntriesOrRaws - An iterable containing keys, nodes, entries, or raw
* elements to be added to the data structure.
* @param [values] - An optional iterable of values to be associated with the keys or nodes being
* added. If provided, the values will be assigned to the corresponding keys or nodes in the same
@ -293,7 +295,7 @@ export class BST<
* successfully inserted into the data structure.
*/
override addMany(
keysOrNodesOrEntriesOrRaws: Iterable<R | BTNKeyOrNodeOrEntry<K, V, NODE>>,
keysNodesEntriesOrRaws: Iterable<R | BTNRep<K, V, NODE>>,
values?: Iterable<V | undefined>,
isBalanceAdd = true,
iterationType: IterationType = this.iterationType
@ -307,7 +309,7 @@ export class BST<
}
if (!isBalanceAdd) {
for (const kve of keysOrNodesOrEntriesOrRaws) {
for (const kve of keysNodesEntriesOrRaws) {
const value = valuesIterator?.next().value;
inserted.push(this.add(kve, value));
}
@ -315,18 +317,18 @@ export class BST<
}
const realBTNExemplars: {
key: R | BTNKeyOrNodeOrEntry<K, V, NODE>;
key: R | BTNRep<K, V, NODE>;
value: V | undefined;
orgIndex: number;
}[] = [];
let i = 0;
for (const kve of keysOrNodesOrEntriesOrRaws) {
for (const kve of keysNodesEntriesOrRaws) {
realBTNExemplars.push({ key: kve, value: valuesIterator?.next().value, orgIndex: i });
i++;
}
let sorted: { key: R | BTNKeyOrNodeOrEntry<K, V, NODE>; value: V | undefined; orgIndex: number }[] = [];
let sorted: { key: R | BTNRep<K, V, NODE>; value: V | undefined; orgIndex: number }[] = [];
sorted = realBTNExemplars.sort(({ key: a }, { key: b }) => {
let keyA: K | undefined | null, keyB: K | undefined | null;
@ -352,7 +354,7 @@ export class BST<
return 0;
});
const _dfs = (arr: { key: R | BTNKeyOrNodeOrEntry<K, V, NODE>; value: V | undefined; orgIndex: number }[]) => {
const _dfs = (arr: { key: R | BTNRep<K, V, NODE>; value: V | undefined; orgIndex: number }[]) => {
if (arr.length === 0) return;
const mid = Math.floor((arr.length - 1) / 2);
@ -394,35 +396,35 @@ export class BST<
* Space Complexity: O(k + log n)
*
* The function `getNodes` in TypeScript overrides the base class method to retrieve nodes based on a
* given predicate and iteration type.
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R | BTNPredicate<NODE>} predicate - The `predicate`
* given keyNodeEntryRawOrPredicate and iteration type.
* @param {BTNRep<K, V, NODE> | R | NodePredicate<NODE>} keyNodeEntryRawOrPredicate - The `keyNodeEntryRawOrPredicate`
* parameter in the `getNodes` method is used to filter the nodes that will be returned. It can be a
* key, a node, an entry, or a custom predicate function that determines whether a node should be
* key, a node, an entry, or a custom keyNodeEntryRawOrPredicate function that determines whether a node should be
* included in the result.
* @param [onlyOne=false] - The `onlyOne` parameter in the `getNodes` method is a boolean flag that
* determines whether to return only the first node that matches the predicate (`true`) or all nodes
* that match the predicate (`false`). If `onlyOne` is set to `true`, the method will stop iterating
* determines whether to return only the first node that matches the keyNodeEntryRawOrPredicate (`true`) or all nodes
* that match the keyNodeEntryRawOrPredicate (`false`). If `onlyOne` is set to `true`, the method will stop iterating
* and
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R} beginRoot - The `beginRoot` parameter in the
* @param {BTNRep<K, V, NODE> | R} startNode - The `startNode` parameter in the
* `getNodes` method is used to specify the starting point for traversing the tree when searching for
* nodes that match a given predicate. It represents the root node of the subtree where the search
* nodes that match a given keyNodeEntryRawOrPredicate. It represents the root node of the subtree where the search
* should begin. If not explicitly provided, the default value for `begin
* @param {IterationType} iterationType - The `iterationType` parameter in the `getNodes` method
* specifies the type of iteration to be performed when traversing the nodes of a binary tree. It can
* have two possible values:
* @returns The `getNodes` method returns an array of nodes that satisfy the given predicate.
* @returns The `getNodes` method returns an array of nodes that satisfy the given keyNodeEntryRawOrPredicate.
*/
override getNodes(
predicate: BTNKeyOrNodeOrEntry<K, V, NODE> | R | BTNPredicate<NODE>,
keyNodeEntryRawOrPredicate: BTNRep<K, V, NODE> | R | NodePredicate<NODE>,
onlyOne = false,
beginRoot: BTNKeyOrNodeOrEntry<K, V, NODE> | R = this._root,
startNode: BTNRep<K, V, NODE> | R = this._root,
iterationType: IterationType = this.iterationType
): NODE[] {
if (predicate === undefined) return [];
if (predicate === null) return [];
beginRoot = this.ensureNode(beginRoot);
if (!beginRoot) return [];
const callback = this._ensurePredicate(predicate);
if (keyNodeEntryRawOrPredicate === undefined) return [];
if (keyNodeEntryRawOrPredicate === null) return [];
startNode = this.ensureNode(startNode);
if (!startNode) return [];
const callback = this._ensurePredicate(keyNodeEntryRawOrPredicate);
const ans: NODE[] = [];
if (iterationType === 'RECURSIVE') {
@ -433,27 +435,53 @@ export class BST<
}
if (!this.isRealNode(cur.left) && !this.isRealNode(cur.right)) return;
if (this.isKey(predicate)) {
if (this.isRealNode(cur.left) && this.comparator(cur.key, predicate) > 0) dfs(cur.left);
if (this.isRealNode(cur.right) && this.comparator(cur.key, predicate) < 0) dfs(cur.right);
if (!this._isPredicate(keyNodeEntryRawOrPredicate)) {
const benchmarkKey = this._getKey(keyNodeEntryRawOrPredicate);
if (
this.isRealNode(cur.left) &&
benchmarkKey !== null &&
benchmarkKey !== undefined &&
this.comparator(cur.key, benchmarkKey) > 0
)
dfs(cur.left);
if (
this.isRealNode(cur.right) &&
benchmarkKey !== null &&
benchmarkKey !== undefined &&
this.comparator(cur.key, benchmarkKey) < 0
)
dfs(cur.right);
} else {
if (this.isRealNode(cur.left)) dfs(cur.left);
if (this.isRealNode(cur.right)) dfs(cur.right);
}
};
dfs(beginRoot);
dfs(startNode);
} else {
const stack = [beginRoot];
const stack = [startNode];
while (stack.length > 0) {
const cur = stack.pop()!;
if (callback(cur)) {
ans.push(cur);
if (onlyOne) return ans;
}
if (this.isKey(predicate)) {
if (this.isRealNode(cur.right) && this.comparator(cur.key, predicate) < 0) stack.push(cur.right);
if (this.isRealNode(cur.left) && this.comparator(cur.key, predicate) > 0) stack.push(cur.left);
if (!this._isPredicate(keyNodeEntryRawOrPredicate)) {
const benchmarkKey = this._getKey(keyNodeEntryRawOrPredicate);
if (
this.isRealNode(cur.right) &&
benchmarkKey !== null &&
benchmarkKey !== undefined &&
this.comparator(cur.key, benchmarkKey) < 0
)
stack.push(cur.right);
if (
this.isRealNode(cur.left) &&
benchmarkKey !== null &&
benchmarkKey !== undefined &&
this.comparator(cur.key, benchmarkKey) > 0
)
stack.push(cur.left);
} else {
if (this.isRealNode(cur.right)) stack.push(cur.right);
if (this.isRealNode(cur.left)) stack.push(cur.left);
@ -468,10 +496,10 @@ export class BST<
* Time Complexity: O(log n)
* Space Complexity: O(1)
*
* This function retrieves a node based on a given predicate within a binary search tree structure.
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R | BTNPredicate<NODE>} predicate - The `predicate`
* parameter can be of type `BTNKeyOrNodeOrEntry<K, V, NODE>`, `R`, or `BTNPredicate<NODE>`.
* @param {R | BSTNKeyOrNode<K, NODE>} beginRoot - The `beginRoot` parameter in the `getNode` method
* This function retrieves a node based on a given keyNodeEntryRawOrPredicate within a binary search tree structure.
* @param {BTNRep<K, V, NODE> | R | NodePredicate<NODE>} keyNodeEntryRawOrPredicate - The `keyNodeEntryRawOrPredicate`
* parameter can be of type `BTNRep<K, V, NODE>`, `R`, or `NodePredicate<NODE>`.
* @param {R | BSTNOptKeyOrNode<K, NODE>} startNode - The `startNode` parameter in the `getNode` method
* is used to specify the starting point for searching nodes in the binary search tree. If no
* specific starting point is provided, the default value is set to `this._root`, which is the root
* node of the binary search tree.
@ -479,17 +507,17 @@ export class BST<
* parameter that specifies the type of iteration to be used. It has a default value of
* `this.iterationType`, which means it will use the iteration type defined in the class instance if
* no value is provided when calling the method.
* @returns The `getNode` method is returning an optional binary search tree node (`OptBSTN<NODE>`).
* It is using the `getNodes` method to find the node based on the provided predicate, beginning at
* the specified root node (`beginRoot`) and using the specified iteration type. The method then
* @returns The `getNode` method is returning an optional binary search tree node (`OptNode<NODE>`).
* It is using the `getNodes` method to find the node based on the provided keyNodeEntryRawOrPredicate, beginning at
* the specified root node (`startNode`) and using the specified iteration type. The method then
* returns the first node found or `undefined` if no node is found.
*/
override getNode(
predicate: BTNKeyOrNodeOrEntry<K, V, NODE> | R | BTNPredicate<NODE>,
beginRoot: R | BSTNKeyOrNode<K, NODE> = this._root,
keyNodeEntryRawOrPredicate: BTNRep<K, V, NODE> | R | NodePredicate<NODE>,
startNode: R | BSTNOptKeyOrNode<K, NODE> = this._root,
iterationType: IterationType = this.iterationType
): OptBSTN<NODE> {
return this.getNodes(predicate, true, beginRoot, iterationType)[0] ?? undefined;
): OptNode<NODE> {
return this.getNodes(keyNodeEntryRawOrPredicate, true, startNode, iterationType)[0] ?? undefined;
}
/**
@ -505,7 +533,7 @@ export class BST<
* It has a default value of `'ITERATIVE'`.
* @returns The method is returning a NODE object or undefined.
*/
override getNodeByKey(key: K, iterationType: IterationType = this.iterationType): OptBSTN<NODE> {
override getNodeByKey(key: K, iterationType: IterationType = this.iterationType): OptNode<NODE> {
return this.getNode(key, this._root, iterationType);
}
@ -517,11 +545,11 @@ export class BST<
* the callback function.
* @param {C} callback - The `callback` parameter is a function that will be called for each node
* during the depth-first search traversal. It is an optional parameter and defaults to
* `this._DEFAULT_BTN_CALLBACK`. The type `C` represents the type of the callback function.
* `this._DEFAULT_NODE_CALLBACK`. The type `C` represents the type of the callback function.
* @param {DFSOrderPattern} [pattern=IN] - The "pattern" parameter in the code snippet refers to the
* order in which the Depth-First Search (DFS) algorithm visits the nodes in a tree or graph. It can
* take one of the following values:
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R} beginRoot - The `beginRoot` parameter is the starting
* @param {BTNRep<K, V, NODE> | R} startNode - The `startNode` parameter is the starting
* point for the depth-first search traversal. It can be either a root node, a key-value pair, or a
* node entry. If not specified, the default value is the root of the tree.
* @param {IterationType} [iterationType=ITERATIVE] - The `iterationType` parameter specifies the
@ -529,13 +557,13 @@ export class BST<
* following values:
* @returns The method is returning an array of the return type of the callback function.
*/
override dfs<C extends BTNCallback<NODE>>(
callback: C = this._DEFAULT_BTN_CALLBACK as C,
override dfs<C extends NodeCallback<NODE>>(
callback: C = this._DEFAULT_NODE_CALLBACK as C,
pattern: DFSOrderPattern = 'IN',
beginRoot: BTNKeyOrNodeOrEntry<K, V, NODE> | R = this._root,
startNode: BTNRep<K, V, NODE> | R = this._root,
iterationType: IterationType = this.iterationType
): ReturnType<C>[] {
return super.dfs(callback, pattern, beginRoot, iterationType);
return super.dfs(callback, pattern, startNode, iterationType);
}
/**
@ -547,7 +575,7 @@ export class BST<
* @param {C} callback - The `callback` parameter is a function that will be called for each node
* visited during the breadth-first search. It should take a single argument, which is the current
* node being visited, and it can return a value of any type.
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R} beginRoot - The `beginRoot` parameter is the starting
* @param {BTNRep<K, V, NODE> | R} startNode - The `startNode` parameter is the starting
* point for the breadth-first search. It can be either a root node, a key-value pair, or an entry
* object. If no value is provided, the default value is the root of the tree.
* @param {IterationType} iterationType - The `iterationType` parameter is used to specify the type
@ -555,12 +583,12 @@ export class BST<
* the following values:
* @returns an array of the return type of the callback function.
*/
override bfs<C extends BTNCallback<NODE>>(
callback: C = this._DEFAULT_BTN_CALLBACK as C,
beginRoot: BTNKeyOrNodeOrEntry<K, V, NODE> | R = this._root,
override bfs<C extends NodeCallback<NODE>>(
callback: C = this._DEFAULT_NODE_CALLBACK as C,
startNode: BTNRep<K, V, NODE> | R = this._root,
iterationType: IterationType = this.iterationType
): ReturnType<C>[] {
return super.bfs(callback, beginRoot, iterationType, false);
return super.bfs(callback, startNode, iterationType, false);
}
/**
@ -570,9 +598,9 @@ export class BST<
* The function overrides the listLevels method from the superclass and returns an array of arrays
* containing the results of the callback function applied to each level of the tree.
* @param {C} callback - The `callback` parameter is a generic type `C` that extends
* `BTNCallback<NODE>`. It represents a callback function that will be called for each node in the
* `NodeCallback<NODE>`. It represents a callback function that will be called for each node in the
* tree during the iteration process.
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R} beginRoot - The `beginRoot` parameter is the starting
* @param {BTNRep<K, V, NODE> | R} startNode - The `startNode` parameter is the starting
* point for listing the levels of the binary tree. It can be either a root node of the tree, a
* key-value pair representing a node in the tree, or a key representing a node in the tree. If no
* value is provided, the root of
@ -581,12 +609,12 @@ export class BST<
* @returns The method is returning a two-dimensional array of the return type of the callback
* function.
*/
override listLevels<C extends BTNCallback<NODE>>(
callback: C = this._DEFAULT_BTN_CALLBACK as C,
beginRoot: BTNKeyOrNodeOrEntry<K, V, NODE> | R = this._root,
override listLevels<C extends NodeCallback<NODE>>(
callback: C = this._DEFAULT_NODE_CALLBACK as C,
startNode: BTNRep<K, V, NODE> | R = this._root,
iterationType: IterationType = this.iterationType
): ReturnType<C>[][] {
return super.listLevels(callback, beginRoot, iterationType, false);
return super.listLevels(callback, startNode, iterationType, false);
}
/**
@ -601,7 +629,7 @@ export class BST<
* @param {CP} lesserOrGreater - The `lesserOrGreater` parameter is used to determine whether to
* traverse nodes that are lesser, greater, or both than the `targetNode`. It accepts the values -1,
* 0, or 1, where:
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R} targetNode - The `targetNode` parameter is the node in
* @param {BTNRep<K, V, NODE> | R} targetNode - The `targetNode` parameter is the node in
* the binary tree that you want to start traversing from. It can be specified either by providing
* the key of the node, the node itself, or an entry containing the key and value of the node. If no
* `targetNode` is provided,
@ -610,14 +638,14 @@ export class BST<
* @returns The function `lesserOrGreaterTraverse` returns an array of values of type
* `ReturnType<C>`, which is the return type of the callback function passed as an argument.
*/
lesserOrGreaterTraverse<C extends BTNCallback<NODE>>(
callback: C = this._DEFAULT_BTN_CALLBACK as C,
lesserOrGreaterTraverse<C extends NodeCallback<NODE>>(
callback: C = this._DEFAULT_NODE_CALLBACK as C,
lesserOrGreater: CP = -1,
targetNode: BTNKeyOrNodeOrEntry<K, V, NODE> | R = this._root,
targetNode: BTNRep<K, V, NODE> | R = this._root,
iterationType: IterationType = this.iterationType
): ReturnType<C>[] {
const targetNodeEnsured = this.ensureNode(targetNode);
const ans: ReturnType<BTNCallback<NODE>>[] = [];
const ans: ReturnType<NodeCallback<NODE>>[] = [];
if (!this._root) return ans;
if (!targetNodeEnsured) return ans;
@ -665,7 +693,7 @@ export class BST<
perfectlyBalance(iterationType: IterationType = this.iterationType): boolean {
const sorted = this.dfs(node => node, 'IN'),
n = sorted.length;
this.clear();
this._clearNodes();
if (sorted.length < 1) return false;
if (iterationType === 'RECURSIVE') {
@ -673,7 +701,8 @@ export class BST<
if (l > r) return;
const m = l + Math.floor((r - l) / 2);
const midNode = sorted[m];
this.add([midNode.key, midNode.value]);
if (this._isMapMode) this.add(midNode.key);
else this.add([midNode.key, midNode.value]);
buildBalanceBST(l, m - 1);
buildBalanceBST(m + 1, r);
};
@ -689,7 +718,8 @@ export class BST<
if (l <= r) {
const m = l + Math.floor((r - l) / 2);
const midNode = sorted[m];
this.add([midNode.key, midNode.value]);
if (this._isMapMode) this.add(midNode.key);
else this.add([midNode.key, midNode.value]);
stack.push([m + 1, r]);
stack.push([l, m - 1]);
}
@ -717,7 +747,7 @@ export class BST<
let balanced = true;
if (iterationType === 'RECURSIVE') {
const _height = (cur: OptBSTN<NODE>): number => {
const _height = (cur: OptNode<NODE>): number => {
if (!cur) return 0;
const leftHeight = _height(cur.left),
rightHeight = _height(cur.right);
@ -727,8 +757,8 @@ export class BST<
_height(this._root);
} else {
const stack: NODE[] = [];
let node: OptBSTN<NODE> = this._root,
last: OptBSTN<NODE> = undefined;
let node: OptNode<NODE> = this._root,
last: OptNode<NODE> = undefined;
const depths: Map<NODE, number> = new Map();
while (stack.length > 0 || node) {
@ -779,9 +809,9 @@ export class BST<
/**
* The function sets the root of a tree-like structure and updates the parent property of the new
* root.
* @param {OptBSTN<NODE>} v - v is a parameter of type NODE or undefined.
* @param {OptNode<NODE>} v - v is a parameter of type NODE or undefined.
*/
protected override _setRoot(v: OptBSTN<NODE>) {
protected override _setRoot(v: OptNode<NODE>) {
if (v) {
v.parent = undefined;
}

View file

@ -1,13 +1,12 @@
import type {
BinaryTreeDeleteResult,
BTNKeyOrNodeOrEntry,
BTNRep,
CRUD,
OptBSTN,
OptNode,
RBTNColor,
RBTreeOptions,
RedBlackTreeNested,
RedBlackTreeNodeNested,
BTNEntry
RedBlackTreeNodeNested
} from '../../types';
import { BST, BSTNode } from './bst';
import { IBinaryTree } from '../../interfaces';
@ -55,7 +54,7 @@ export class RedBlackTreeNode<
export class RedBlackTree<
K = any,
V = any,
R = BTNEntry<K, V>,
R = object,
NODE extends RedBlackTreeNode<K, V, NODE> = RedBlackTreeNode<K, V, RedBlackTreeNodeNested<K, V>>,
TREE extends RedBlackTree<K, V, R, NODE, TREE> = RedBlackTree<K, V, R, NODE, RedBlackTreeNested<K, V, R, NODE>>
>
@ -64,7 +63,7 @@ export class RedBlackTree<
{
/**
* This is the constructor function for a Red-Black Tree data structure in TypeScript.
* @param keysOrNodesOrEntriesOrRaws - The `keysOrNodesOrEntriesOrRaws` parameter is an
* @param keysNodesEntriesOrRaws - The `keysNodesEntriesOrRaws` parameter is an
* iterable object that can contain either keys, nodes, entries, or raw elements. It is used to
* initialize the RBTree with the provided elements.
* @param [options] - The `options` parameter is an optional object that can be passed to the
@ -72,16 +71,13 @@ export class RedBlackTree<
* configuring the behavior of the Red-Black Tree. The specific properties and their meanings would
* depend on the implementation
*/
constructor(
keysOrNodesOrEntriesOrRaws: Iterable<R | BTNKeyOrNodeOrEntry<K, V, NODE>> = [],
options?: RBTreeOptions<K, V, R>
) {
constructor(keysNodesEntriesOrRaws: Iterable<R | BTNRep<K, V, NODE>> = [], options?: RBTreeOptions<K, V, R>) {
super([], options);
this._root = this.NIL;
if (keysOrNodesOrEntriesOrRaws) {
this.addMany(keysOrNodesOrEntriesOrRaws);
if (keysNodesEntriesOrRaws) {
this.addMany(keysNodesEntriesOrRaws);
}
}
@ -122,6 +118,7 @@ export class RedBlackTree<
override createTree(options?: RBTreeOptions<K, V, R>): TREE {
return new RedBlackTree<K, V, R, NODE, TREE>([], {
iterationType: this.iterationType,
isMapMode: this._isMapMode,
comparator: this._comparator,
toEntryFn: this._toEntryFn,
...options
@ -133,13 +130,13 @@ export class RedBlackTree<
* Space Complexity: O(1)
*
* The function checks if the input is an instance of the RedBlackTreeNode class.
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R} keyOrNodeOrEntryOrRaw - The parameter
* `keyOrNodeOrEntryOrRaw` can be of type `R` or `BTNKeyOrNodeOrEntry<K, V, NODE>`.
* @returns a boolean value indicating whether the input parameter `keyOrNodeOrEntryOrRaw` is
* @param {BTNRep<K, V, NODE> | R} keyNodeEntryOrRaw - The parameter
* `keyNodeEntryOrRaw` can be of type `R` or `BTNRep<K, V, NODE>`.
* @returns a boolean value indicating whether the input parameter `keyNodeEntryOrRaw` is
* an instance of the `RedBlackTreeNode` class.
*/
override isNode(keyOrNodeOrEntryOrRaw: BTNKeyOrNodeOrEntry<K, V, NODE> | R): keyOrNodeOrEntryOrRaw is NODE {
return keyOrNodeOrEntryOrRaw instanceof RedBlackTreeNode;
override isNode(keyNodeEntryOrRaw: BTNRep<K, V, NODE> | R): keyNodeEntryOrRaw is NODE {
return keyNodeEntryOrRaw instanceof RedBlackTreeNode;
}
// /**
@ -151,29 +148,29 @@ export class RedBlackTree<
// * Time Complexity: O(1)
// * Space Complexity: O(1)
// *
// * The function `keyValueOrEntryOrRawElementToNode` takes a key, value, or entry and returns a node if it is
// * The function `keyValueNodeEntryRawToNodeAndValue` takes a key, value, or entry and returns a node if it is
// * valid, otherwise it returns undefined.
// * @param {BTNKeyOrNodeOrEntry<K, V, NODE>} keyOrNodeOrEntryOrRaw - The key, value, or entry to convert.
// * @param {V} [value] - The value associated with the key (if `keyOrNodeOrEntryOrRaw` is a key).
// * @param {BTNRep<K, V, NODE>} keyNodeEntryOrRaw - The key, value, or entry to convert.
// * @param {V} [value] - The value associated with the key (if `keyNodeEntryOrRaw` is a key).
// * @returns {NODE | undefined} - The corresponding Red-Black Tree node, or `undefined` if conversion fails.
// */
// override keyValueOrEntryOrRawElementToNode(keyOrNodeOrEntryOrRaw: BTNKeyOrNodeOrEntry<K, V, NODE> | R, value?: V): NODE | undefined {
// override keyValueNodeEntryRawToNodeAndValue(keyNodeEntryOrRaw: BTNRep<K, V, NODE> | R, value?: V): NODE | undefined {
//
// if (keyOrNodeOrEntryOrRaw === null || keyOrNodeOrEntryOrRaw === undefined) return;
// if (this.isNode(keyOrNodeOrEntryOrRaw)) return keyOrNodeOrEntryOrRaw;
// if (keyNodeEntryOrRaw === null || keyNodeEntryOrRaw === undefined) return;
// if (this.isNode(keyNodeEntryOrRaw)) return keyNodeEntryOrRaw;
//
// if (this._toEntryFn) {
// const [key, entryValue] = this._toEntryFn(keyOrNodeOrEntryOrRaw as R);
// if (this.isKey(key)) return this.createNode(key, entryValue ?? value, 'RED');
// const [key, entryValue] = this._toEntryFn(keyNodeEntryOrRaw as R);
// if (this.isKey(key)) return this.createNode(key, value ?? entryValue, 'RED');
// }
//
// if (this.isEntry(keyOrNodeOrEntryOrRaw)) {
// const [key, value] = keyOrNodeOrEntryOrRaw;
// if (this.isEntry(keyNodeEntryOrRaw)) {
// const [key, value] = keyNodeEntryOrRaw;
// if (key === undefined || key === null) return;
// else return this.createNode(key, value, 'RED');
// }
//
// if (this.isKey(keyOrNodeOrEntryOrRaw)) return this.createNode(keyOrNodeOrEntryOrRaw, value, 'RED');
// if (this.isKey(keyNodeEntryOrRaw)) return this.createNode(keyNodeEntryOrRaw, value, 'RED');
//
// return ;
// }
@ -196,8 +193,8 @@ export class RedBlackTree<
*
* The function adds a new node to a binary search tree and returns true if the node was successfully
* added.
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R} keyOrNodeOrEntryOrRaw - The parameter
* `keyOrNodeOrEntryOrRaw` can accept a value of type `R` or `BTNKeyOrNodeOrEntry<K, V, NODE>`.
* @param {BTNRep<K, V, NODE> | R} keyNodeEntryOrRaw - The parameter
* `keyNodeEntryOrRaw` can accept a value of type `R` or `BTNRep<K, V, NODE>`.
* @param {V} [value] - The `value` parameter is an optional value that you want to associate with
* the key in the data structure. It represents the value that you want to add or update in the data
* structure.
@ -205,8 +202,8 @@ export class RedBlackTree<
* the method returns true. If the node already exists and its value is updated, the method also
* returns true. If the node cannot be added or updated, the method returns false.
*/
override add(keyOrNodeOrEntryOrRaw: BTNKeyOrNodeOrEntry<K, V, NODE> | R, value?: V): boolean {
const newNode = this.keyValueOrEntryOrRawElementToNode(keyOrNodeOrEntryOrRaw, value);
override add(keyNodeEntryOrRaw: BTNRep<K, V, NODE> | R, value?: V): boolean {
const [newNode, newValue] = this.keyValueNodeEntryRawToNodeAndValue(keyNodeEntryOrRaw, value);
if (!this.isRealNode(newNode)) return false;
const insertStatus = this._insert(newNode);
@ -218,6 +215,7 @@ export class RedBlackTree<
} else {
return false;
}
if (this._isMapMode) this._setValue(newNode.key, newValue);
this._size++;
return true;
} else return insertStatus === 'UPDATED';
@ -229,7 +227,7 @@ export class RedBlackTree<
*
* The function overrides the delete method in a binary tree data structure to remove a node based on
* a given predicate and maintain the binary search tree properties.
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R} keyOrNodeOrEntryOrRaw - The `keyOrNodeOrEntryOrRaw`
* @param {BTNRep<K, V, NODE> | R} keyNodeEntryOrRaw - The `keyNodeEntryOrRaw`
* parameter in the `override delete` method is used to specify the condition or key based on which a
* node should be deleted from the binary tree. It can be a key, a node, an entry, or a predicate
* function that determines which node(s) should be deleted.
@ -237,16 +235,13 @@ export class RedBlackTree<
* objects. Each object in the array contains information about the deleted node and whether
* balancing is needed.
*/
override delete(keyOrNodeOrEntryOrRaw: BTNKeyOrNodeOrEntry<K, V, NODE> | R): BinaryTreeDeleteResult<NODE>[] {
if (keyOrNodeOrEntryOrRaw === null) return [];
override delete(keyNodeEntryOrRaw: BTNRep<K, V, NODE> | R): BinaryTreeDeleteResult<NODE>[] {
if (keyNodeEntryOrRaw === null) return [];
const results: BinaryTreeDeleteResult<NODE>[] = [];
let nodeToDelete: OptBSTN<NODE>;
if (this._isPredicated(keyOrNodeOrEntryOrRaw)) nodeToDelete = this.getNode(keyOrNodeOrEntryOrRaw);
else
nodeToDelete = this.isRealNode(keyOrNodeOrEntryOrRaw)
? keyOrNodeOrEntryOrRaw
: this.getNode(keyOrNodeOrEntryOrRaw);
let nodeToDelete: OptNode<NODE>;
if (this._isPredicate(keyNodeEntryOrRaw)) nodeToDelete = this.getNode(keyNodeEntryOrRaw);
else nodeToDelete = this.isRealNode(keyNodeEntryOrRaw) ? keyNodeEntryOrRaw : this.getNode(keyNodeEntryOrRaw);
if (!nodeToDelete) {
return results;
@ -287,6 +282,7 @@ export class RedBlackTree<
successor.color = nodeToDelete.color;
}
}
if (this._isMapMode) this._store.delete(nodeToDelete.key);
this._size--;
// If the original color was black, fix the tree

View file

@ -7,15 +7,14 @@
*/
import type {
BinaryTreeDeleteResult,
BSTNKeyOrNode,
BTNKeyOrNodeOrEntry,
BSTNOptKeyOrNode,
BTNRep,
IterationType,
OptBSTN,
OptNode,
RBTNColor,
TreeMultiMapNested,
TreeMultiMapNodeNested,
TreeMultiMapOptions,
BTNEntry
TreeMultiMapOptions
} from '../../types';
import { IBinaryTree } from '../../interfaces';
import { RedBlackTree, RedBlackTreeNode } from './rb-tree';
@ -65,7 +64,7 @@ export class TreeMultiMapNode<
export class TreeMultiMap<
K = any,
V = any,
R = BTNEntry<K, V>,
R = object,
NODE extends TreeMultiMapNode<K, V, NODE> = TreeMultiMapNode<K, V, TreeMultiMapNodeNested<K, V>>,
TREE extends TreeMultiMap<K, V, R, NODE, TREE> = TreeMultiMap<K, V, R, NODE, TreeMultiMapNested<K, V, R, NODE>>
>
@ -74,19 +73,16 @@ export class TreeMultiMap<
{
/**
* The constructor function initializes a TreeMultiMap object with optional initial data.
* @param keysOrNodesOrEntriesOrRaws - The parameter `keysOrNodesOrEntriesOrRaws` is an
* @param keysNodesEntriesOrRaws - The parameter `keysNodesEntriesOrRaws` is an
* iterable that can contain keys, nodes, entries, or raw elements. It is used to initialize the
* TreeMultiMap with initial data.
* @param [options] - The `options` parameter is an optional object that can be used to customize the
* behavior of the `TreeMultiMap` constructor. It can include properties such as `compareKeys` and
* `compareValues`, which are functions used to compare keys and values respectively.
*/
constructor(
keysOrNodesOrEntriesOrRaws: Iterable<BTNKeyOrNodeOrEntry<K, V, NODE>> = [],
options?: TreeMultiMapOptions<K, V, R>
) {
constructor(keysNodesEntriesOrRaws: Iterable<BTNRep<K, V, NODE>> = [], options?: TreeMultiMapOptions<K, V, R>) {
super([], options);
if (keysOrNodesOrEntriesOrRaws) this.addMany(keysOrNodesOrEntriesOrRaws);
if (keysNodesEntriesOrRaws) this.addMany(keysNodesEntriesOrRaws);
}
protected _count = 0;
@ -142,6 +138,7 @@ export class TreeMultiMap<
override createTree(options?: TreeMultiMapOptions<K, V, R>): TREE {
return new TreeMultiMap<K, V, R, NODE, TREE>([], {
iterationType: this.iterationType,
isMapMode: this._isMapMode,
comparator: this._comparator,
toEntryFn: this._toEntryFn,
...options
@ -149,10 +146,10 @@ export class TreeMultiMap<
}
/**
* The function `keyValueOrEntryOrRawElementToNode` takes in a key, value, and count and returns a
* The function `keyValueNodeEntryRawToNodeAndValue` takes in a key, value, and count and returns a
* node based on the input.
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R} keyOrNodeOrEntryOrRaw - The parameter
* `keyOrNodeOrEntryOrRaw` can be of type `R` or `BTNKeyOrNodeOrEntry<K, V, NODE>`.
* @param {BTNRep<K, V, NODE> | R} keyNodeEntryOrRaw - The parameter
* `keyNodeEntryOrRaw` can be of type `R` or `BTNRep<K, V, NODE>`.
* @param {V} [value] - The `value` parameter is an optional value that represents the value
* associated with the key in the node. It is used when creating a new node or updating the value of
* an existing node.
@ -160,40 +157,42 @@ export class TreeMultiMap<
* times the key-value pair should be added to the data structure. If not provided, it defaults to 1.
* @returns either a NODE object or undefined.
*/
override keyValueOrEntryOrRawElementToNode(
keyOrNodeOrEntryOrRaw: BTNKeyOrNodeOrEntry<K, V, NODE> | R,
override keyValueNodeEntryRawToNodeAndValue(
keyNodeEntryOrRaw: BTNRep<K, V, NODE> | R,
value?: V,
count = 1
): NODE | undefined {
if (keyOrNodeOrEntryOrRaw === undefined || keyOrNodeOrEntryOrRaw === null) return;
): [NODE | undefined, V | undefined] {
if (keyNodeEntryOrRaw === undefined || keyNodeEntryOrRaw === null) return [undefined, undefined];
if (this.isNode(keyOrNodeOrEntryOrRaw)) return keyOrNodeOrEntryOrRaw;
if (this.isNode(keyNodeEntryOrRaw)) return [keyNodeEntryOrRaw, value];
if (this.isEntry(keyOrNodeOrEntryOrRaw)) {
const [key, entryValue] = keyOrNodeOrEntryOrRaw;
if (key === undefined || key === null) return;
if (this.isKey(key)) return this.createNode(key, value ?? entryValue, 'BLACK', count);
if (this.isEntry(keyNodeEntryOrRaw)) {
const [key, entryValue] = keyNodeEntryOrRaw;
if (key === undefined || key === null) return [undefined, undefined];
const finalValue = value ?? entryValue;
if (this.isKey(key)) return [this.createNode(key, finalValue, 'BLACK', count), finalValue];
}
if (this._toEntryFn) {
const [key, entryValue] = this._toEntryFn(keyOrNodeOrEntryOrRaw as R);
if (this.isKey(key)) return this.createNode(key, value ?? entryValue, 'BLACK', count);
const [key, entryValue] = this._toEntryFn(keyNodeEntryOrRaw as R);
const finalValue = value ?? entryValue;
if (this.isKey(key)) return [this.createNode(key, finalValue, 'BLACK', count), finalValue];
}
if (this.isKey(keyOrNodeOrEntryOrRaw)) return this.createNode(keyOrNodeOrEntryOrRaw, value, 'BLACK', count);
if (this.isKey(keyNodeEntryOrRaw)) return [this.createNode(keyNodeEntryOrRaw, value, 'BLACK', count), value];
return;
return [undefined, undefined];
}
/**
* The function checks if the input is an instance of the TreeMultiMapNode class.
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R} keyOrNodeOrEntryOrRaw - The parameter
* `keyOrNodeOrEntryOrRaw` can be of type `R` or `BTNKeyOrNodeOrEntry<K, V, NODE>`.
* @returns a boolean value indicating whether the input parameter `keyOrNodeOrEntryOrRaw` is
* @param {BTNRep<K, V, NODE> | R} keyNodeEntryOrRaw - The parameter
* `keyNodeEntryOrRaw` can be of type `R` or `BTNRep<K, V, NODE>`.
* @returns a boolean value indicating whether the input parameter `keyNodeEntryOrRaw` is
* an instance of the `TreeMultiMapNode` class.
*/
override isNode(keyOrNodeOrEntryOrRaw: BTNKeyOrNodeOrEntry<K, V, NODE> | R): keyOrNodeOrEntryOrRaw is NODE {
return keyOrNodeOrEntryOrRaw instanceof TreeMultiMapNode;
override isNode(keyNodeEntryOrRaw: BTNRep<K, V, NODE> | R): keyNodeEntryOrRaw is NODE {
return keyNodeEntryOrRaw instanceof TreeMultiMapNode;
}
/**
@ -202,8 +201,8 @@ export class TreeMultiMap<
*
* The function overrides the add method of a class and adds a new node to a data structure, updating
* the count and returning a boolean indicating success.
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R} keyOrNodeOrEntryOrRaw - The
* `keyOrNodeOrEntryOrRaw` parameter can accept one of the following types:
* @param {BTNRep<K, V, NODE> | R} keyNodeEntryOrRaw - The
* `keyNodeEntryOrRaw` parameter can accept one of the following types:
* @param {V} [value] - The `value` parameter represents the value associated with the key in the
* data structure. It is an optional parameter, so it can be omitted if not needed.
* @param [count=1] - The `count` parameter represents the number of times the key-value pair should
@ -212,10 +211,10 @@ export class TreeMultiMap<
* @returns The method is returning a boolean value. It returns true if the addition of the new node
* was successful, and false otherwise.
*/
override add(keyOrNodeOrEntryOrRaw: BTNKeyOrNodeOrEntry<K, V, NODE> | R, value?: V, count = 1): boolean {
const newNode = this.keyValueOrEntryOrRawElementToNode(keyOrNodeOrEntryOrRaw, value, count);
override add(keyNodeEntryOrRaw: BTNRep<K, V, NODE> | R, value?: V, count = 1): boolean {
const [newNode, newValue] = this.keyValueNodeEntryRawToNodeAndValue(keyNodeEntryOrRaw, value, count);
const orgCount = newNode?.count || 0;
const isSuccessAdded = super.add(newNode);
const isSuccessAdded = super.add(newNode, newValue);
if (isSuccessAdded) {
this._count += orgCount;
@ -231,7 +230,7 @@ export class TreeMultiMap<
*
* The function `delete` in TypeScript overrides the deletion operation in a binary tree data
* structure, handling cases where nodes have children and maintaining balance in the tree.
* @param {BTNKeyOrNodeOrEntry<K, V, NODE> | R} keyOrNodeOrEntryOrRaw - The `predicate`
* @param {BTNRep<K, V, NODE> | R} keyNodeEntryOrRaw - The `predicate`
* parameter in the `delete` method is used to specify the condition or key based on which a node
* should be deleted from the binary tree. It can be a key, a node, or an entry.
* @param [ignoreCount=false] - The `ignoreCount` parameter in the `override delete` method is a
@ -240,20 +239,14 @@ export class TreeMultiMap<
* `ignoreCount` is `false
* @returns The `override delete` method returns an array of `BinaryTreeDeleteResult<NODE>` objects.
*/
override delete(
keyOrNodeOrEntryOrRaw: BTNKeyOrNodeOrEntry<K, V, NODE> | R,
ignoreCount = false
): BinaryTreeDeleteResult<NODE>[] {
if (keyOrNodeOrEntryOrRaw === null) return [];
override delete(keyNodeEntryOrRaw: BTNRep<K, V, NODE> | R, ignoreCount = false): BinaryTreeDeleteResult<NODE>[] {
if (keyNodeEntryOrRaw === null) return [];
const results: BinaryTreeDeleteResult<NODE>[] = [];
let nodeToDelete: OptBSTN<NODE>;
if (this._isPredicated(keyOrNodeOrEntryOrRaw)) nodeToDelete = this.getNode(keyOrNodeOrEntryOrRaw);
else
nodeToDelete = this.isRealNode(keyOrNodeOrEntryOrRaw)
? keyOrNodeOrEntryOrRaw
: this.getNode(keyOrNodeOrEntryOrRaw);
let nodeToDelete: OptNode<NODE>;
if (this._isPredicate(keyNodeEntryOrRaw)) nodeToDelete = this.getNode(keyNodeEntryOrRaw);
else nodeToDelete = this.isRealNode(keyNodeEntryOrRaw) ? keyNodeEntryOrRaw : this.getNode(keyNodeEntryOrRaw);
if (!nodeToDelete) {
return results;
@ -374,7 +367,8 @@ export class TreeMultiMap<
if (l > r) return;
const m = l + Math.floor((r - l) / 2);
const midNode = sorted[m];
this.add(midNode.key, midNode.value, midNode.count);
if (this._isMapMode) this.add(midNode.key, undefined, midNode.count);
else this.add(midNode.key, midNode.value, midNode.count);
buildBalanceBST(l, m - 1);
buildBalanceBST(m + 1, r);
};
@ -390,7 +384,8 @@ export class TreeMultiMap<
if (l <= r) {
const m = l + Math.floor((r - l) / 2);
const midNode = sorted[m];
this.add(midNode.key, midNode.value, midNode.count);
if (this._isMapMode) this.add(midNode.key, undefined, midNode.count);
else this.add(midNode.key, midNode.value, midNode.count);
stack.push([m + 1, r]);
stack.push([l, m - 1]);
}
@ -409,7 +404,8 @@ export class TreeMultiMap<
*/
override clone(): TREE {
const cloned = this.createTree();
this.bfs(node => cloned.add(node.key, node.value, node.count));
this.bfs(node => cloned.add(node.key, undefined, node.count));
if (this._isMapMode) cloned._store = this._store;
return cloned;
}
@ -419,17 +415,17 @@ export class TreeMultiMap<
*
* The `_swapProperties` function swaps the properties (key, value, count, color) between two nodes
* in a binary search tree.
* @param {R | BSTNKeyOrNode<K, NODE>} srcNode - The `srcNode` parameter represents the source node
* @param {R | BSTNOptKeyOrNode<K, NODE>} srcNode - The `srcNode` parameter represents the source node
* that will be swapped with the `destNode`. It can be either an instance of the `R` class or an
* instance of the `BSTNKeyOrNode<K, NODE>` class.
* @param {R | BSTNKeyOrNode<K, NODE>} destNode - The `destNode` parameter represents the destination
* instance of the `BSTNOptKeyOrNode<K, NODE>` class.
* @param {R | BSTNOptKeyOrNode<K, NODE>} destNode - The `destNode` parameter represents the destination
* node where the properties will be swapped with the source node.
* @returns The method is returning the `destNode` after swapping its properties with the `srcNode`.
* If either `srcNode` or `destNode` is undefined, it returns undefined.
*/
protected override _swapProperties(
srcNode: R | BSTNKeyOrNode<K, NODE>,
destNode: R | BSTNKeyOrNode<K, NODE>
srcNode: R | BSTNOptKeyOrNode<K, NODE>,
destNode: R | BSTNOptKeyOrNode<K, NODE>
): NODE | undefined {
srcNode = this.ensureNode(srcNode);
destNode = this.ensureNode(destNode);
@ -440,12 +436,12 @@ export class TreeMultiMap<
tempNode.color = color;
destNode.key = srcNode.key;
destNode.value = srcNode.value;
if (!this._isMapMode) destNode.value = srcNode.value;
destNode.count = srcNode.count;
destNode.color = srcNode.color;
srcNode.key = tempNode.key;
srcNode.value = tempNode.value;
if (!this._isMapMode) srcNode.value = tempNode.value;
srcNode.count = tempNode.count;
srcNode.color = tempNode.color;
}

View file

@ -266,9 +266,9 @@ export class Trie<R = any> extends IterableElementBase<string, R, Trie<R>> {
*
*/
getHeight(): number {
const beginRoot = this.root;
const startNode = this.root;
let maxDepth = 0;
if (beginRoot) {
if (startNode) {
const bfs = (node: TrieNode, level: number) => {
if (level > maxDepth) {
maxDepth = level;
@ -280,7 +280,7 @@ export class Trie<R = any> extends IterableElementBase<string, R, Trie<R>> {
}
}
};
bfs(beginRoot, 0);
bfs(startNode, 0);
}
return maxDepth;
}

View file

@ -4,14 +4,14 @@ import type {
BinaryTreeNested,
BinaryTreeNodeNested,
BinaryTreeOptions,
BTNKeyOrNodeOrEntry,
BTNPredicate
BTNRep,
NodePredicate
} from '../types';
export interface IBinaryTree<
K = any,
V = any,
R = [K, V],
R = object,
NODE extends BinaryTreeNode<K, V, NODE> = BinaryTreeNodeNested<K, V>,
TREE extends BinaryTree<K, V, R, NODE, TREE> = BinaryTreeNested<K, V, R, NODE>
> {
@ -19,9 +19,9 @@ export interface IBinaryTree<
createTree(options?: Partial<BinaryTreeOptions<K, V, R>>): TREE;
add(keyOrNodeOrEntryOrRawElement: BTNKeyOrNodeOrEntry<K, V, NODE>, value?: V, count?: number): boolean;
add(keyOrNodeOrEntryOrRawElement: BTNRep<K, V, NODE>, value?: V, count?: number): boolean;
addMany(nodes: Iterable<BTNKeyOrNodeOrEntry<K, V, NODE>>, values?: Iterable<V | undefined>): boolean[];
addMany(nodes: Iterable<BTNRep<K, V, NODE>>, values?: Iterable<V | undefined>): boolean[];
delete(predicate: R | BTNKeyOrNodeOrEntry<K, V, NODE> | BTNPredicate<NODE>): BinaryTreeDeleteResult<NODE>[];
delete(predicate: R | BTNRep<K, V, NODE> | NodePredicate<NODE>): BinaryTreeDeleteResult<NODE>[];
}

View file

@ -6,31 +6,30 @@ export type BinaryTreeNodeNested<K, V> = BinaryTreeNode<K, V, BinaryTreeNode<K,
export type BinaryTreeNested<K, V, R, NODE extends BinaryTreeNode<K, V, NODE>> = BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, BinaryTree<K, V, R, NODE, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type ToEntryFn<K, V, R> = (rawElement: R) => BTNEntry<K, V>;
export type BinaryTreeOptions<K, V, R> = {
iterationType?: IterationType;
toEntryFn?: (rawElement: R) => BTNEntry<K, V>;
iterationType?: IterationType;
toEntryFn?: ToEntryFn<K, V, R>;
isMapMode?: boolean;
}
export type BinaryTreePrintOptions = { isShowUndefined?: boolean; isShowNull?: boolean; isShowRedBlackNIL?: boolean };
export type OptBTNOrNull<NODE> = NODE | null | undefined;
export type OptNodeOrNull<NODE> = NODE | null | undefined;
export type OptBTNKeyOrNull<K> = K | null | undefined;
export type BTNOptKeyOrNull<K> = K | null | undefined;
export type BTNEntry<K, V> = [OptBTNKeyOrNull<K>, OptValue<V>];
export type BTNEntry<K, V> = [BTNOptKeyOrNull<K>, OptValue<V>];
export type BTNKeyOrNode<K, NODE> = OptBTNKeyOrNull<K> | NODE;
export type BTNOptKeyNodeOrNull<K, NODE> = BTNOptKeyOrNull<K> | NODE;
export type BTNKeyOrNodeOrEntry<K, V, NODE> = BTNEntry<K, V> | BTNKeyOrNode<K, NODE>;
export type BTNRep<K, V, NODE> = BTNEntry<K, V> | BTNOptKeyNodeOrNull<K, NODE>;
export type BTNPureKeyOrNode<K, NODE> = K | NODE;
export type BinaryTreeDeleteResult<NODE> = { deleted: OptNodeOrNull<NODE>; needBalanced: OptNodeOrNull<NODE> };
export type BTNPureKeyOrNodeOrEntry<K, V, NODE> = [K, OptValue<V>] | BTNPureKeyOrNode<K, NODE>;
export type NodeCallback<NODE, D = any> = (node: NODE) => D;
export type BinaryTreeDeleteResult<NODE> = { deleted: OptBTNOrNull<NODE>; needBalanced: OptBTNOrNull<NODE> };
export type NodePredicate<NODE> = (node: NODE) => boolean;
export type BTNCallback<NODE, D = any> = (node: NODE) => D;
export type BTNPredicate<NODE> = (node: NODE) => boolean;
export type DFSStackItem<NODE> = { opt: DFSOperation; node: OptBTNOrNull<NODE> }
export type DFSStackItem<NODE> = { opt: DFSOperation; node: OptNodeOrNull<NODE> }

View file

@ -7,12 +7,12 @@ export type BSTNodeNested<K, V> = BSTNode<K, V, BSTNode<K, V, BSTNode<K, V, BSTN
export type BSTNested<K, V, R, NODE extends BSTNode<K, V, NODE>> = BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, BST<K, V, R, NODE, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type BSTOptions<K, V, R> = BinaryTreeOptions<K, V, R> & {
comparator?: Comparator<K>
comparator?: Comparator<K>
}
export type OptBSTNKey<K> = K | undefined;
export type BSTNOptKey<K> = K | undefined;
export type OptBSTN<NODE> = NODE | undefined;
export type OptNode<NODE> = NODE | undefined;
export type BSTNKeyOrNode<K, NODE> = OptBSTNKey<K> | NODE;
export type BSTNOptKeyOrNode<K, NODE> = BSTNOptKey<K> | NODE;

View file

@ -3,7 +3,7 @@ import * as Benchmark from 'benchmark';
import { getRandomIntArray, magnitude } from '../../../utils';
const suite = new Benchmark.Suite();
const avlTree = new AVLTree<number>();
const avlTree = new AVLTree<number>([], { isMapMode: true });
const { HUNDRED_THOUSAND } = magnitude;
const randomArray = getRandomIntArray(HUNDRED_THOUSAND, 0, HUNDRED_THOUSAND - 1, true);

View file

@ -3,8 +3,8 @@ import * as Benchmark from 'benchmark';
import { getRandomIntArray, magnitude } from '../../../utils';
const suite = new Benchmark.Suite();
const rbTree = new RedBlackTree();
const avlTree = new AVLTree();
const rbTree = new RedBlackTree<number>([], { isMapMode: true });
const avlTree = new AVLTree<number>([], { isMapMode: true });
const { TEN_THOUSAND } = magnitude;
const arr = getRandomIntArray(TEN_THOUSAND, 0, TEN_THOUSAND - 1, true);

View file

@ -3,7 +3,7 @@ import * as Benchmark from 'benchmark';
import { getRandomIntArray, magnitude } from '../../../utils';
const suite = new Benchmark.Suite();
const biTree = new BinaryTree<number>();
const biTree = new BinaryTree<number>([], { isMapMode: true });
const { THOUSAND } = magnitude;
const arr = getRandomIntArray(THOUSAND, 0, THOUSAND, true);

View file

@ -3,7 +3,7 @@ import * as Benchmark from 'benchmark';
import { getRandomIntArray, magnitude } from '../../../utils';
const suite = new Benchmark.Suite();
const bst = new BST<number>();
const bst = new BST<number>([], { isMapMode: true });
const { TEN_THOUSAND } = magnitude;
const arr = getRandomIntArray(TEN_THOUSAND, 0, TEN_THOUSAND, true);

View file

@ -5,7 +5,7 @@ import { OrderedMap } from 'js-sdsl';
import { isCompetitor } from '../../../config';
const suite = new Benchmark.Suite();
const rbTree = new RedBlackTree();
const rbTree = new RedBlackTree<number>([], { isMapMode: true });
const { HUNDRED_THOUSAND } = magnitude;
const randomArray = getRandomIntArray(HUNDRED_THOUSAND, 0, HUNDRED_THOUSAND - 1, true);
const cOrderedMap = new OrderedMap<number, number>();

View file

@ -678,7 +678,7 @@ describe('AVLTreeMultiMap iterative methods test', () => {
expect(treeMM.count).toBe(21);
const cloned = treeMM.clone();
expect(cloned.root?.left?.key).toBe(1);
expect(cloned.root?.right?.value).toBe('c');
expect(cloned.get(cloned.root?.right)).toBe('c');
});
it('should keys', () => {
@ -761,3 +761,115 @@ describe('AVLTree toEntryFn', () => {
expect(tree.dfs(node => node.key, 'IN', tree.root, 'RECURSIVE')).toEqual(expected);
});
});
describe('AVLTreeMultiMap map mode count', () => {
let tm: AVLTreeMultiMap<number>;
beforeEach(() => {
tm = new AVLTreeMultiMap<number>([], { isMapMode: true });
});
it('Should added isolated node count ', () => {
tm.addMany([
[1, 1],
[2, 2],
[3, 3],
[4, 4],
[5, 5]
]);
const newNode = new AVLTreeMultiMapNode(3, undefined, 10);
tm.add(newNode, 33);
expect(tm.count).toBe(15);
});
});
describe('AVLTreeMultiMap map mode operations test1', () => {
it('should perform various operations on a Binary Search Tree with numeric values1', () => {
const treeMultimap = new AVLTreeMultiMap<number>([], { isMapMode: true });
expect(treeMultimap instanceof AVLTreeMultiMap);
treeMultimap.add([11, 11]);
treeMultimap.add([3, 3]);
const idAndValues: [number, number][] = [
[11, 11],
[3, 3],
[15, 15],
[1, 1],
[8, 8],
[13, 13],
[16, 16],
[2, 2],
[6, 6],
[9, 9],
[12, 12],
[14, 14],
[4, 4],
[7, 7],
[10, 10],
[5, 5]
];
treeMultimap.addMany(idAndValues);
expect(treeMultimap.root instanceof AVLTreeMultiMapNode);
if (treeMultimap.root) expect(treeMultimap.root.key == 11);
expect(treeMultimap.size).toBe(16);
expect(treeMultimap.count).toBe(18);
expect(treeMultimap.has(6));
expect(treeMultimap.getHeight(6)).toBe(4);
expect(treeMultimap.getDepth(6)).toBe(0);
const nodeId10 = treeMultimap.getNode(10);
expect(nodeId10?.key).toBe(10);
const nodeVal9 = treeMultimap.getNode(node => node.key === 9);
expect(nodeVal9?.key).toBe(9);
});
});
describe('AVLTreeMultiMap map mode operations test recursively1', () => {
it('should perform various operations on a Binary Search Tree with numeric values1', () => {
const treeMultimap = new AVLTreeMultiMap<number>([], {
iterationType: 'RECURSIVE',
isMapMode: true
});
expect(treeMultimap instanceof AVLTreeMultiMap);
treeMultimap.add([11, 11]);
treeMultimap.add([3, 3]);
const idAndValues: [number, number][] = [
[11, 11],
[3, 3],
[15, 15],
[1, 1],
[8, 8],
[13, 13],
[16, 16],
[2, 2],
[6, 6],
[9, 9],
[12, 12],
[14, 14],
[4, 4],
[7, 7],
[10, 10],
[5, 5]
];
treeMultimap.addMany(idAndValues);
expect(treeMultimap.root).toBeInstanceOf(AVLTreeMultiMapNode);
if (treeMultimap.root) expect(treeMultimap.root.key).toBe(6);
expect(treeMultimap.size).toBe(16);
expect(treeMultimap.count).toBe(18);
expect(treeMultimap.has(6));
expect(treeMultimap.getHeight(6)).toBe(4);
expect(treeMultimap.getDepth(6)).toBe(0);
const nodeId10 = treeMultimap.getNode(10);
expect(nodeId10?.key).toBe(10);
const nodeVal9 = treeMultimap.getNode(node => node.key === 9);
expect(nodeVal9?.key).toBe(9);
});
});

View file

@ -33,7 +33,6 @@ describe('AVL Tree Test', () => {
// node15 has type problem. After the uniform design, the generics of containers (DirectedGraph, BST) are based on the type of value. However, this design has a drawback: when I attempt to inherit from the Vertex or BSTNode classes, the types of the results obtained by all methods are those of the parent class.
expect(node15?.value).toBe(15);
const dfs = tree.dfs(node => node, 'IN');
expect(dfs[0].key).toBe(1);
expect(dfs[dfs.length - 1].key).toBe(16);
@ -437,3 +436,90 @@ describe('AVLTree iterative methods test', () => {
expect(leaves).toEqual([1, 3]);
});
});
describe('AVL Tree map mode', () => {
it('should perform various operations on a AVL Tree', () => {
const arr = [11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5];
const tree = new AVLTree<number>([], { isMapMode: true });
for (const i of arr) tree.add([i, i]);
tree.add(null);
const node6 = tree.getNode(6);
expect(node6 && tree.getHeight(node6)).toBe(3);
expect(node6 && tree.getDepth(node6)).toBe(1);
const getNodeById = tree.getNode(10);
expect(getNodeById?.key).toBe(10);
const getMinNodeByRoot = tree.getLeftMost();
expect(getMinNodeByRoot).toBe(1);
const node15 = tree.getNode(15);
const getMinNodeBySpecificNode = node15 && tree.getLeftMost(node => node, node15);
expect(getMinNodeBySpecificNode?.key).toBe(12);
let subTreeSum = 0;
if (node15) tree.dfs(node => (subTreeSum += node.key), 'PRE', node15);
expect(subTreeSum).toBe(70);
let lesserSum = 0;
tree.lesserOrGreaterTraverse(node => (lesserSum += node.key), -1, 10);
expect(lesserSum).toBe(45);
// node15 has type problem. After the uniform design, the generics of containers (DirectedGraph, BST) are based on the type of value. However, this design has a drawback: when I attempt to inherit from the Vertex or BSTNode classes, the types of the results obtained by all methods are those of the parent class.
expect(tree.get(node15)).toBe(15);
});
});
describe('AVL Tree map mode test recursively', () => {
it('should perform various operations on a AVL Tree', () => {
const arr = [11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5];
const tree = new AVLTree<number>([], { iterationType: 'RECURSIVE', isMapMode: true });
for (const i of arr) tree.add([i, i]);
const node6 = tree.getNode(6);
expect(node6 && tree.getHeight(node6)).toBe(3);
expect(node6 && tree.getDepth(node6)).toBe(1);
const getNodeById = tree.getNode(10);
expect(getNodeById?.key).toBe(10);
const getMinNodeByRoot = tree.getLeftMost();
expect(getMinNodeByRoot).toBe(1);
const node15 = tree.getNode(15);
const getMinNodeBySpecificNode = node15 && tree.getLeftMost(node => node, node15);
expect(getMinNodeBySpecificNode?.key).toBe(12);
let subTreeSum = 0;
if (node15) tree.dfs(node => (subTreeSum += node.key), 'PRE', node15);
expect(subTreeSum).toBe(70);
let lesserSum = 0;
tree.lesserOrGreaterTraverse(node => (lesserSum += node.key), -1, 10);
expect(lesserSum).toBe(45);
// node15 has type problem. After the uniform design, the generics of containers (DirectedGraph, BST) are based on the type of value. However, this design has a drawback: when I attempt to inherit from the Vertex or BSTNode classes, the types of the results obtained by all methods are those of the parent class.
expect(tree.get(node15)).toBe(15);
});
});
describe('AVLTree iterative methods map mode', () => {
let avl: AVLTree<number, string>;
beforeEach(() => {
avl = new AVLTree<number, string>([], { isMapMode: true });
avl.add([1, 'a']);
avl.add([2, 'b']);
avl.add([3, 'c']);
});
it('should clone work well', () => {
const cloned = avl.clone();
expect(cloned.root?.left?.key).toBe(1);
expect(cloned.get(cloned.root?.right?.key)).toBe('c');
});
});

View file

@ -20,6 +20,8 @@ describe('BinaryTreeNode', () => {
it('should set and get the value correctly', () => {
const node: BinaryTreeNode<number> = new BinaryTreeNode<number>(1, 42);
expect(node.key).toBe(1);
expect(node.value).toBe(42);
node.value = 55;
@ -319,26 +321,28 @@ describe('BinaryTree', () => {
it('should isSubtreeBST', () => {
expect(tree.toVisual()).toBe('');
tree.addMany([4, 2, 6, 1, 3, 5, 7, 4]);
expect(tree.toVisual()).toBe('N for null\n' +
' ___4___ \n' +
' / \\ \n' +
' _2_ _6_ \n' +
' / \\ / \\ \n' +
' 1 3 5 7 \n' +
' \n');
expect(tree.toVisual()).toBe(
'N for null\n' +
' ___4___ \n' +
' / \\ \n' +
' _2_ _6_ \n' +
' / \\ / \\ \n' +
' 1 3 5 7 \n' +
' \n'
);
const visualized = tree.toVisual(undefined, { isShowUndefined: true, isShowNull: true, isShowRedBlackNIL: true });
expect(visualized).toBe(
'U for undefined\n' +
'N for null\n' +
'S for Sentinel Node(NIL)\n' +
' _______4_______ \n' +
' / \\ \n' +
' ___2___ ___6___ \n' +
' / \\ / \\ \n' +
' _1_ _3_ _5_ _7_ \n' +
' / \\ / \\ / \\ / \\ \n' +
' U U U U U U U U \n' +
' \n'
'N for null\n' +
'S for Sentinel Node(NIL)\n' +
' _______4_______ \n' +
' / \\ \n' +
' ___2___ ___6___ \n' +
' / \\ / \\ \n' +
' _1_ _3_ _5_ _7_ \n' +
' / \\ / \\ / \\ / \\ \n' +
' U U U U U U U U \n' +
' \n'
);
expect(tree.isBST(tree.getNode(4), 'RECURSIVE')).toBe(true);
@ -729,34 +733,40 @@ describe('BinaryTree', () => {
]);
});
it('should keyValueOrEntryOrRawElementToNode', () => {
it('should keyValueNodeEntryRawToNodeAndValue', () => {
const tree = new BinaryTree<number>();
const node0 = tree.keyValueOrEntryOrRawElementToNode(0);
expect(node0).toEqual({
_left: undefined,
_right: undefined,
key: 0,
parent: undefined,
value: undefined
});
const node0 = tree.keyValueNodeEntryRawToNodeAndValue(0);
expect(node0).toEqual([
{
_left: undefined,
_right: undefined,
key: 0,
parent: undefined,
value: undefined
},
undefined
]);
const nodeUndefined = tree.keyValueOrEntryOrRawElementToNode(undefined);
expect(nodeUndefined).toBe(undefined);
const nodeUndefined = tree.keyValueNodeEntryRawToNodeAndValue(undefined);
expect(nodeUndefined).toEqual([undefined, undefined]);
const nodeNull = tree.keyValueOrEntryOrRawElementToNode(null);
expect(nodeNull).toBe(null);
const nodeNull = tree.keyValueNodeEntryRawToNodeAndValue(null);
expect(nodeNull).toEqual([null, undefined]);
const nodeWithSeparateValue = tree.keyValueOrEntryOrRawElementToNode(7, 77);
expect(nodeWithSeparateValue?.value).toBe(77);
const [, nodeWithSeparateValue] = tree.keyValueNodeEntryRawToNodeAndValue(7, 77);
expect(nodeWithSeparateValue).toBe(77);
expect(tree.keyValueOrEntryOrRawElementToNode([undefined, 2])).toBe(undefined);
expect(tree.keyValueNodeEntryRawToNodeAndValue([undefined, 2])).toEqual([undefined, undefined]);
expect(tree.keyValueOrEntryOrRawElementToNode(Symbol('test') as unknown as number)).toBe(undefined);
expect(tree.keyValueNodeEntryRawToNodeAndValue(Symbol('test') as unknown as number)).toEqual([
undefined,
undefined
]);
const bTree = new BinaryTree<number, number, { obj: { id: number } }>([], {
toEntryFn: (ele: { obj: { id: number } }) => [Symbol('test') as unknown as number, ele.obj.id]
});
expect(bTree.keyValueOrEntryOrRawElementToNode({ obj: { id: 1 } })).toBe(undefined);
expect(bTree.keyValueNodeEntryRawToNodeAndValue({ obj: { id: 1 } })).toEqual([undefined, undefined]);
});
});
@ -1150,17 +1160,21 @@ describe('BinaryTree', () => {
tree.add([2, 'B']);
tree.add([null, 'null']);
const nodes = tree.getNodes(node => node.value === 'B');
const nodes = tree.isMapMode ? tree.getNodes(node => node.key === 2) : tree.getNodes(node => node.value === 'B');
expect(nodes.length).toBe(1);
expect(nodes[0].key).toBe(2);
const nodesRec = tree.getNodes(node => node.value === 'B', false, tree.root, 'RECURSIVE');
const nodesRec = tree.isMapMode
? tree.getNodes(node => node.key === 2, false, tree.root, 'RECURSIVE')
: tree.getNodes(node => node.value === 'B', false, tree.root, 'RECURSIVE');
expect(nodesRec.length).toBe(1);
expect(nodesRec[0].key).toBe(2);
const nodesItr = tree.getNodes(node => node.value === 'B', false, tree.root, 'ITERATIVE');
const nodesItr = tree.isMapMode
? tree.getNodes(node => node.key === 2, false, tree.root, 'ITERATIVE')
: tree.getNodes(node => node.value === 'B', false, tree.root, 'ITERATIVE');
expect(nodesItr.length).toBe(1);
expect(nodesItr[0].key).toBe(2);
@ -1206,6 +1220,98 @@ describe('BinaryTree', () => {
});
});
describe('BinaryTree map mode', () => {
let tree: BinaryTree<number, string>;
beforeEach(() => {
tree = new BinaryTree<number, string>([], {
iterationType: 'RECURSIVE',
isMapMode: true
});
});
afterEach(() => {
tree.clear();
});
it('should add and find nodes', () => {
tree.add([1, 1]);
tree.add(undefined);
tree.add([2, 2]);
tree.add([3, 3]);
expect(tree.has(1)).toBe(true);
expect(tree.has(2)).toBe(true);
expect(tree.has(3)).toBe(true);
expect(tree.has(4)).toBe(false);
const node4 = tree.getNode(4);
expect(tree.has(node4)).toBe(false);
expect(tree.has(node => node === node4)).toBe(false);
if (tree.isMapMode) expect(tree.has(node => node.key?.toString() === '3')).toBe(true);
else expect(tree.has(node => node.value?.toString() === '3')).toBe(true);
});
it('should isSubtreeBST', () => {
tree.addMany([
new BinaryTreeNode(4),
new BinaryTreeNode(2),
new BinaryTreeNode(6),
new BinaryTreeNode(1),
new BinaryTreeNode(3),
new BinaryTreeNode(5),
new BinaryTreeNode(7),
new BinaryTreeNode(4)
]);
expect(tree.isBST(tree.getNode(4), 'RECURSIVE')).toBe(true);
expect(tree.isBST(tree.getNode(4), 'ITERATIVE')).toBe(true);
});
it('should get nodes by key', () => {
tree.add([5, 'A']);
tree.add([3, 'B']);
tree.add([7, 'C']);
const nodeA = tree.getNode(5);
const nodeB = tree.getNode(3);
expect(nodeA?.key).toBe(5);
expect(tree.get(nodeA)).toBe('A');
expect(nodeB?.key).toBe(3);
expect(tree.get(nodeB)).toBe('B');
});
it('should get nodes by a custom callback', () => {
tree.add([5, 'E']);
tree.add([4, 'D']);
tree.add([3, 'C']);
tree.add([7, 'G']);
tree.add([null, 'null']);
tree.add([1, 'A']);
tree.add([6, 'F']);
tree.add([null, 'null']);
tree.add([2, 'B']);
tree.add([null, 'null']);
const nodes = tree.getNodes(node => node.key === 2);
expect(nodes.length).toBe(1);
expect(nodes[0].key).toBe(2);
const nodesRec = tree.getNodes(node => node.key === 2, false, tree.root, 'RECURSIVE');
expect(nodesRec.length).toBe(1);
expect(nodesRec[0].key).toBe(2);
const nodesItr = tree.getNodes(node => node.key === 2, false, tree.root, 'ITERATIVE');
expect(nodesItr.length).toBe(1);
expect(nodesItr[0].key).toBe(2);
expect(nodesItr).toEqual(nodesRec);
});
});
describe('BinaryTree iterative methods test', () => {
let binaryTree: BinaryTree<number, string>;
beforeEach(() => {
@ -1273,7 +1379,8 @@ describe('BinaryTree iterative methods test', () => {
it('should clone work well', () => {
const cloned = binaryTree.clone();
expect(cloned.root?.left?.key).toBe(2);
expect(cloned.root?.right?.value).toBe('c');
if (cloned.isMapMode) expect(cloned.get(cloned.root?.right)).toBe('c');
else expect(cloned.root?.right?.value).toBe('c');
});
it('should keys', () => {
@ -1315,3 +1422,19 @@ describe('BinaryTree iterative methods test', () => {
]);
});
});
describe('BinaryTree map mode iterative methods test', () => {
let binaryTree: BinaryTree<number, string>;
beforeEach(() => {
binaryTree = new BinaryTree<number, string>([], { isMapMode: true });
binaryTree.add([1, 'a']);
binaryTree.add(2, 'b');
binaryTree.add([3, 'c']);
});
it('should clone work well', () => {
const cloned = binaryTree.clone();
expect(cloned.root?.left?.key).toBe(2);
expect(cloned.get(cloned.root?.right)).toBe('c');
});
});

View file

@ -1,5 +1,5 @@
import { BinaryTreeNode, BST, BSTNode } from '../../../../src';
import { isDebugTest, SYSTEM_MAX_CALL_STACK, isTestStackOverflow } from '../../../config';
import { isDebugTest, isTestStackOverflow, SYSTEM_MAX_CALL_STACK } from '../../../config';
const isDebug = isDebugTest;
@ -450,22 +450,25 @@ describe('BST operations test', () => {
expect(bfsNodes[2].key).toBe(16);
});
it('should keyValueOrEntryOrRawElementToNode', () => {
it('should keyValueNodeEntryRawToNodeAndValue', () => {
const bst = new BST<number>();
const node0 = bst.keyValueOrEntryOrRawElementToNode(0);
expect(node0).toEqual({
_left: undefined,
_right: undefined,
key: 0,
parent: undefined,
value: undefined
});
const node0 = bst.keyValueNodeEntryRawToNodeAndValue(0);
expect(node0).toEqual([
{
_left: undefined,
_right: undefined,
key: 0,
parent: undefined,
value: undefined
},
undefined
]);
const nodeUndefined = bst.keyValueOrEntryOrRawElementToNode(undefined);
expect(nodeUndefined).toBe(undefined);
const nodeUndefined = bst.keyValueNodeEntryRawToNodeAndValue(undefined);
expect(nodeUndefined).toEqual([undefined, undefined]);
const nodeNull = bst.keyValueOrEntryOrRawElementToNode(null);
expect(nodeNull).toBe(undefined);
const nodeNull = bst.keyValueNodeEntryRawToNodeAndValue(null);
expect(nodeNull).toEqual([undefined, undefined]);
});
});
@ -496,7 +499,7 @@ describe('BST operations test recursively', () => {
expect(nodeId10?.key).toBe(10);
const nodeVal9 = bst.getNode(node => node.value === 9);
expect(nodeVal9?.key).toBe(undefined);
expect(bst.get(nodeVal9?.key)).toBe(undefined);
const leftMost = bst.getLeftMost();
expect(leftMost).toBe(1);
@ -1210,3 +1213,300 @@ describe('BST iterative methods test', () => {
expect(balanced.leaves(node => node?.value)).toEqual(['a', 'f', 'd', 'i']);
});
});
describe('BST operations map mode test', () => {
it('should perform various operations on a Binary Search Tree with numeric values', () => {
const bst = new BST<number, number>([], { isMapMode: true });
expect(bst).toBeInstanceOf(BST);
bst.add([11, 11]);
bst.add([3, 3]);
const idsAndValues: [number, number][] = [
[15, 15],
[1, 1],
[8, 8],
[13, 13],
[16, 16],
[2, 2],
[6, 6],
[9, 9],
[12, 12],
[14, 14],
[4, 4],
[7, 7],
[10, 10],
[5, 5]
];
bst.addMany(idsAndValues, undefined, false);
expect(bst.root).toBeInstanceOf(BSTNode);
if (bst.root) expect(bst.root.key).toBe(11);
expect(bst.size).toBe(16);
expect(bst.has(6)).toBe(true);
const node6 = bst.getNode(6);
expect(node6 && bst.getHeight(6)).toBe(2);
expect(node6 && bst.getDepth(6)).toBe(3);
const nodeId10 = bst.getNode(10);
expect(nodeId10?.key).toBe(10);
const nodeVal9 = bst.getNode(node => node.key === 9);
expect(nodeVal9?.key).toBe(9);
const leftMost = bst.getLeftMost();
expect(leftMost).toBe(1);
expect(bst.isBST()).toBe(true);
const node15 = bst.getNode(15);
const minNodeBySpecificNode = node15 && bst.getLeftMost(node => node, node15);
expect(minNodeBySpecificNode?.key).toBe(12);
const nodes = bst.getNodes(node => node.key === 15);
expect(nodes.map(node => node.key)).toEqual([15]);
});
it('should perform various operations on a Binary Search Tree with object values', () => {
const objBST = new BST<number, { name: string; age: number }>([], { isMapMode: true });
expect(objBST).toBeInstanceOf(BST);
objBST.add([11, { name: '11', age: 11 }]);
objBST.add([3, { name: '3', age: 3 }]);
objBST.addMany(
[15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5],
[
{ name: 'Alice', age: 15 },
{ name: 'Bob', age: 1 },
{ name: 'Charlie', age: 8 },
{ name: 'David', age: 13 },
{ name: 'Emma', age: 16 },
{ name: 'Frank', age: 2 },
{ name: 'Grace', age: 6 },
{ name: 'Hannah', age: 9 },
{ name: 'Isaac', age: 12 },
{ name: 'Jack', age: 14 },
{ name: 'Katie', age: 4 },
{ name: 'Liam', age: 7 },
{ name: 'Mia', age: 10 },
{ name: 'Noah', age: 5 }
],
false
);
expect(objBST.root).toBeInstanceOf(BSTNode);
if (objBST.root) expect(objBST.root.key).toBe(11);
expect(objBST.has(6)).toBe(true);
const node6 = objBST.getNode(6);
expect(node6 && objBST.getHeight(node6)).toBe(2);
expect(node6 && objBST.getDepth(node6)).toBe(3);
const nodeId10 = objBST.getNode(10);
expect(nodeId10?.key).toBe(10);
const nodeVal9 = objBST.getNode(9);
expect(nodeVal9?.key).toBe(9);
const leftMost = objBST.getLeftMost();
expect(leftMost).toBe(1);
const node15 = objBST.getNode(15);
expect(objBST.get(node15)).toEqual({
name: 'Alice',
age: 15
});
});
it('should keyValueNodeEntryRawToNodeAndValue', () => {
const bst = new BST<number>([], { isMapMode: true });
const node0 = bst.keyValueNodeEntryRawToNodeAndValue(0);
expect(node0).toEqual([
{
_left: undefined,
_right: undefined,
key: 0,
parent: undefined,
value: undefined
},
undefined
]);
const nodeUndefined = bst.keyValueNodeEntryRawToNodeAndValue(undefined);
expect(nodeUndefined).toEqual([undefined, undefined]);
const nodeNull = bst.keyValueNodeEntryRawToNodeAndValue(null);
expect(nodeNull).toEqual([undefined, undefined]);
});
});
describe('BST operations map mode test recursively', () => {
it('should perform various operations on a Binary Search Tree with numeric values', () => {
const bst = new BST<number>([], {
iterationType: 'RECURSIVE',
isMapMode: true
});
expect(bst).toBeInstanceOf(BST);
bst.add([11, 11]);
bst.add([3, 3]);
const idsAndValues = [15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5];
bst.addMany(idsAndValues, undefined, false);
expect(bst.root).toBeInstanceOf(BSTNode);
if (bst.root) expect(bst.root.key).toBe(11);
expect(bst.size).toBe(16);
expect(bst.has(6)).toBe(true);
const node6 = bst.getNode(6);
expect(node6 && bst.getHeight(6)).toBe(2);
expect(node6 && bst.getDepth(6)).toBe(3);
const nodeId10 = bst.getNode(10);
expect(bst.get(10)).toBe(undefined);
expect(nodeId10?.key).toBe(10);
const nodeVal9 = bst.getNode(node => node.key === 9);
expect(bst.get(nodeVal9?.key)).toBe(undefined);
});
it('should perform various operations on a Binary Search Tree with object values', () => {
const objBST = new BST<number, { key: number; keyA: number }>([], { isMapMode: true });
expect(objBST).toBeInstanceOf(BST);
objBST.add([11, { key: 11, keyA: 11 }]);
objBST.add([3, { key: 3, keyA: 3 }]);
const entries: [number, { key: number; keyA: number }][] = [
[15, { key: 15, keyA: 15 }],
[1, { key: 1, keyA: 1 }],
[8, { key: 8, keyA: 8 }],
[13, { key: 13, keyA: 13 }],
[16, { key: 16, keyA: 16 }],
[2, { key: 2, keyA: 2 }],
[6, { key: 6, keyA: 6 }],
[9, { key: 9, keyA: 9 }],
[12, { key: 12, keyA: 12 }],
[14, { key: 14, keyA: 14 }],
[4, { key: 4, keyA: 4 }],
[7, { key: 7, keyA: 7 }],
[10, { key: 10, keyA: 10 }],
[5, { key: 5, keyA: 5 }]
];
objBST.addMany(entries, undefined, false);
expect(objBST.root).toBeInstanceOf(BSTNode);
if (objBST.root) expect(objBST.root.key).toBe(11);
expect(objBST.has(6)).toBe(true);
const node6 = objBST.getNode(6);
expect(objBST.get(6)).toEqual({
key: 6,
keyA: 6
});
expect(node6 && objBST.getHeight(node6)).toBe(2);
expect(node6 && objBST.getDepth(node6)).toBe(3);
const nodeId10 = objBST.getNode(10);
expect(nodeId10?.key).toBe(10);
const nodeVal9 = objBST.getNode(9);
expect(nodeVal9?.key).toBe(9);
const leftMost = objBST.getLeftMost();
expect(leftMost).toBe(1);
const node15 = objBST.getNode(15);
expect(objBST.get(node15)).toEqual({
key: 15,
keyA: 15
});
});
});
describe('BST iterative methods map mode test', () => {
let bst: BST<number, string>;
beforeEach(() => {
bst = new BST();
bst.addMany(
[
[1, 'a'],
[2, 'b'],
[3, 'c']
],
[],
false
);
});
it('should clone work well', () => {
const cloned = bst.clone();
expect(cloned.root?.left).toBe(undefined);
expect(cloned.get(cloned.root?.right)).toBe('b');
});
it('should collapsed, unbalanced, balanced bst leaves', () => {
const collapsedToLinkedList = new BST();
collapsedToLinkedList.addMany(
[
[1, 'a'],
[2, 'b'],
[3, 'c'],
[4, 'd'],
[5, 'e'],
[6, 'f'],
[7, 'g'],
[8, 'h'],
[9, 'i']
],
[],
false
);
expect(collapsedToLinkedList.leaves()).toEqual([9]);
const unbalanced = new BST();
unbalanced.addMany(
[
[2, 'b'],
[1, 'a'],
[3, 'c'],
[4, 'd'],
[5, 'e'],
[6, 'f'],
[7, 'g'],
[8, 'h'],
[9, 'i']
],
[],
false
);
expect(unbalanced.leaves()).toEqual([1, 9]);
const balanced = new BST();
balanced.addMany(
[
[2, 'b'],
[1, 'a'],
[3, 'c'],
[4, 'd'],
[5, 'e'],
[6, 'f'],
[7, 'g'],
[8, 'h'],
[9, 'i']
],
[],
true
);
expect(balanced.leaves()).toEqual([1, 6, 4, 9]);
expect(balanced.leaves(node => balanced.get(node?.key))).toEqual(['a', 'f', 'd', 'i']);
});
});

View file

@ -817,7 +817,8 @@ describe('TreeMultiMap iterative methods test', () => {
expect(treeMM.getComputedCount()).toBe(21);
const cloned = treeMM.clone();
expect(cloned.root?.left?.key).toBe(1);
expect(cloned.root?.right?.value).toBe('c');
if (cloned.isMapMode) expect(cloned.get(cloned.root?.right)).toBe('c');
else expect(cloned.root?.right?.value).toBe(undefined);
});
it('should keys', () => {
@ -835,3 +836,140 @@ describe('TreeMultiMap iterative methods test', () => {
expect(leaves).toEqual([1, 3]);
});
});
describe('TreeMultiMap count map mode', () => {
let tmm: TreeMultiMap<number>;
beforeEach(() => {
tmm = new TreeMultiMap<number>([], { isMapMode: true });
});
it('Should added node count ', () => {
tmm.addMany([
[1, 1],
[2, 2],
[3, 3],
[4, 4],
[5, 5]
]);
const newNode = new TreeMultiMapNode(3, undefined, 10);
tmm.add(newNode, 33, 20);
// TODO expect(tmm.count).toBe(25);
expect(tmm.count).toBe(15);
expect(tmm.getComputedCount()).toBe(15);
expect(tmm.getNode(3)?.count).toBe(11);
});
});
describe('TreeMultiMap operations test1 map mode', () => {
it('should perform various operations on a Binary Search Tree with numeric values1', () => {
const tmm = new TreeMultiMap<number, number>([], { isMapMode: true });
expect(tmm instanceof TreeMultiMap);
tmm.add([11, 11]);
tmm.add([3, 3]);
const idAndValues: [number, number][] = [
[11, 11],
[3, 3],
[15, 15],
[1, 1],
[8, 8],
[13, 13],
[16, 16],
[2, 2],
[6, 6],
[9, 9],
[12, 12],
[14, 14],
[4, 4],
[7, 7],
[10, 10],
[5, 5]
];
tmm.addMany(idAndValues);
expect(tmm.root instanceof TreeMultiMapNode);
if (tmm.root) expect(tmm.root.key == 11);
expect(tmm.size).toBe(16);
expect(tmm.count).toBe(18);
expect(tmm.getComputedCount()).toBe(18);
expect(tmm.has(6));
if (isDebug) tmm.print();
expect(tmm.getHeight(6)).toBe(1);
expect(tmm.getDepth(6)).toBe(3);
const nodeId10 = tmm.getNode(10);
expect(nodeId10?.key).toBe(10);
const nodeVal9 = tmm.getNode(node => node.key === 9);
expect(nodeVal9?.key).toBe(9);
});
});
describe('TreeMultiMap operations test recursively1 map mode', () => {
it('should perform various operations on a Binary Search Tree with numeric values1', () => {
const tmm = new TreeMultiMap<number>([], {
iterationType: 'RECURSIVE',
isMapMode: true
});
expect(tmm instanceof TreeMultiMap);
tmm.add([11, 11]);
tmm.add([3, 3]);
const idAndValues: [number, number][] = [
[11, 11],
[3, 3],
[15, 15],
[1, 1],
[8, 8],
[13, 13],
[16, 16],
[2, 2],
[6, 6],
[9, 9],
[12, 12],
[14, 14],
[4, 4],
[7, 7],
[10, 10],
[5, 5]
];
tmm.addMany(idAndValues);
expect(tmm.root).toBeInstanceOf(TreeMultiMapNode);
if (tmm.root) expect(tmm.root.key).toBe(5);
expect(tmm.size).toBe(16);
expect(tmm.count).toBe(18);
expect(tmm.getComputedCount()).toBe(18);
expect(tmm.has(6));
expect(tmm.getHeight(6)).toBe(1);
expect(tmm.getDepth(6)).toBe(3);
const nodeId10 = tmm.getNode(10);
expect(nodeId10?.key).toBe(10);
const nodeVal9 = tmm.getNode(node => node.key === 9);
expect(nodeVal9?.key).toBe(9);
});
});
describe('TreeMultiMap iterative methods testm ap mode', () => {
let treeMM: TreeMultiMap<number, string>;
beforeEach(() => {
treeMM = new TreeMultiMap<number, string>([], { isMapMode: true });
treeMM.add(1, 'a', 10);
treeMM.add([2, 'b'], undefined, 10);
treeMM.add([3, 'c'], undefined, 1);
});
it('should clone work well', () => {
expect(treeMM.count).toBe(21);
expect(treeMM.getComputedCount()).toBe(21);
const cloned = treeMM.clone();
expect(cloned.root?.left?.key).toBe(1);
expect(cloned.get(cloned.root?.right)).toBe('c');
});
});