perf: Unified all APIs, all parameters that accept node types can also accept node keys as parameters.

This commit is contained in:
Revone 2023-11-09 17:47:02 +08:00
parent 8971dbb605
commit 28207b6d45
9 changed files with 326 additions and 239 deletions

View file

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

244
README.md
View file

@ -25,108 +25,6 @@ Now you can use this library in Node.js and browser environments in CommonJS(req
[//]: # (![Lines](https://img.shields.io/badge/lines-68.6%25-red.svg?style=flat))
## Built-in classic algorithms
<table>
<thead>
<tr>
<th>Algorithm</th>
<th>Function Description</th>
<th>Iteration Type</th>
</tr>
</thead>
<tbody>
<tr>
<td>Binary Tree DFS</td>
<td>Traverse a binary tree in a depth-first manner, starting from the root node, first visiting the left subtree,
and then the right subtree, using recursion.
</td>
<td>Recursion + Iteration</td>
</tr>
<tr>
<td>Binary Tree BFS</td>
<td>Traverse a binary tree in a breadth-first manner, starting from the root node, visiting nodes level by level
from left to right.
</td>
<td>Iteration</td>
</tr>
<tr>
<td>Graph DFS</td>
<td>Traverse a graph in a depth-first manner, starting from a given node, exploring along one path as deeply as
possible, and backtracking to explore other paths. Used for finding connected components, paths, etc.
</td>
<td>Recursion + Iteration</td>
</tr>
<tr>
<td>Binary Tree Morris</td>
<td>Morris traversal is an in-order traversal algorithm for binary trees with O(1) space complexity. It allows tree
traversal without additional stack or recursion.
</td>
<td>Iteration</td>
</tr>
<tr>
<td>Graph BFS</td>
<td>Traverse a graph in a breadth-first manner, starting from a given node, first visiting nodes directly connected
to the starting node, and then expanding level by level. Used for finding shortest paths, etc.
</td>
<td>Recursion + Iteration</td>
</tr>
<tr>
<td>Graph Tarjan's Algorithm</td>
<td>Find strongly connected components in a graph, typically implemented using depth-first search.</td>
<td>Recursion</td>
</tr>
<tr>
<td>Graph Bellman-Ford Algorithm</td>
<td>Finding the shortest paths from a single source, can handle negative weight edges</td>
<td>Iteration</td>
</tr>
<tr>
<td>Graph Dijkstra's Algorithm</td>
<td>Finding the shortest paths from a single source, cannot handle negative weight edges</td>
<td>Iteration</td>
</tr>
<tr>
<td>Graph Floyd-Warshall Algorithm</td>
<td>Finding the shortest paths between all pairs of nodes</td>
<td>Iteration</td>
</tr>
<tr>
<td>Graph getCycles</td>
<td>Find all cycles in a graph or detect the presence of cycles.</td>
<td>Recursion</td>
</tr>
<tr>
<td>Graph getCutVertexes</td>
<td>Find cut vertices in a graph, which are nodes that, when removed, increase the number of connected components in
the graph.
</td>
<td>Recursion</td>
</tr>
<tr>
<td>Graph getSCCs</td>
<td>Find strongly connected components in a graph, which are subgraphs where any two nodes can reach each other.
</td>
<td>Recursion</td>
</tr>
<tr>
<td>Graph getBridges</td>
<td>Find bridges in a graph, which are edges that, when removed, increase the number of connected components in the
graph.
</td>
<td>Recursion</td>
</tr>
<tr>
<td>Graph topologicalSort</td>
<td>Perform topological sorting on a directed acyclic graph (DAG) to find a linear order of nodes such that all
directed edges go from earlier nodes to later nodes.
</td>
<td>Recursion</td>
</tr>
</tbody>
</table>
## Installation and Usage
### npm
@ -174,13 +72,6 @@ const {
![](https://raw.githubusercontent.com/zrwusa/assets/master/images/data-structure-typed/examples/videos/webp_output/directed-graph-test.webp)
![](https://raw.githubusercontent.com/zrwusa/assets/master/images/data-structure-typed/examples/videos/webp_output/map-graph-test.webp)
## API docs & Examples
[API Docs](https://data-structure-typed-docs.vercel.app)
[Live Examples](https://vivid-algorithm.vercel.app)
<a href="https://github.com/zrwusa/vivid-algorithm" target="_blank">Examples Repository</a>
## Code Snippets
@ -338,6 +229,115 @@ const dijkstraResult = graph.dijkstra('A');
Array.from(dijkstraResult?.seen ?? []).map(vertex => vertex.key) // ['A', 'B', 'D']
```
## Built-in classic algorithms
<table>
<thead>
<tr>
<th>Algorithm</th>
<th>Function Description</th>
<th>Iteration Type</th>
</tr>
</thead>
<tbody>
<tr>
<td>Binary Tree DFS</td>
<td>Traverse a binary tree in a depth-first manner, starting from the root node, first visiting the left subtree,
and then the right subtree, using recursion.
</td>
<td>Recursion + Iteration</td>
</tr>
<tr>
<td>Binary Tree BFS</td>
<td>Traverse a binary tree in a breadth-first manner, starting from the root node, visiting nodes level by level
from left to right.
</td>
<td>Iteration</td>
</tr>
<tr>
<td>Graph DFS</td>
<td>Traverse a graph in a depth-first manner, starting from a given node, exploring along one path as deeply as
possible, and backtracking to explore other paths. Used for finding connected components, paths, etc.
</td>
<td>Recursion + Iteration</td>
</tr>
<tr>
<td>Binary Tree Morris</td>
<td>Morris traversal is an in-order traversal algorithm for binary trees with O(1) space complexity. It allows tree
traversal without additional stack or recursion.
</td>
<td>Iteration</td>
</tr>
<tr>
<td>Graph BFS</td>
<td>Traverse a graph in a breadth-first manner, starting from a given node, first visiting nodes directly connected
to the starting node, and then expanding level by level. Used for finding shortest paths, etc.
</td>
<td>Recursion + Iteration</td>
</tr>
<tr>
<td>Graph Tarjan's Algorithm</td>
<td>Find strongly connected components in a graph, typically implemented using depth-first search.</td>
<td>Recursion</td>
</tr>
<tr>
<td>Graph Bellman-Ford Algorithm</td>
<td>Finding the shortest paths from a single source, can handle negative weight edges</td>
<td>Iteration</td>
</tr>
<tr>
<td>Graph Dijkstra's Algorithm</td>
<td>Finding the shortest paths from a single source, cannot handle negative weight edges</td>
<td>Iteration</td>
</tr>
<tr>
<td>Graph Floyd-Warshall Algorithm</td>
<td>Finding the shortest paths between all pairs of nodes</td>
<td>Iteration</td>
</tr>
<tr>
<td>Graph getCycles</td>
<td>Find all cycles in a graph or detect the presence of cycles.</td>
<td>Recursion</td>
</tr>
<tr>
<td>Graph getCutVertexes</td>
<td>Find cut vertices in a graph, which are nodes that, when removed, increase the number of connected components in
the graph.
</td>
<td>Recursion</td>
</tr>
<tr>
<td>Graph getSCCs</td>
<td>Find strongly connected components in a graph, which are subgraphs where any two nodes can reach each other.
</td>
<td>Recursion</td>
</tr>
<tr>
<td>Graph getBridges</td>
<td>Find bridges in a graph, which are edges that, when removed, increase the number of connected components in the
graph.
</td>
<td>Recursion</td>
</tr>
<tr>
<td>Graph topologicalSort</td>
<td>Perform topological sorting on a directed acyclic graph (DAG) to find a linear order of nodes such that all
directed edges go from earlier nodes to later nodes.
</td>
<td>Recursion</td>
</tr>
</tbody>
</table>
## API docs & Examples
[API Docs](https://data-structure-typed-docs.vercel.app)
[Live Examples](https://vivid-algorithm.vercel.app)
<a href="https://github.com/zrwusa/vivid-algorithm" target="_blank">Examples Repository</a>
## Data Structures
<table>
@ -376,7 +376,7 @@ Array.from(dijkstraResult?.seen ?? []).map(vertex => vertex.key) // ['A', 'B', '
<td>Red Black Tree</td>
<td><img src="https://raw.githubusercontent.com/zrwusa/assets/master/images/data-structure-typed/assets/tick.svg" alt=""></td>
<td><img src="https://raw.githubusercontent.com/zrwusa/assets/master/images/data-structure-typed/assets/tick.svg" alt=""></td>
<td><a href="https://data-structure-typed-docs.vercel.app/classes/RedBlackTree.html"><span>AVLTree</span></a></td>
<td><a href="https://data-structure-typed-docs.vercel.app/classes/RedBlackTree.html"><span>RedBlackTree</span></a></td>
<td><img src="https://raw.githubusercontent.com/zrwusa/assets/master/images/data-structure-typed/assets/tick.svg" alt=""></td>
</tr>
<tr>
@ -728,40 +728,40 @@ optimal approach to data structure design.
[//]: # (No deletion!!! Start of Replace Section)
<div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>avl-tree</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 add randomly</td><td>30.52</td><td>32.76</td><td>3.28e-4</td></tr><tr><td>10,000 add & delete randomly</td><td>66.96</td><td>14.94</td><td>0.00</td></tr><tr><td>10,000 addMany</td><td>39.78</td><td>25.14</td><td>3.67e-4</td></tr><tr><td>10,000 get</td><td>27.38</td><td>36.52</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>10,000 add randomly</td><td>31.95</td><td>31.30</td><td>2.69e-4</td></tr><tr><td>10,000 add & delete randomly</td><td>69.18</td><td>14.45</td><td>8.01e-4</td></tr><tr><td>10,000 addMany</td><td>41.62</td><td>24.03</td><td>2.25e-4</td></tr><tr><td>10,000 get</td><td>27.67</td><td>36.13</td><td>1.96e-4</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>binary-tree</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000 add randomly</td><td>10.50</td><td>95.20</td><td>2.30e-4</td></tr><tr><td>1,000 add & delete randomly</td><td>16.18</td><td>61.81</td><td>2.48e-4</td></tr><tr><td>1,000 addMany</td><td>10.80</td><td>92.62</td><td>1.83e-4</td></tr><tr><td>1,000 get</td><td>18.03</td><td>55.45</td><td>1.41e-4</td></tr><tr><td>1,000 dfs</td><td>157.86</td><td>6.33</td><td>0.00</td></tr><tr><td>1,000 bfs</td><td>56.68</td><td>17.64</td><td>0.00</td></tr><tr><td>1,000 morris</td><td>37.21</td><td>26.88</td><td>2.79e-4</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000 add randomly</td><td>12.29</td><td>81.38</td><td>9.60e-5</td></tr><tr><td>1,000 add & delete randomly</td><td>15.60</td><td>64.11</td><td>1.04e-4</td></tr><tr><td>1,000 addMany</td><td>10.30</td><td>97.04</td><td>9.16e-5</td></tr><tr><td>1,000 get</td><td>18.02</td><td>55.50</td><td>2.21e-4</td></tr><tr><td>1,000 dfs</td><td>175.42</td><td>5.70</td><td>0.00</td></tr><tr><td>1,000 bfs</td><td>55.71</td><td>17.95</td><td>2.56e-4</td></tr><tr><td>1,000 morris</td><td>38.29</td><td>26.11</td><td>2.10e-4</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>bst</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 add randomly</td><td>27.61</td><td>36.21</td><td>4.73e-4</td></tr><tr><td>10,000 add & delete randomly</td><td>62.93</td><td>15.89</td><td>5.86e-4</td></tr><tr><td>10,000 addMany</td><td>28.70</td><td>34.84</td><td>0.00</td></tr><tr><td>10,000 get</td><td>27.67</td><td>36.14</td><td>2.92e-4</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 add randomly</td><td>30.55</td><td>32.73</td><td>2.83e-4</td></tr><tr><td>10,000 add & delete randomly</td><td>69.22</td><td>14.45</td><td>7.57e-4</td></tr><tr><td>10,000 addMany</td><td>29.52</td><td>33.88</td><td>3.69e-4</td></tr><tr><td>10,000 get</td><td>28.71</td><td>34.83</td><td>2.69e-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 randomly</td><td>87.51</td><td>11.43</td><td>0.01</td></tr><tr><td>100,000 add & delete randomly</td><td>189.06</td><td>5.29</td><td>0.01</td></tr><tr><td>100,000 getNode</td><td>35.33</td><td>28.31</td><td>8.93e-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 randomly</td><td>85.63</td><td>11.68</td><td>0.00</td></tr><tr><td>100,000 add & delete randomly</td><td>181.31</td><td>5.52</td><td>0.01</td></tr><tr><td>100,000 getNode</td><td>91.77</td><td>10.90</td><td>5.02e-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>9899.91</td><td>8.58e-7</td></tr><tr><td>1,000 addEdge</td><td>6.06</td><td>165.02</td><td>1.68e-4</td></tr><tr><td>1,000 getVertex</td><td>0.05</td><td>2.17e+4</td><td>4.22e-7</td></tr><tr><td>1,000 getEdge</td><td>23.05</td><td>43.38</td><td>0.00</td></tr><tr><td>tarjan</td><td>222.59</td><td>4.49</td><td>0.01</td></tr><tr><td>tarjan all</td><td>226.89</td><td>4.41</td><td>0.01</td></tr><tr><td>topologicalSort</td><td>187.34</td><td>5.34</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>9889.32</td><td>1.21e-6</td></tr><tr><td>1,000 addEdge</td><td>5.97</td><td>167.63</td><td>1.09e-4</td></tr><tr><td>1,000 getVertex</td><td>0.05</td><td>2.17e+4</td><td>4.36e-7</td></tr><tr><td>1,000 getEdge</td><td>23.73</td><td>42.14</td><td>0.00</td></tr><tr><td>tarjan</td><td>225.10</td><td>4.44</td><td>0.01</td></tr><tr><td>tarjan all</td><td>233.47</td><td>4.28</td><td>0.02</td></tr><tr><td>topologicalSort</td><td>183.96</td><td>5.44</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'>heap</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 add & pop</td><td>4.66</td><td>214.54</td><td>9.38e-5</td></tr><tr><td>10,000 fib add & pop</td><td>364.30</td><td>2.74</td><td>0.01</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 add & pop</td><td>4.61</td><td>216.99</td><td>4.19e-5</td></tr><tr><td>10,000 fib add & pop</td><td>354.79</td><td>2.82</td><td>0.00</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>doubly-linked-list</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 unshift</td><td>243.61</td><td>4.10</td><td>0.07</td></tr><tr><td>1,000,000 unshift & shift</td><td>173.32</td><td>5.77</td><td>0.03</td></tr><tr><td>1,000,000 insertBefore</td><td>315.86</td><td>3.17</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 unshift</td><td>210.07</td><td>4.76</td><td>0.03</td></tr><tr><td>1,000,000 unshift & shift</td><td>174.44</td><td>5.73</td><td>0.04</td></tr><tr><td>1,000,000 insertBefore</td><td>355.36</td><td>2.81</td><td>0.10</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>singly-linked-list</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 push & pop</td><td>228.06</td><td>4.38</td><td>0.03</td></tr><tr><td>10,000 insertBefore</td><td>252.07</td><td>3.97</td><td>0.01</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 push & pop</td><td>220.47</td><td>4.54</td><td>0.01</td></tr><tr><td>10,000 insertBefore</td><td>252.59</td><td>3.96</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'>max-priority-queue</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 refill & poll</td><td>11.53</td><td>86.71</td><td>2.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>10,000 refill & poll</td><td>11.72</td><td>85.32</td><td>2.97e-4</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>deque</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 push</td><td>227.24</td><td>4.40</td><td>0.07</td></tr><tr><td>1,000,000 shift</td><td>25.60</td><td>39.07</td><td>0.00</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 push</td><td>233.90</td><td>4.28</td><td>0.07</td></tr><tr><td>1,000,000 shift</td><td>25.40</td><td>39.37</td><td>0.00</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>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>45.98</td><td>21.75</td><td>0.01</td></tr><tr><td>1,000,000 push & shift</td><td>81.12</td><td>12.33</td><td>0.00</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 push</td><td>43.54</td><td>22.97</td><td>0.00</td></tr><tr><td>1,000,000 push & shift</td><td>83.99</td><td>11.91</td><td>0.00</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>trie</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>100,000 push</td><td>59.40</td><td>16.83</td><td>0.01</td></tr><tr><td>100,000 getWords</td><td>90.07</td><td>11.10</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 push</td><td>49.17</td><td>20.34</td><td>0.01</td></tr><tr><td>100,000 getWords</td><td>88.84</td><td>11.26</td><td>0.01</td></tr></table></div>
</div>
[//]: # (No deletion!!! End of Replace Section)

View file

@ -6,7 +6,7 @@
* @license MIT License
*/
import {BST, BSTNode} from './bst';
import type {AVLTreeNodeNested, AVLTreeOptions, BinaryTreeDeletedResult, BTNKey} from '../../types';
import type {AVLTreeNodeNested, AVLTreeOptions, BiTreeDeleteResult, BTNKey} from '../../types';
import {BTNCallback} from '../../types';
import {IBinaryTree} from '../../interfaces';
@ -72,12 +72,12 @@ export class AVLTree<V = any, N extends AVLTreeNode<V, N> = AVLTreeNode<V, AVLTr
* value. This value is compared with the `identifier` parameter to determine if the node should be
* included in the result. The `callback` parameter has a default value of
* `this.defaultOneParamCallback`
* @returns The method is returning an array of `BinaryTreeDeletedResult<N>` objects.
* @returns The method is returning an array of `BiTreeDeleteResult<N>` objects.
*/
override delete<C extends BTNCallback<N>>(
identifier: ReturnType<C>,
callback: C = this.defaultOneParamCallback as C
): BinaryTreeDeletedResult<N>[] {
): BiTreeDeleteResult<N>[] {
if ((identifier as any) instanceof AVLTreeNode) callback = (node => node) as C;
const deletedResults = super.delete(identifier, callback);
for (const {needBalanced} of deletedResults) {
@ -96,23 +96,29 @@ export class AVLTree<V = any, N extends AVLTreeNode<V, N> = AVLTreeNode<V, AVLTr
* from the source node (`srcNode`) will be swapped to.
* @returns The method is returning the `destNode` after swapping its properties with the `srcNode`.
*/
protected override _swap(srcNode: N, destNode: N): N {
const {key, value, height} = destNode;
const tempNode = this.createNode(key, value);
protected override _swap(srcNode: BTNKey | N | undefined, destNode: BTNKey | N | undefined): N | undefined {
if (this.isNodeKey(srcNode)) srcNode = this._getNodeByKey(srcNode);
if (this.isNodeKey(destNode)) destNode = this._getNodeByKey(destNode);
if (tempNode) {
tempNode.height = height;
if (srcNode && destNode) {
const {key, value, height} = destNode;
const tempNode = this.createNode(key, value);
destNode.key = srcNode.key;
destNode.value = srcNode.value;
destNode.height = srcNode.height;
if (tempNode) {
tempNode.height = height;
srcNode.key = tempNode.key;
srcNode.value = tempNode.value;
srcNode.height = tempNode.height;
destNode.key = srcNode.key;
destNode.value = srcNode.value;
destNode.height = srcNode.height;
srcNode.key = tempNode.key;
srcNode.value = tempNode.value;
srcNode.height = tempNode.height;
}
return destNode;
}
return destNode;
return undefined;
}
/**

View file

@ -7,7 +7,7 @@
*/
import type {BinaryTreeNodeNested, BinaryTreeOptions, BTNCallback, BTNKey} from '../../types';
import {BinaryTreeDeletedResult, DFSOrderPattern, FamilyPosition, IterationType} from '../../types';
import {BiTreeDeleteResult, CP, DFSOrderPattern, FamilyPosition, IterationType} from '../../types';
import {IBinaryTree} from '../../interfaces';
import {trampoline} from '../../utils';
import {Queue} from '../queue';
@ -117,7 +117,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @param {BinaryTreeOptions} [options] - The options for the binary tree.
*/
constructor(options?: BinaryTreeOptions) {
if (options !== undefined) {
if (options) {
const {iterationType = IterationType.ITERATIVE} = options;
this.iterationType = iterationType;
}
@ -192,7 +192,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return;
};
let inserted: N | null | undefined, needInsert: N | null;
let inserted: N | null | undefined, needInsert: N | null | undefined;
if (keyOrNode === null) {
needInsert = null;
@ -204,19 +204,11 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return;
}
// const key = typeof keyOrNode === 'number' ? keyOrNode : keyOrNode ? keyOrNode.key : undefined;
// const existNode = key !== undefined ? this.getNode(key, (node: N) => node.key) : undefined;
if (this.root) {
// if (existNode) {
// existNode.value = value;
// inserted = existNode;
// } else {
inserted = _bfs(this.root, needInsert);
// }
} else {
this._setRoot(needInsert);
if (needInsert !== null) {
if (needInsert) {
this._size = 1;
} else {
this._size = 0;
@ -236,7 +228,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* the value of the nodes will be `undefined`.
* @returns The function `addMany` returns an array of `N`, `null`, or `undefined` values.
*/
addMany(keysOrNodes: (BTNKey | null | undefined)[] | (N | null | undefined)[], values?: V[]): (N | null | undefined)[] {
addMany(keysOrNodes: (BTNKey | N |null | undefined)[], values?: (V | undefined)[]): (N | null | undefined)[] {
// TODO not sure addMany not be run multi times
return keysOrNodes.map((keyOrNode, i) => {
if (keyOrNode instanceof BinaryTreeNode) {
@ -256,28 +248,28 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* The `refill` function clears the binary tree and adds multiple nodes with the given IDs or nodes and optional data.
* @param {(BTNKey | N)[]} keysOrNodes - The `keysOrNodes` parameter is an array that can contain either
* `BTNKey` or `N` values.
* @param {N[] | Array<V>} [data] - The `data` parameter is an optional array of values that will be assigned to
* @param {N[] | Array<V>} [values] - The `data` parameter is an optional array of values that will be assigned to
* the nodes being added. If provided, the length of the `data` array should be equal to the length of the `keysOrNodes`
* array. Each value in the `data` array will be assigned to the
* @returns The method is returning a boolean value.
*/
refill(keysOrNodes: (BTNKey | null | undefined)[] | (N | null | undefined)[], data?: Array<V>): boolean {
refill(keysOrNodes: (BTNKey | null | undefined)[] | (N | null | undefined)[], values?: Array<V | undefined>): boolean {
this.clear();
return keysOrNodes.length === this.addMany(keysOrNodes, data).length;
return keysOrNodes.length === this.addMany(keysOrNodes, values).length;
}
delete<C extends BTNCallback<N, BTNKey>>(identifier: BTNKey, callback?: C): BinaryTreeDeletedResult<N>[];
delete<C extends BTNCallback<N, BTNKey>>(identifier: BTNKey, callback?: C): BiTreeDeleteResult<N>[];
delete<C extends BTNCallback<N, N>>(identifier: N | null | undefined, callback?: C): BinaryTreeDeletedResult<N>[];
delete<C extends BTNCallback<N, N>>(identifier: N | null | undefined, callback?: C): BiTreeDeleteResult<N>[];
delete<C extends BTNCallback<N>>(identifier: ReturnType<C>, callback: C): BinaryTreeDeletedResult<N>[];
delete<C extends BTNCallback<N>>(identifier: ReturnType<C>, callback: C): BiTreeDeleteResult<N>[];
/**
* The `delete` function removes a node from a binary search tree and returns the deleted node along
* with the parent node that needs to be balanced.
* a key (`BTNKey`). If it is a key, the function will find the corresponding node in the
* binary tree.
* @returns an array of `BinaryTreeDeletedResult<N>` objects.
* @returns an array of `BiTreeDeleteResult<N>` objects.
* @param {ReturnType<C>} identifier - The `identifier` parameter is either a
* `BTNKey` or a generic type `N`. It represents the property of the node that we are
* searching for. It can be a specific key value or any other property of the node.
@ -289,17 +281,17 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
delete<C extends BTNCallback<N>>(
identifier: ReturnType<C> | null | undefined,
callback: C = this.defaultOneParamCallback as C
): BinaryTreeDeletedResult<N>[] {
const bstDeletedResult: BinaryTreeDeletedResult<N>[] = [];
if (!this.root) return bstDeletedResult;
): BiTreeDeleteResult<N>[] {
const deleteResult: BiTreeDeleteResult<N>[] = [];
if (!this.root) return deleteResult;
if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C;
const curr = this.getNode(identifier, callback);
if (!curr) return bstDeletedResult;
if (!curr) return deleteResult;
const parent: N | null | undefined = curr?.parent ? curr.parent : null;
let needBalanced: N | null | undefined = null,
orgCurrent = curr;
let needBalanced: N | null | undefined = undefined;
let orgCurrent: N | undefined = curr;
if (!curr.left) {
if (!parent) {
@ -329,8 +321,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
}
this._size = this.size - 1;
bstDeletedResult.push({deleted: orgCurrent, needBalanced});
return bstDeletedResult;
deleteResult.push({deleted: orgCurrent, needBalanced});
return deleteResult;
}
/**
@ -347,7 +339,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
*/
getDepth(distNode: BTNKey | N | null | undefined, beginRoot: BTNKey | N | null | undefined = this.root): number {
if (typeof distNode === 'number') distNode = this.getNode(distNode);
if (typeof beginRoot === 'number') beginRoot = this.getNode(beginRoot);
if (this.isNodeKey(beginRoot)) beginRoot = this._getNodeByKey(beginRoot);
let depth = 0;
while (distNode?.parent) {
if (distNode === beginRoot) {
@ -372,7 +364,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @returns the height of the binary tree.
*/
getHeight(beginRoot: BTNKey | N | null | undefined = this.root, iterationType = this.iterationType): number {
if (typeof beginRoot === 'number') beginRoot = this.getNode(beginRoot);
if (this.isNodeKey(beginRoot)) beginRoot = this._getNodeByKey(beginRoot);
if (!beginRoot) return -1;
if (iterationType === IterationType.RECURSIVE) {
@ -420,9 +412,11 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* to calculate the minimum height of a binary tree. It can have two possible values:
* @returns The function `getMinHeight` returns the minimum height of a binary tree.
*/
getMinHeight(beginRoot: N | null | undefined = this.root, iterationType = this.iterationType): number {
getMinHeight(beginRoot: BTNKey | N | null | undefined = this.root, iterationType = this.iterationType): number {
if (!beginRoot) return -1;
if (this.isNodeKey(beginRoot)) beginRoot = this._getNodeByKey(beginRoot);
if (!beginRoot) return -1;
if (iterationType === IterationType.RECURSIVE) {
const _getMinHeight = (cur: N | null | undefined): number => {
if (!cur) return 0;
@ -469,7 +463,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* either be of type `N` (representing a node in a tree) or `null` (representing an empty tree).
* @returns The method is returning a boolean value.
*/
isPerfectlyBalanced(beginRoot: N | null | undefined = this.root): boolean {
isPerfectlyBalanced(beginRoot: BTNKey | N | null | undefined = this.root): boolean {
return this.getMinHeight(beginRoot) + 1 >= this.getHeight(beginRoot);
}
@ -477,7 +471,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
identifier: BTNKey,
callback?: C,
onlyOne?: boolean,
beginRoot?: N | null | undefined,
beginRoot?: BTNKey | N | null | undefined,
iterationType?: IterationType
): N[];
@ -485,7 +479,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
identifier: N | null | undefined,
callback?: C,
onlyOne?: boolean,
beginRoot?: N | null | undefined,
beginRoot?: BTNKey | N | null | undefined,
iterationType?: IterationType
): N[];
@ -493,7 +487,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
identifier: ReturnType<C>,
callback: C,
onlyOne?: boolean,
beginRoot?: N | null | undefined,
beginRoot?: BTNKey | N | null | undefined,
iterationType?: IterationType
): N[];
@ -522,11 +516,14 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
identifier: ReturnType<C> | null | undefined,
callback: C = this.defaultOneParamCallback as C,
onlyOne = false,
beginRoot: N | null | undefined = this.root,
beginRoot: BTNKey | N | null | undefined = this.root,
iterationType = this.iterationType
): N[] {
if (!beginRoot) return [];
if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C;
if (this.isNodeKey(beginRoot)) beginRoot = this._getNodeByKey(beginRoot);
if (!beginRoot) return [];
const ans: N[] = [];
if (iterationType === IterationType.RECURSIVE) {
@ -562,21 +559,21 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
has<C extends BTNCallback<N, BTNKey>>(
identifier: BTNKey,
callback?: C,
beginRoot?: N | null | undefined,
beginRoot?: BTNKey | N | null | undefined,
iterationType?: IterationType
): boolean;
has<C extends BTNCallback<N, N>>(
identifier: N | null | undefined,
callback?: C,
beginRoot?: N | null | undefined,
beginRoot?: BTNKey | N | null | undefined,
iterationType?: IterationType
): boolean;
has<C extends BTNCallback<N>>(
identifier: ReturnType<C> | null | undefined,
callback: C,
beginRoot?: N | null | undefined,
beginRoot?: BTNKey | N | null | undefined,
iterationType?: IterationType
): boolean;
@ -600,7 +597,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
has<C extends BTNCallback<N>>(
identifier: ReturnType<C> | null | undefined,
callback: C = this.defaultOneParamCallback as C,
beginRoot = this.root,
beginRoot: BTNKey | N | null | undefined = this.root,
iterationType = this.iterationType
): boolean {
if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C;
@ -611,21 +608,21 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
getNode<C extends BTNCallback<N, BTNKey>>(
identifier: BTNKey,
callback?: C,
beginRoot?: N | null | undefined,
beginRoot?: BTNKey | N | null | undefined,
iterationType?: IterationType
): N | null | undefined;
getNode<C extends BTNCallback<N, N>>(
identifier: N | null | undefined,
callback?: C,
beginRoot?: N | null | undefined,
beginRoot?: BTNKey | N | null | undefined,
iterationType?: IterationType
): N | null | undefined;
getNode<C extends BTNCallback<N>>(
identifier: ReturnType<C>,
callback: C,
beginRoot?: N | null | undefined,
beginRoot?: BTNKey | N | null | undefined,
iterationType?: IterationType
): N | null | undefined;
@ -647,7 +644,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
getNode<C extends BTNCallback<N>>(
identifier: ReturnType<C> | null | undefined,
callback: C = this.defaultOneParamCallback as C,
beginRoot = this.root,
beginRoot: BTNKey | N | null | undefined = this.root,
iterationType = this.iterationType
): N | null | undefined {
if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C;
@ -655,24 +652,49 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return this.getNodes(identifier, callback, true, beginRoot, iterationType)[0] ?? null;
}
protected _getNodeByKey(key: BTNKey, iterationType = IterationType.ITERATIVE): N | undefined {
if (!this.root) return undefined;
if (iterationType === IterationType.RECURSIVE) {
const _dfs = (cur: N): N | undefined => {
if (cur.key === key) return cur;
if (!cur.left && !cur.right) return;
if (cur.left) return _dfs(cur.left);
if (cur.right) return _dfs(cur.right);
};
return _dfs(this.root);
} else {
const queue = new Queue<N>([this.root]);
while (queue.size > 0) {
const cur = queue.shift();
if (cur) {
if (cur.key === key) return cur;
cur.left && queue.push(cur.left);
cur.right && queue.push(cur.right);
}
}
}
}
get<C extends BTNCallback<N, BTNKey>>(
identifier: BTNKey,
callback?: C,
beginRoot?: N | null | undefined,
beginRoot?: BTNKey | N | null | undefined,
iterationType?: IterationType
): V | undefined;
get<C extends BTNCallback<N, N>>(
identifier: N | null | undefined,
callback?: C,
beginRoot?: N | null | undefined,
beginRoot?: BTNKey | N | null | undefined,
iterationType?: IterationType
): V | undefined;
get<C extends BTNCallback<N>>(
identifier: ReturnType<C>,
callback: C,
beginRoot?: N | null | undefined,
beginRoot?: BTNKey | N | null | undefined,
iterationType?: IterationType
): V | undefined;
@ -694,14 +716,14 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
get<C extends BTNCallback<N>>(
identifier: ReturnType<C> | null | undefined,
callback: C = this.defaultOneParamCallback as C,
beginRoot = this.root,
beginRoot:BTNKey | N | null | undefined = this.root,
iterationType = this.iterationType
): V | undefined {
if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C;
return this.getNode(identifier, callback, beginRoot, iterationType)?.value ?? undefined;
}
/**
* The function `getPathToRoot` returns an array of nodes starting from a given node and traversing
* up to the root node, with the option to reverse the order of the nodes.
@ -712,9 +734,13 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* reversed before returning it. If `isReverse` is set to `false` or not provided, the path will
* @returns The function `getPathToRoot` returns an array of type `N[]`.
*/
getPathToRoot(beginRoot: N, isReverse = true): N[] {
getPathToRoot(beginRoot: BTNKey | N | null | undefined, isReverse = true): N[] {
// TODO to support get path through passing key
const result: N[] = [];
if (this.isNodeKey(beginRoot)) beginRoot = this._getNodeByKey(beginRoot);
if (!beginRoot) return result;
while (beginRoot.parent) {
// Array.push + Array.reverse is more efficient than Array.unshift
// TODO may consider using Deque, so far this is not the performance bottleneck
@ -737,7 +763,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* no leftmost node, it returns `null`.
*/
getLeftMost(beginRoot: BTNKey | N | null | undefined = this.root, iterationType = this.iterationType): N | null | undefined {
if (typeof beginRoot === 'number') beginRoot = this.getNode(beginRoot);
if (this.isNodeKey(beginRoot)) beginRoot = this._getNodeByKey(beginRoot);
if (!beginRoot) return beginRoot;
@ -770,8 +796,9 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @returns The function `getRightMost` returns the rightmost node (`N`) in a binary tree. If the
* `beginRoot` parameter is `null`, it returns `null`.
*/
getRightMost(beginRoot: N | null | undefined = this.root, iterationType = this.iterationType): N | null | undefined {
getRightMost(beginRoot: BTNKey | N | null | undefined = this.root, iterationType = this.iterationType): N | null | undefined {
// TODO support get right most by passing key in
if (this.isNodeKey(beginRoot)) beginRoot = this._getNodeByKey(beginRoot);
if (!beginRoot) return beginRoot;
if (iterationType === IterationType.RECURSIVE) {
@ -801,8 +828,9 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* possible values:
* @returns The function `isSubtreeBST` returns a boolean value.
*/
isSubtreeBST(beginRoot: N | null | undefined, iterationType = this.iterationType): boolean {
isSubtreeBST(beginRoot: BTNKey | N | null | undefined, iterationType = this.iterationType): boolean {
// TODO there is a bug
if (this.isNodeKey(beginRoot)) beginRoot = this._getNodeByKey(beginRoot);
if (!beginRoot) return true;
if (iterationType === IterationType.RECURSIVE) {
@ -886,7 +914,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
iterationType = this.iterationType,
includeNull = false
): ReturnType<C>[] {
if (typeof beginRoot === 'number') beginRoot = this.getNode(beginRoot);
if (this.isNodeKey(beginRoot)) beginRoot = this._getNodeByKey(beginRoot);
const ans: (ReturnType<BTNCallback<N>> | null | undefined)[] = [];
if (!beginRoot) return ans;
@ -938,10 +966,14 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return this.isNode(node) || node === null;
}
isNodeKey(potentialKey: any) : potentialKey is number {
return typeof potentialKey === 'number';
}
dfs<C extends BTNCallback<N>>(
callback?: C,
pattern?: DFSOrderPattern,
beginRoot?: N | null | undefined,
beginRoot?: BTNKey | N | null | undefined,
iterationType?: IterationType,
includeNull?: false
): ReturnType<C>[];
@ -949,7 +981,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
dfs<C extends BTNCallback<N>>(
callback?: C,
pattern?: DFSOrderPattern,
beginRoot?: N | null | undefined,
beginRoot?: BTNKey | N | null | undefined,
iterationType?: IterationType,
includeNull?: undefined
): ReturnType<C>[];
@ -957,7 +989,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
dfs<C extends BTNCallback<N | null | undefined>>(
callback?: C,
pattern?: DFSOrderPattern,
beginRoot?: N | null | undefined,
beginRoot?: BTNKey | N | null | undefined,
iterationType?: IterationType,
includeNull?: true
): ReturnType<C>[];
@ -981,10 +1013,12 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
dfs<C extends BTNCallback<N | null | undefined>>(
callback: C = this.defaultOneParamCallback as C,
pattern: DFSOrderPattern = 'in',
beginRoot: N | null | undefined = this.root,
beginRoot: BTNKey | N | null | undefined = this.root,
iterationType: IterationType = IterationType.ITERATIVE,
includeNull = false
): ReturnType<C>[] {
if (this.isNodeKey(beginRoot)) beginRoot = this._getNodeByKey(beginRoot);
if (!beginRoot) return [];
const ans: ReturnType<C>[] = [];
if (iterationType === IterationType.RECURSIVE) {
@ -1074,21 +1108,21 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
bfs<C extends BTNCallback<N>>(
callback?: C,
beginRoot?: N | null | undefined,
beginRoot?: BTNKey | N | null | undefined,
iterationType?: IterationType,
includeNull?: false
): ReturnType<C>[];
bfs<C extends BTNCallback<N>>(
callback?: C,
beginRoot?: N | null | undefined,
beginRoot?: BTNKey | N | null | undefined,
iterationType?: IterationType,
includeNull?: undefined
): ReturnType<C>[];
bfs<C extends BTNCallback<N | null | undefined>>(
callback?: C,
beginRoot?: N | null | undefined,
beginRoot?: BTNKey | N | null | undefined,
iterationType?: IterationType,
includeNull?: true
): ReturnType<C>[];
@ -1109,10 +1143,11 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
*/
bfs<C extends BTNCallback<N | null | undefined>>(
callback: C = this.defaultOneParamCallback as C,
beginRoot: N | null | undefined = this.root,
beginRoot: BTNKey | N | null | undefined = this.root,
iterationType = this.iterationType,
includeNull = false
): ReturnType<C>[] {
if (this.isNodeKey(beginRoot)) beginRoot = this._getNodeByKey(beginRoot);
if (!beginRoot) return [];
const ans: ReturnType<BTNCallback<N>>[] = [];
@ -1162,21 +1197,21 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
listLevels<C extends BTNCallback<N>>(
callback?: C,
beginRoot?: N | null | undefined,
beginRoot?: BTNKey | N | null | undefined,
iterationType?: IterationType,
includeNull?: false
): ReturnType<C>[][];
listLevels<C extends BTNCallback<N>>(
callback?: C,
beginRoot?: N | null | undefined,
beginRoot?: BTNKey | N | null | undefined,
iterationType?: IterationType,
includeNull?: undefined
): ReturnType<C>[][];
listLevels<C extends BTNCallback<N | null | undefined>>(
callback?: C,
beginRoot?: N | null | undefined,
beginRoot?: BTNKey | N | null | undefined,
iterationType?: IterationType,
includeNull?: true
): ReturnType<C>[][];
@ -1199,10 +1234,11 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
*/
listLevels<C extends BTNCallback<N | null | undefined>>(
callback: C = this.defaultOneParamCallback as C,
beginRoot: N | null | undefined = this.root,
beginRoot: BTNKey | N | null | undefined = this.root,
iterationType = this.iterationType,
includeNull = false
): ReturnType<C>[][] {
if (this.isNodeKey(beginRoot)) beginRoot = this._getNodeByKey(beginRoot);
if (!beginRoot) return [];
const levelsNodes: ReturnType<C>[][] = [];
@ -1243,12 +1279,17 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return levelsNodes;
}
getPredecessor(node: N ): N
/**
* The function returns the predecessor node of a given node in a binary tree.
* @param {N} node - The parameter "node" represents a node in a binary tree.
* @returns The function `getPredecessor` returns the predecessor node of the given node `node`.
*/
getPredecessor(node: N): N {
getPredecessor(node: BTNKey | N | null | undefined): N | undefined{
if (this.isNodeKey(node)) node = this.getNode(node);
if (!node) return undefined;
if (node.left) {
let predecessor: N | null | undefined = node.left;
while (!predecessor || (predecessor.right && predecessor.right !== node)) {
@ -1269,7 +1310,10 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @returns The function `getSuccessor` returns a value of type `N` (the successor node), or `null`
* if there is no successor, or `undefined` if the input `x` is `undefined`.
*/
getSuccessor(x: N): N | null | undefined {
getSuccessor(x: BTNKey | N | null | undefined): N | null | undefined {
if (this.isNodeKey(x)) x = this.getNode(x);
if (!x) return undefined;
if (x.right) {
return this.getLeftMost(x.right);
}
@ -1299,8 +1343,9 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
morris<C extends BTNCallback<N>>(
callback: C = this.defaultOneParamCallback as C,
pattern: DFSOrderPattern = 'in',
beginRoot: N | null | undefined = this.root
beginRoot: BTNKey | N | null | undefined = this.root
): ReturnType<C>[] {
if (this.isNodeKey(beginRoot)) beginRoot = this._getNodeByKey(beginRoot);
if (beginRoot === null) return [];
const ans: ReturnType<BTNCallback<N>>[] = [];
@ -1433,19 +1478,26 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @param {N} destNode - The destination node to swap.
* @returns {N} - The destination node after the swap.
*/
protected _swap(srcNode: N, destNode: N): N {
const {key, value} = destNode;
const tempNode = this.createNode(key, value);
protected _swap(srcNode: BTNKey | N | null | undefined, destNode:BTNKey | N | null | undefined): N | undefined{
if (this.isNodeKey(srcNode)) srcNode = this._getNodeByKey(srcNode);
if (this.isNodeKey(destNode)) destNode = this._getNodeByKey(destNode);
if (tempNode) {
destNode.key = srcNode.key;
destNode.value = srcNode.value;
if (srcNode && destNode) {
const {key, value} = destNode;
const tempNode = this.createNode(key, value);
srcNode.key = tempNode.key;
srcNode.value = tempNode.value;
if (tempNode) {
destNode.key = srcNode.key;
destNode.value = srcNode.value;
srcNode.key = tempNode.key;
srcNode.value = tempNode.value;
}
return destNode;
}
return undefined;
return destNode;
}
/**
@ -1459,7 +1511,9 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* the binary tree. If neither the left nor right child is available, the function returns undefined.
* If the parent node is null, the function also returns undefined.
*/
protected _addTo(newNode: N | null | undefined, parent: N): N | null | undefined {
protected _addTo(newNode: N | null | undefined, parent: BTNKey | N | null | undefined): N | null | undefined {
if (this.isNodeKey(parent)) parent = this.getNode(parent);
if (parent) {
// When all leaf nodes are null, it will no longer be possible to add new entity nodes to this binary tree.
// In this scenario, null nodes serve as "sentinel nodes," "virtual nodes," or "placeholder nodes."

View file

@ -13,6 +13,7 @@ import {Queue} from '../queue';
export class BSTNode<V = any, N extends BSTNode<V, N> = BSTNodeNested<V>> extends BinaryTreeNode<V, N> {
override parent: N | undefined;
constructor(key: BTNKey, value?: V) {
super(key, value);
this.parent = undefined;
@ -64,8 +65,7 @@ export class BSTNode<V = any, N extends BSTNode<V, N> = BSTNodeNested<V>> extend
export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>>
extends BinaryTree<V, N>
implements IBinaryTree<V, N>
{
implements IBinaryTree<V, N> {
/**
* The constructor function initializes a binary search tree object with an optional comparator
* function.
@ -82,6 +82,7 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
}
}
}
protected override _root: N | undefined = undefined;
/**
@ -119,8 +120,8 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
}
if (keyOrNode === null) return undefined;
// TODO support node as a parameter
let inserted:N | undefined;
let newNode:N | undefined;
let inserted: N | undefined;
let newNode: N | undefined;
if (keyOrNode instanceof BSTNode) {
newNode = keyOrNode;
} else if (typeof keyOrNode === 'number') {
@ -198,13 +199,13 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
*/
override addMany(
keysOrNodes: (BTNKey | undefined)[] | (N | undefined)[],
data?: V[],
keysOrNodes: (BTNKey | N | undefined)[],
data?: (V | undefined)[],
isBalanceAdd = true,
iterationType = this.iterationType
): (N | undefined)[] {
// TODO this addMany function is inefficient, it should be optimized
function hasNoNull(arr: (BTNKey | undefined)[] | (N | undefined)[]): arr is BTNKey[] | N[] {
function hasNoNull(arr: (BTNKey | N | undefined)[]): arr is (BTNKey | N)[] {
return arr.indexOf(undefined) === -1;
}
@ -289,12 +290,37 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
* the key of the leftmost node if the comparison result is greater than, and the key of the
* rightmost node otherwise. If no node is found, it returns 0.
*/
lastKey(beginRoot: N | undefined = this.root, iterationType = this.iterationType): BTNKey {
lastKey(beginRoot: BTNKey | N | undefined = this.root, iterationType = this.iterationType): BTNKey {
if (this._compare(0, 1) === CP.lt) return this.getRightMost(beginRoot, iterationType)?.key ?? 0;
else if (this._compare(0, 1) === CP.gt) return this.getLeftMost(beginRoot, iterationType)?.key ?? 0;
else return this.getRightMost(beginRoot, iterationType)?.key ?? 0;
}
protected override _getNodeByKey(key: BTNKey, iterationType = IterationType.ITERATIVE): N | undefined {
if (!this.root) return undefined;
if (iterationType === IterationType.RECURSIVE) {
const _dfs = (cur: N): N | undefined => {
if (cur.key === key) return cur;
if (!cur.left && !cur.right) return;
if (this._compare(cur.key, key) === CP.gt && cur.left) return _dfs(cur.left);
if (this._compare(cur.key, key) === CP.lt && cur.right) return _dfs(cur.right);
};
return _dfs(this.root);
} else {
const queue = new Queue<N>([this.root]);
while (queue.size > 0) {
const cur = queue.shift();
if (cur) {
if (this._compare(cur.key, key) === CP.eq) return cur;
if (this._compare(cur.key, key) === CP.gt) cur.left && queue.push(cur.left);
if (this._compare(cur.key, key) === CP.lt) cur.right && queue.push(cur.right);
}
}
}
}
/**
* The function `getNodes` retrieves nodes from a binary tree based on a given node property or key,
* using either recursive or iterative traversal.
@ -320,9 +346,10 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
identifier: ReturnType<C> | undefined,
callback: C = this.defaultOneParamCallback as C,
onlyOne = false,
beginRoot: N | undefined = this.root,
beginRoot: BTNKey | N | undefined = this.root,
iterationType = this.iterationType
): N[] {
if (this.isNodeKey(beginRoot)) beginRoot = this._getNodeByKey(beginRoot);
if (!beginRoot) return [];
const ans: N[] = [];
@ -509,7 +536,7 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
} else {
const stack: N[] = [];
let node: N | undefined = this.root,
last:N | undefined = undefined;
last: N | undefined = undefined;
const depths: Map<N, number> = new Map();
while (stack.length > 0 || node) {

View file

@ -7,7 +7,7 @@
*/
import {
BinaryTreeDeletedResult,
BiTreeDeleteResult,
BTNCallback,
BTNKey,
IterationType,
@ -119,8 +119,8 @@ export class RedBlackTree<V = any, N extends RBTreeNode<V, N> = RBTreeNode<V, RB
delete<C extends BTNCallback<N>>(
identifier: ReturnType<C> | null | undefined,
callback: C = this.defaultOneParamCallback as C
): BinaryTreeDeletedResult<N>[] {
const ans: BinaryTreeDeletedResult<N>[] = [];
): BiTreeDeleteResult<N>[] {
const ans: BiTreeDeleteResult<N>[] = [];
if (identifier === null) return ans;
const helper = (node: N | undefined): void => {
let z: N = this.NIL;

View file

@ -6,7 +6,7 @@
* @license MIT License
*/
import type {BTNKey, TreeMultimapNodeNested, TreeMultimapOptions} from '../../types';
import {BinaryTreeDeletedResult, BTNCallback, CP, FamilyPosition, IterationType} from '../../types';
import {BiTreeDeleteResult, BTNCallback, CP, FamilyPosition, IterationType} from '../../types';
import {IBinaryTree} from '../../interfaces';
import {AVLTree, AVLTreeNode} from './avl-tree';
@ -274,14 +274,14 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
* being deleted. If set to true, the count of the node will not be considered and the node will be
* deleted regardless of its count. If set to false (default), the count of the node will be
* decremented by 1 and
* @returns The method `delete` returns an array of `BinaryTreeDeletedResult<N>` objects.
* @returns The method `delete` returns an array of `BiTreeDeleteResult<N>` objects.
*/
override delete<C extends BTNCallback<N>>(
identifier: ReturnType<C>,
callback: C = this.defaultOneParamCallback as C,
ignoreCount = false
): BinaryTreeDeletedResult<N>[] {
const bstDeletedResult: BinaryTreeDeletedResult<N>[] = [];
): BiTreeDeleteResult<N>[] {
const bstDeletedResult: BiTreeDeleteResult<N>[] = [];
if (!this.root) return bstDeletedResult;
const curr: N | undefined = this.getNode(identifier, callback) ?? undefined;

View file

@ -1,10 +1,10 @@
import {BinaryTreeNode} from '../data-structures';
import {BinaryTreeDeletedResult, BinaryTreeNodeNested, BTNCallback, BTNKey} from '../types';
import {BiTreeDeleteResult, BinaryTreeNodeNested, BTNCallback, BTNKey} from '../types';
export interface IBinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNodeNested<V>> {
createNode(key: BTNKey, value?: N['value']): N;
add(keyOrNode: BTNKey | N | null, value?: N['value']): N | null | undefined;
delete<C extends BTNCallback<N>>(identifier: ReturnType<C> | null, callback: C): BinaryTreeDeletedResult<N>[];
delete<C extends BTNCallback<N>>(identifier: ReturnType<C> | null, callback: C): BiTreeDeleteResult<N>[];
}

View file

@ -24,7 +24,7 @@ export enum FamilyPosition {
export type BTNKey = number;
export type BinaryTreeDeletedResult<N> = { deleted: N | null | undefined; needBalanced: N | null | undefined };
export type BiTreeDeleteResult<N> = { deleted: N | null | undefined; needBalanced: N | null | undefined };
export type BinaryTreeNodeNested<T> = BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>