refactor: Renaming SENTINEL to NIL and placing the NIL node in the BinaryTree allows for direct equality checks in isNIL and isRealNode, avoiding excessive operations to improve performance. As a result, the performance of the get method in AVLTree has tripled.

This commit is contained in:
Revone 2024-01-15 21:05:42 +08:00
parent 173966edea
commit 56f1fabfca
9 changed files with 151 additions and 169 deletions

View file

@ -8,7 +8,7 @@ All notable changes to this project will be documented in this file.
- [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
- [`auto-changelog`](https://github.com/CookPete/auto-changelog)
## [v1.51.0](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming)
## [v1.51.1](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming)
### Changes

View file

@ -687,43 +687,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.36</td><td>157.24</td><td>1.88e-4</td></tr><tr><td>100,000 add & poll</td><td>32.56</td><td>30.72</td><td>0.01</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>100,000 add</td><td>6.44</td><td>155.39</td><td>1.89e-4</td></tr><tr><td>100,000 add & poll</td><td>31.54</td><td>31.71</td><td>7.91e-4</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>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>55.46</td><td>18.03</td><td>0.00</td></tr><tr><td>100,000 get</td><td>114.63</td><td>8.72</td><td>0.00</td></tr><tr><td>100,000 iterator</td><td>26.52</td><td>37.71</td><td>0.01</td></tr><tr><td>100,000 add & delete orderly</td><td>128.13</td><td>7.80</td><td>0.02</td></tr><tr><td>100,000 add & delete randomly</td><td>228.89</td><td>4.37</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>55.64</td><td>17.97</td><td>3.93e-4</td></tr><tr><td>100,000 add randomly</td><td>70.35</td><td>14.21</td><td>0.00</td></tr><tr><td>100,000 get</td><td>115.51</td><td>8.66</td><td>0.00</td></tr><tr><td>100,000 iterator</td><td>27.64</td><td>36.18</td><td>0.01</td></tr><tr><td>100,000 add & delete orderly</td><td>120.73</td><td>8.28</td><td>0.00</td></tr><tr><td>100,000 add & delete randomly</td><td>223.37</td><td>4.48</td><td>0.00</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>queue</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 push</td><td>43.53</td><td>22.97</td><td>0.01</td></tr><tr><td>100,000 push & shift</td><td>4.80</td><td>208.14</td><td>5.81e-4</td></tr><tr><td>Native JS Array 100,000 push & shift</td><td>2201.64</td><td>0.45</td><td>0.11</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.87</td><td>23.33</td><td>0.01</td></tr><tr><td>100,000 push & shift</td><td>4.87</td><td>205.17</td><td>6.94e-4</td></tr><tr><td>Native JS Array 100,000 push & shift</td><td>2196.84</td><td>0.46</td><td>0.19</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>25.91</td><td>38.59</td><td>0.01</td></tr><tr><td>1,000,000 push & pop</td><td>30.71</td><td>32.57</td><td>0.00</td></tr><tr><td>1,000,000 push & shift</td><td>30.59</td><td>32.69</td><td>0.00</td></tr><tr><td>100,000 push & shift</td><td>3.23</td><td>309.94</td><td>2.61e-4</td></tr><tr><td>Native JS Array 100,000 push & shift</td><td>2525.12</td><td>0.40</td><td>0.39</td></tr><tr><td>100,000 unshift & shift</td><td>2.87</td><td>347.92</td><td>2.86e-4</td></tr><tr><td>Native JS Array 100,000 unshift & shift</td><td>4400.38</td><td>0.23</td><td>0.14</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>23.68</td><td>42.22</td><td>0.00</td></tr><tr><td>1,000,000 push & pop</td><td>30.68</td><td>32.60</td><td>0.00</td></tr><tr><td>1,000,000 push & shift</td><td>30.49</td><td>32.80</td><td>0.00</td></tr><tr><td>100,000 push & shift</td><td>3.21</td><td>311.51</td><td>2.41e-4</td></tr><tr><td>Native JS Array 100,000 push & shift</td><td>2510.08</td><td>0.40</td><td>0.34</td></tr><tr><td>100,000 unshift & shift</td><td>2.89</td><td>346.57</td><td>2.98e-4</td></tr><tr><td>Native JS Array 100,000 unshift & shift</td><td>4581.65</td><td>0.22</td><td>0.40</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>113.02</td><td>8.85</td><td>0.02</td></tr><tr><td>Native JS Map 1,000,000 set</td><td>201.23</td><td>4.97</td><td>0.00</td></tr><tr><td>Native JS Set 1,000,000 add</td><td>168.53</td><td>5.93</td><td>0.01</td></tr><tr><td>1,000,000 set & get</td><td>118.49</td><td>8.44</td><td>0.02</td></tr><tr><td>Native JS Map 1,000,000 set & get</td><td>263.49</td><td>3.80</td><td>0.01</td></tr><tr><td>Native JS Set 1,000,000 add & has</td><td>168.28</td><td>5.94</td><td>0.01</td></tr><tr><td>1,000,000 ObjKey set & get</td><td>309.88</td><td>3.23</td><td>0.01</td></tr><tr><td>Native JS Map 1,000,000 ObjKey set & get</td><td>282.50</td><td>3.54</td><td>0.04</td></tr><tr><td>Native JS Set 1,000,000 ObjKey add & has</td><td>268.42</td><td>3.73</td><td>0.03</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 set</td><td>120.66</td><td>8.29</td><td>0.03</td></tr><tr><td>Native JS Map 1,000,000 set</td><td>202.57</td><td>4.94</td><td>0.01</td></tr><tr><td>Native JS Set 1,000,000 add</td><td>167.46</td><td>5.97</td><td>0.01</td></tr><tr><td>1,000,000 set & get</td><td>115.60</td><td>8.65</td><td>0.01</td></tr><tr><td>Native JS Map 1,000,000 set & get</td><td>265.34</td><td>3.77</td><td>0.01</td></tr><tr><td>Native JS Set 1,000,000 add & has</td><td>167.85</td><td>5.96</td><td>0.01</td></tr><tr><td>1,000,000 ObjKey set & get</td><td>308.73</td><td>3.24</td><td>0.03</td></tr><tr><td>Native JS Map 1,000,000 ObjKey set & get</td><td>300.60</td><td>3.33</td><td>0.03</td></tr><tr><td>Native JS Set 1,000,000 ObjKey add & has</td><td>270.49</td><td>3.70</td><td>0.04</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>44.85</td><td>22.30</td><td>0.01</td></tr><tr><td>100,000 getWords</td><td>84.84</td><td>11.79</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>45.79</td><td>21.84</td><td>7.32e-4</td></tr><tr><td>100,000 getWords</td><td>87.85</td><td>11.38</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>381.63</td><td>2.62</td><td>0.00</td></tr><tr><td>100,000 get</td><td>354.69</td><td>2.82</td><td>0.00</td></tr><tr><td>100,000 iterator</td><td>29.87</td><td>33.48</td><td>0.01</td></tr><tr><td>100,000 add & delete orderly</td><td>652.77</td><td>1.53</td><td>0.00</td></tr><tr><td>100,000 add & delete randomly</td><td>929.07</td><td>1.08</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>260.78</td><td>3.83</td><td>0.00</td></tr><tr><td>100,000 add randomly</td><td>306.61</td><td>3.26</td><td>0.00</td></tr><tr><td>100,000 get</td><td>140.27</td><td>7.13</td><td>0.00</td></tr><tr><td>100,000 iterator</td><td>29.90</td><td>33.45</td><td>0.01</td></tr><tr><td>100,000 add & delete orderly</td><td>428.76</td><td>2.33</td><td>0.00</td></tr><tr><td>100,000 add & delete randomly</td><td>580.74</td><td>1.72</td><td>0.00</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>binary-tree-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</td><td>5.55</td><td>180.05</td><td>7.09e-5</td></tr><tr><td>10,000 RBTree add & delete randomly</td><td>19.06</td><td>52.46</td><td>1.94e-4</td></tr><tr><td>10,000 RBTree get</td><td>0.61</td><td>1647.37</td><td>6.11e-6</td></tr><tr><td>10,000 AVLTree add</td><td>32.03</td><td>31.22</td><td>7.32e-4</td></tr><tr><td>10,000 AVLTree get</td><td>19.65</td><td>50.89</td><td>3.12e-4</td></tr><tr><td>10,000 AVLTree add & delete randomly</td><td>62.07</td><td>16.11</td><td>4.26e-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</td><td>5.74</td><td>174.10</td><td>9.29e-5</td></tr><tr><td>10,000 RBTree add & delete randomly</td><td>18.83</td><td>53.10</td><td>1.49e-4</td></tr><tr><td>10,000 RBTree get</td><td>0.77</td><td>1290.55</td><td>7.33e-6</td></tr><tr><td>10,000 AVLTree add</td><td>22.60</td><td>44.25</td><td>2.14e-4</td></tr><tr><td>10,000 AVLTree get</td><td>10.63</td><td>94.08</td><td>1.02e-4</td></tr><tr><td>10,000 AVLTree add & delete randomly</td><td>44.17</td><td>22.64</td><td>3.52e-4</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>directed-graph</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000 addVertex</td><td>0.10</td><td>9939.30</td><td>9.29e-7</td></tr><tr><td>1,000 addEdge</td><td>6.15</td><td>162.54</td><td>8.71e-4</td></tr><tr><td>1,000 getVertex</td><td>0.05</td><td>2.18e+4</td><td>2.83e-7</td></tr><tr><td>1,000 getEdge</td><td>23.93</td><td>41.78</td><td>0.00</td></tr><tr><td>tarjan</td><td>207.83</td><td>4.81</td><td>0.01</td></tr><tr><td>topologicalSort</td><td>181.91</td><td>5.50</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 addVertex</td><td>0.11</td><td>9501.69</td><td>1.02e-6</td></tr><tr><td>1,000 addEdge</td><td>6.18</td><td>161.81</td><td>4.27e-4</td></tr><tr><td>1,000 getVertex</td><td>0.05</td><td>2.16e+4</td><td>3.23e-7</td></tr><tr><td>1,000 getEdge</td><td>23.31</td><td>42.90</td><td>0.00</td></tr><tr><td>tarjan</td><td>206.06</td><td>4.85</td><td>0.01</td></tr><tr><td>topologicalSort</td><td>181.65</td><td>5.51</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'>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>210.21</td><td>4.76</td><td>0.03</td></tr><tr><td>1,000,000 unshift</td><td>218.63</td><td>4.57</td><td>0.05</td></tr><tr><td>1,000,000 unshift & shift</td><td>162.14</td><td>6.17</td><td>0.01</td></tr><tr><td>1,000,000 addBefore</td><td>319.75</td><td>3.13</td><td>0.06</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 push</td><td>207.88</td><td>4.81</td><td>0.04</td></tr><tr><td>1,000,000 unshift</td><td>214.33</td><td>4.67</td><td>0.06</td></tr><tr><td>1,000,000 unshift & shift</td><td>185.54</td><td>5.39</td><td>0.04</td></tr><tr><td>1,000,000 addBefore</td><td>308.66</td><td>3.24</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>191.55</td><td>5.22</td><td>0.03</td></tr><tr><td>10,000 push & pop</td><td>215.95</td><td>4.63</td><td>0.01</td></tr><tr><td>10,000 addBefore</td><td>249.82</td><td>4.00</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 & shift</td><td>202.61</td><td>4.94</td><td>0.04</td></tr><tr><td>10,000 push & pop</td><td>219.69</td><td>4.55</td><td>0.02</td></tr><tr><td>10,000 addBefore</td><td>247.13</td><td>4.05</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'>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>27.54</td><td>36.31</td><td>2.55e-4</td></tr><tr><td>100,000 add & poll</td><td>75.88</td><td>13.18</td><td>4.27e-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>27.36</td><td>36.55</td><td>9.92e-4</td></tr><tr><td>100,000 add & poll</td><td>146.72</td><td>6.82</td><td>6.84e-4</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>39.78</td><td>25.14</td><td>0.01</td></tr><tr><td>1,000,000 push & pop</td><td>46.90</td><td>21.32</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>39.36</td><td>25.41</td><td>0.01</td></tr><tr><td>1,000,000 push & pop</td><td>47.86</td><td>20.89</td><td>0.01</td></tr></table></div>
</div>
[//]: # (No deletion!!! End of Replace Section)

View file

@ -191,6 +191,16 @@ export class BinaryTree<
return this._size;
}
protected _NIL: NODE = new BinaryTreeNode<K, V>(NaN as K) as unknown as NODE;
/**
* The function returns the value of the _NIL property.
* @returns The method is returning the value of the `_NIL` property.
*/
get NIL(): NODE {
return this._NIL;
}
/**
* Creates a new instance of BinaryTreeNode with the given key and value.
* @param {K} key - The key for the new node.
@ -281,6 +291,15 @@ export class BinaryTree<
}
}
/**
* The function checks if a given node is a real node or null.
* @param {any} node - The parameter `node` is of type `any`, which means it can be any data type.
* @returns a boolean value.
*/
isNodeOrNull(node: KeyOrNodeOrEntry<K, V, NODE>): node is NODE | null {
return this.isRealNode(node) || node === null;
}
/**
* The function "isNode" checks if an keyOrNodeOrEntry is an instance of the BinaryTreeNode class.
* @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter is a variable of type `KeyOrNodeOrEntry<K, V,NODE>`.
@ -290,6 +309,26 @@ export class BinaryTree<
return keyOrNodeOrEntry instanceof BinaryTreeNode;
}
/**
* The function checks if a given node is a real node by verifying if it is an instance of
* BinaryTreeNode and its key is not NaN.
* @param {any} node - The parameter `node` is of type `any`, which means it can be any data type.
* @returns a boolean value.
*/
isRealNode(node: KeyOrNodeOrEntry<K, V, NODE>): node is NODE {
if (!this.isNode(node)) return false;
return node !== this.NIL;
}
/**
* The function checks if a given node is a BinaryTreeNode instance and has a key value of NaN.
* @param {any} node - The parameter `node` is of type `any`, which means it can be any data type.
* @returns a boolean value.
*/
isNIL(node: KeyOrNodeOrEntry<K, V, NODE>) {
return node === this.NIL;
}
/**
* The function checks if a given value is an entry in a binary tree node.
* @param keyOrNodeOrEntry - KeyOrNodeOrEntry<K, V,NODE> - A generic type representing a node in a binary tree. It has
@ -300,34 +339,6 @@ export class BinaryTree<
return Array.isArray(keyOrNodeOrEntry) && keyOrNodeOrEntry.length === 2;
}
/**
* The function checks if a given node is a real node by verifying if it is an instance of
* BinaryTreeNode and its key is not NaN.
* @param {any} node - The parameter `node` is of type `any`, which means it can be any data type.
* @returns a boolean value.
*/
isRealNode(node: KeyOrNodeOrEntry<K, V, NODE>): node is NODE {
return node instanceof BinaryTreeNode && String(node.key) !== 'NaN';
}
/**
* The function checks if a given node is a BinaryTreeNode instance and has a key value of NaN.
* @param {any} node - The parameter `node` is of type `any`, which means it can be any data type.
* @returns a boolean value.
*/
isNIL(node: KeyOrNodeOrEntry<K, V, NODE>) {
return node instanceof BinaryTreeNode && String(node.key) === 'NaN';
}
/**
* The function checks if a given node is a real node or null.
* @param {any} node - The parameter `node` is of type `any`, which means it can be any data type.
* @returns a boolean value.
*/
isNodeOrNull(node: KeyOrNodeOrEntry<K, V, NODE>): node is NODE | null {
return this.isRealNode(node) || node === null;
}
/**
* Time Complexity O(n)
* Space Complexity O(1)
@ -612,9 +623,9 @@ export class BinaryTree<
ans.push(cur);
if (onlyOne) return;
}
if (!cur.left && !cur.right) return;
cur.left && dfs(cur.left);
cur.right && dfs(cur.right);
if (!this.isRealNode(cur.left) && !this.isRealNode(cur.right)) return;
this.isRealNode(cur.left) && dfs(cur.left);
this.isRealNode(cur.right) && dfs(cur.right);
};
dfs(beginRoot);
@ -622,13 +633,13 @@ export class BinaryTree<
const stack = [beginRoot];
while (stack.length > 0) {
const cur = stack.pop();
if (cur) {
if (this.isRealNode(cur)) {
if (callback(cur) === identifier) {
ans.push(cur);
if (onlyOne) return ans;
}
cur.left && stack.push(cur.left);
cur.right && stack.push(cur.right);
this.isRealNode(cur.left) && stack.push(cur.left);
this.isRealNode(cur.right) && stack.push(cur.right);
}
}
}
@ -689,9 +700,6 @@ export class BinaryTree<
beginRoot: KeyOrNodeOrEntry<K, V, NODE> = this.root,
iterationType: IterationType = this.iterationType
): NODE | null | undefined {
if ((!callback || callback === this._DEFAULT_CALLBACK) && (identifier as any) instanceof BinaryTreeNode)
callback = (node => node) as C;
return this.getNodes(identifier, callback, true, beginRoot, iterationType)[0] ?? null;
}
@ -793,9 +801,6 @@ export class BinaryTree<
beginRoot: KeyOrNodeOrEntry<K, V, NODE> = this.root,
iterationType: IterationType = this.iterationType
): V | undefined {
if ((!callback || callback === this._DEFAULT_CALLBACK) && (identifier as any) instanceof BinaryTreeNode)
callback = (node => node) as C;
return this.getNode(identifier, callback, beginRoot, iterationType)?.value ?? undefined;
}

View file

@ -13,7 +13,7 @@ import type {
BTNodePureExemplar,
KeyOrNodeOrEntry
} from '../../types';
import { BSTVariant, CP, DFSOrderPattern, IterationType } from '../../types';
import { BSTNKeyOrNode, BSTVariant, CP, DFSOrderPattern, IterationType } from '../../types';
import { BinaryTree, BinaryTreeNode } from './binary-tree';
import { IBinaryTree } from '../../interfaces';
import { Queue } from '../queue';
@ -543,6 +543,41 @@ export class BST<
return ans;
}
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
*
* The `getNode` function retrieves a node from a Red-Black Tree based on the provided identifier and
* callback function.
* @param {ReturnType<C> | undefined} identifier - The `identifier` parameter is the value or key
* that you want to search for in the binary search tree. It can be of any type that is compatible
* with the type of nodes in the tree.
* @param {C} callback - The `callback` parameter is a function that will be called for each node in
* the tree. It is used to determine whether a node matches the given identifier. The `callback`
* function should take a node as its parameter and return a value that can be compared to the
* `identifier` parameter.
* @param beginRoot - The `beginRoot` parameter is the starting point for the search in the binary
* search tree. It can be either a key or a node. If it is a key, it will be converted to a node
* using the `ensureNode` method. If it is not provided, the `root`
* @param iterationType - The `iterationType` parameter is used to specify the type of iteration to
* be performed when searching for nodes in the binary search tree. It is an optional parameter and
* its default value is taken from the `iterationType` property of the class.
* @returns The method is returning a value of type `NODE | null | undefined`.
*/
override getNode<C extends BTNCallback<NODE>>(
identifier: ReturnType<C> | undefined,
callback: C = this._DEFAULT_CALLBACK as C,
beginRoot: BSTNKeyOrNode<K, NODE> = this.root,
iterationType: IterationType = this.iterationType
): NODE | undefined {
return this.getNodes(identifier, callback, true, beginRoot, iterationType)[0] ?? undefined;
}
/**
* Time complexity: O(n)
* Space complexity: O(n)

View file

@ -1,8 +1,6 @@
import type {
BinaryTreeDeleteResult,
BSTNKeyOrNode,
BTNCallback,
IterationType,
KeyOrNodeOrEntry,
RBTreeOptions,
RedBlackTreeNested,
@ -73,23 +71,13 @@ export class RedBlackTree<
constructor(keysOrNodesOrEntries: Iterable<KeyOrNodeOrEntry<K, V, NODE>> = [], options?: RBTreeOptions<K>) {
super([], options);
this._root = this.SENTINEL;
this._root = this.NIL;
if (keysOrNodesOrEntries) {
this.addMany(keysOrNodesOrEntries);
}
}
protected _SENTINEL: NODE = new RedBlackTreeNode<K, V>(NaN as K) as unknown as NODE;
/**
* The function returns the value of the _SENTINEL property.
* @returns The method is returning the value of the `_SENTINEL` property.
*/
get SENTINEL(): NODE {
return this._SENTINEL;
}
protected override _root: NODE | undefined;
/**
@ -184,60 +172,6 @@ export class RedBlackTree<
return keyOrNodeOrEntry instanceof RedBlackTreeNode;
}
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* The function checks if a given node is a real node in a Red-Black Tree.
* @param {NODE | undefined} node - The `node` parameter is of type `NODE | undefined`, which means
* it can either be of type `NODE` or `undefined`.
* @returns a boolean value.
*/
override isRealNode(node: NODE | undefined): node is NODE {
if (node === this.SENTINEL || node === undefined) return false;
return node instanceof RedBlackTreeNode;
}
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
*
* The `getNode` function retrieves a node from a Red-Black Tree based on the provided identifier and
* callback function.
* @param {ReturnType<C> | undefined} identifier - The `identifier` parameter is the value or key
* that you want to search for in the binary search tree. It can be of any type that is compatible
* with the type of nodes in the tree.
* @param {C} callback - The `callback` parameter is a function that will be called for each node in
* the tree. It is used to determine whether a node matches the given identifier. The `callback`
* function should take a node as its parameter and return a value that can be compared to the
* `identifier` parameter.
* @param beginRoot - The `beginRoot` parameter is the starting point for the search in the binary
* search tree. It can be either a key or a node. If it is a key, it will be converted to a node
* using the `ensureNode` method. If it is not provided, the `root`
* @param iterationType - The `iterationType` parameter is used to specify the type of iteration to
* be performed when searching for nodes in the binary search tree. It is an optional parameter and
* its default value is taken from the `iterationType` property of the class.
* @returns The method is returning a value of type `NODE | null | undefined`.
*/
override getNode<C extends BTNCallback<NODE>>(
identifier: ReturnType<C> | undefined,
callback: C = this._DEFAULT_CALLBACK as C,
beginRoot: BSTNKeyOrNode<K, NODE> = this.root,
iterationType: IterationType = this.iterationType
): NODE | null | undefined {
return this.getNodes(identifier, callback, true, beginRoot, iterationType)[0] ?? undefined;
}
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
@ -252,7 +186,7 @@ export class RedBlackTree<
*/
override clear() {
super.clear();
this._root = this.SENTINEL;
this._root = this.NIL;
}
/**
@ -430,9 +364,9 @@ export class RedBlackTree<
while (this.isRealNode(current)) {
parent = current;
if (node.key < current.key) {
current = current.left ?? this.SENTINEL;
current = current.left ?? this.NIL;
} else if (node.key > current.key) {
current = current.right ?? this.SENTINEL;
current = current.right ?? this.NIL;
} else {
this._replaceNode(current, node);
return 'UPDATED';
@ -449,8 +383,8 @@ export class RedBlackTree<
parent.right = node;
}
node.left = this.SENTINEL;
node.right = this.SENTINEL;
node.left = this.NIL;
node.right = this.NIL;
node.color = 'RED';
this._insertFixup(node);

View file

@ -12,6 +12,10 @@ suite
avlTree.clear();
for (let i = 0; i < randomArray.length; i++) avlTree.add(i);
})
.add(`${HUNDRED_THOUSAND.toLocaleString()} add randomly`, () => {
avlTree.clear();
for (let i = 0; i < randomArray.length; i++) avlTree.add(randomArray[i]);
})
.add(`${HUNDRED_THOUSAND.toLocaleString()} get`, () => {
for (let i = 0; i < randomArray.length; i++) avlTree.get(randomArray[i]);
})

View file

@ -15,6 +15,10 @@ suite
rbTree.clear();
for (let i = 0; i < randomArray.length; i++) rbTree.add(i);
})
.add(`${HUNDRED_THOUSAND.toLocaleString()} add randomly`, () => {
rbTree.clear();
for (let i = 0; i < randomArray.length; i++) rbTree.add(randomArray[i]);
})
.add(`${HUNDRED_THOUSAND.toLocaleString()} get`, () => {
for (let i = 0; i < randomArray.length; i++) rbTree.get(randomArray[i]);
})

View file

@ -20,8 +20,8 @@ describe('Overall BinaryTree Test', () => {
leftMost?.key === 1; // true
expect(leftMost?.key).toBe(1);
bst.delete(6);
bst.getNode(6); // null
expect(bst.getNode(6)).toBeNull();
bst.getNode(6); // undefined
expect(bst.getNode(6)).toBe(undefined);
bst.isAVLBalanced(); // true or false
expect(bst.isAVLBalanced()).toBe(true);
const bfsIDs: number[] = [];

View file

@ -74,7 +74,7 @@ describe('RedBlackTree 1', () => {
it('should handle an empty rbTree', () => {
const minNode = rbTree.getLeftMost(rbTree.root);
expect(minNode).toBe(rbTree.SENTINEL);
expect(minNode).toBe(rbTree.NIL);
});
});
@ -92,7 +92,7 @@ describe('RedBlackTree 1', () => {
it('should handle an empty rbTree', () => {
const maxNode = rbTree.getRightMost(rbTree.root);
expect(maxNode).toBe(rbTree.SENTINEL);
expect(maxNode).toBe(rbTree.NIL);
});
});
@ -116,7 +116,7 @@ describe('RedBlackTree 1', () => {
const node = rbTree.getNode(10);
const successorNode = rbTree.getSuccessor(node!);
// TODO not sure if it should be undefined or rbTree.SENTINEL
// TODO not sure if it should be undefined or rbTree.NIL
expect(successorNode).toBe(undefined);
});
});
@ -141,7 +141,7 @@ describe('RedBlackTree 1', () => {
const node = rbTree.getNode(20);
const predecessorNode = rbTree.getPredecessor(node!);
// TODO not sure if it should be rbTree.SENTINEL or something else.
// TODO not sure if it should be rbTree.NIL or something else.
expect(predecessorNode).toBe(rbTree.getNode(20));
});
});
@ -279,28 +279,28 @@ describe('RedBlackTree 2', () => {
expect(node5F?.parent).toBe(node10F);
expect(node15F?.key).toBe(15);
expect(node15F?.color).toBe('RED');
expect(node15F?.left).toBe(rbTree.SENTINEL);
expect(node15F?.right).toBe(rbTree.SENTINEL);
expect(node15F?.left).toBe(rbTree.NIL);
expect(node15F?.right).toBe(rbTree.NIL);
expect(node15F?.parent).toBe(node20F);
expect(node21F?.key).toBe(21);
expect(node21F?.color).toBe('RED');
expect(node21F?.left).toBe(rbTree.SENTINEL);
expect(node21F?.right).toBe(rbTree.SENTINEL);
expect(node21F?.left).toBe(rbTree.NIL);
expect(node21F?.right).toBe(rbTree.NIL);
expect(node21F?.parent).toBe(node20F);
expect(node6F?.key).toBe(6);
expect(node6F?.color).toBe('RED');
expect(node6F?.left).toBe(rbTree.SENTINEL);
expect(node6F?.right).toBe(rbTree.SENTINEL);
expect(node6F?.left).toBe(rbTree.NIL);
expect(node6F?.right).toBe(rbTree.NIL);
expect(node6F?.parent).toBe(node5F);
expect(node2F?.key).toBe(2);
expect(node2F?.color).toBe('RED');
expect(node2F?.left).toBe(rbTree.SENTINEL);
expect(node2F?.right).toBe(rbTree.SENTINEL);
expect(node2F?.left).toBe(rbTree.NIL);
expect(node2F?.right).toBe(rbTree.NIL);
expect(node2F?.parent).toBe(node5F);
expect(node15F?.key).toBe(15);
expect(node15F?.color).toBe('RED');
expect(node15F?.left).toBe(rbTree.SENTINEL);
expect(node15F?.right).toBe(rbTree.SENTINEL);
expect(node15F?.left).toBe(rbTree.NIL);
expect(node15F?.right).toBe(rbTree.NIL);
expect(node15F?.parent).toBe(node20F);
rbTree.delete(5);
node10F = rbTree.getNode(10);
@ -323,28 +323,28 @@ describe('RedBlackTree 2', () => {
expect(node5F).toBe(undefined);
expect(node15F?.key).toBe(15);
expect(node15F?.color).toBe('RED');
expect(node15F?.left).toBe(rbTree.SENTINEL);
expect(node15F?.right).toBe(rbTree.SENTINEL);
expect(node15F?.left).toBe(rbTree.NIL);
expect(node15F?.right).toBe(rbTree.NIL);
expect(node15F?.parent).toBe(node20F);
expect(node21F?.key).toBe(21);
expect(node21F?.color).toBe('RED');
expect(node21F?.left).toBe(rbTree.SENTINEL);
expect(node21F?.right).toBe(rbTree.SENTINEL);
expect(node21F?.left).toBe(rbTree.NIL);
expect(node21F?.right).toBe(rbTree.NIL);
expect(node21F?.parent).toBe(node20F);
expect(node6F?.key).toBe(6);
expect(node6F?.color).toBe('BLACK');
expect(node6F?.left).toBe(node2F);
expect(node6F?.right).toBe(rbTree.SENTINEL);
expect(node6F?.right).toBe(rbTree.NIL);
expect(node6F?.parent).toBe(node10F);
expect(node2F?.key).toBe(2);
expect(node2F?.color).toBe('RED');
expect(node2F?.left).toBe(rbTree.SENTINEL);
expect(node2F?.right).toBe(rbTree.SENTINEL);
expect(node2F?.left).toBe(rbTree.NIL);
expect(node2F?.right).toBe(rbTree.NIL);
expect(node2F?.parent).toBe(node6F);
expect(node15F?.key).toBe(15);
expect(node15F?.color).toBe('RED');
expect(node15F?.left).toBe(rbTree.SENTINEL);
expect(node15F?.right).toBe(rbTree.SENTINEL);
expect(node15F?.left).toBe(rbTree.NIL);
expect(node15F?.right).toBe(rbTree.NIL);
expect(node15F?.parent).toBe(node20F);
rbTree.delete(20);
node10F = rbTree.getNode(10);
@ -363,28 +363,28 @@ describe('RedBlackTree 2', () => {
expect(node5F).toBe(undefined);
expect(node15F?.key).toBe(15);
expect(node15F?.color).toBe('RED');
expect(node15F?.left).toBe(rbTree.SENTINEL);
expect(node15F?.right).toBe(rbTree.SENTINEL);
expect(node15F?.left).toBe(rbTree.NIL);
expect(node15F?.right).toBe(rbTree.NIL);
expect(node15F?.parent).toBe(node21F);
expect(node21F?.key).toBe(21);
expect(node21F?.color).toBe('BLACK');
expect(node21F?.left).toBe(node15F);
expect(node21F?.right).toBe(rbTree.SENTINEL);
expect(node21F?.right).toBe(rbTree.NIL);
expect(node21F?.parent).toBe(node10F);
expect(node6F?.key).toBe(6);
expect(node6F?.color).toBe('BLACK');
expect(node6F?.left).toBe(node2F);
expect(node6F?.right).toBe(rbTree.SENTINEL);
expect(node6F?.right).toBe(rbTree.NIL);
expect(node6F?.parent).toBe(node10F);
expect(node2F?.key).toBe(2);
expect(node2F?.color).toBe('RED');
expect(node2F?.left).toBe(rbTree.SENTINEL);
expect(node2F?.right).toBe(rbTree.SENTINEL);
expect(node2F?.left).toBe(rbTree.NIL);
expect(node2F?.right).toBe(rbTree.NIL);
expect(node2F?.parent).toBe(node6F);
expect(node15F?.key).toBe(15);
expect(node15F?.color).toBe('RED');
expect(node15F?.left).toBe(rbTree.SENTINEL);
expect(node15F?.right).toBe(rbTree.SENTINEL);
expect(node15F?.left).toBe(rbTree.NIL);
expect(node15F?.right).toBe(rbTree.NIL);
expect(node15F?.parent).toBe(node21F);
});
@ -394,8 +394,8 @@ describe('RedBlackTree 2', () => {
rbTree.add(5);
rbTree.add(15);
const node15F = rbTree.getNode(15);
expect(node15F?.left).toBe(rbTree.SENTINEL);
expect(node15F?.right).toBe(rbTree.SENTINEL);
expect(node15F?.left).toBe(rbTree.NIL);
expect(node15F?.right).toBe(rbTree.NIL);
expect(node15F?.parent).toBe(rbTree.getNode(5));
rbTree.add(25);
@ -410,8 +410,8 @@ describe('RedBlackTree 2', () => {
rbTree.add(155);
rbTree.add(225);
const node225F = rbTree.getNode(225);
expect(node225F?.left).toBe(rbTree.SENTINEL);
expect(node225F?.right).toBe(rbTree.SENTINEL);
expect(node225F?.left).toBe(rbTree.NIL);
expect(node225F?.right).toBe(rbTree.NIL);
expect(node225F?.parent?.key).toBe(155);
rbTree.add(7);
isDebug && rbTree.print();
@ -438,14 +438,14 @@ describe('RedBlackTree 2', () => {
const node50 = rbTree.getNode(50);
expect(node50?.key).toBe(50);
expect(node50?.left?.key).toBe(33);
expect(node50?.right).toBe(rbTree.SENTINEL);
expect(node50?.right).toBe(rbTree.NIL);
const node15Fo = rbTree.getNode(15);
expect(node15Fo?.key).toBe(15);
expect(node15Fo?.left).toBe(rbTree.SENTINEL);
expect(node15Fo?.left).toBe(rbTree.NIL);
const node225S = rbTree.getNode(225);
expect(node225S?.left).toBe(rbTree.SENTINEL);
expect(node225S?.right).toBe(rbTree.SENTINEL);
expect(node225S?.left).toBe(rbTree.NIL);
expect(node225S?.right).toBe(rbTree.NIL);
expect(node225S?.parent?.key).toBe(155);
// TODO
// expect(rbTree.getNode(0)).toBe(undefined);
@ -512,7 +512,7 @@ describe('RedBlackTree 2', () => {
rbTree.delete(getRandomInt(-100, 1000));
}
// TODO there is a bug when dfs the rbTree with SENTINEL node
// TODO there is a bug when dfs the rbTree with NIL node
// expect(rbTree.isBST()).toBe(true);
});
const { HUNDRED_THOUSAND } = magnitude;