refactor: Unified API parameters, streamline syntax, exclude methods already present in the parent class.

This commit is contained in:
Revone 2023-11-09 20:25:54 +08:00
parent 28207b6d45
commit c2c7011e15
10 changed files with 326 additions and 255 deletions

View file

@ -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>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 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>45.48</td><td>21.99</td><td>0.04</td></tr><tr><td>10,000 add & delete randomly</td><td>132.35</td><td>7.56</td><td>0.10</td></tr><tr><td>10,000 addMany</td><td>79.22</td><td>12.62</td><td>0.07</td></tr><tr><td>10,000 get</td><td>93.13</td><td>10.74</td><td>0.06</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>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 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>23.89</td><td>41.85</td><td>0.01</td></tr><tr><td>1,000 add & delete randomly</td><td>22.84</td><td>43.78</td><td>0.01</td></tr><tr><td>1,000 addMany</td><td>10.61</td><td>94.22</td><td>4.91e-4</td></tr><tr><td>1,000 get</td><td>18.56</td><td>53.87</td><td>8.86e-4</td></tr><tr><td>1,000 dfs</td><td>158.90</td><td>6.29</td><td>0.00</td></tr><tr><td>1,000 bfs</td><td>58.59</td><td>17.07</td><td>0.00</td></tr><tr><td>1,000 morris</td><td>269.91</td><td>3.70</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'>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>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 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.66</td><td>31.59</td><td>8.90e-4</td></tr><tr><td>10,000 add & delete randomly</td><td>73.97</td><td>13.52</td><td>0.00</td></tr><tr><td>10,000 addMany</td><td>31.66</td><td>31.58</td><td>0.00</td></tr><tr><td>10,000 get</td><td>29.75</td><td>33.61</td><td>5.49e-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>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 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.24</td><td>11.46</td><td>0.00</td></tr><tr><td>100,000 add & delete randomly</td><td>218.78</td><td>4.57</td><td>0.01</td></tr><tr><td>100,000 getNode</td><td>91.39</td><td>10.94</td><td>0.00</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>directed-graph</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000 addVertex</td><td>0.10</td><td>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 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>9631.84</td><td>5.21e-6</td></tr><tr><td>1,000 addEdge</td><td>6.25</td><td>160.06</td><td>3.97e-4</td></tr><tr><td>1,000 getVertex</td><td>0.05</td><td>2.13e+4</td><td>1.05e-6</td></tr><tr><td>1,000 getEdge</td><td>23.83</td><td>41.97</td><td>0.00</td></tr><tr><td>tarjan</td><td>217.69</td><td>4.59</td><td>0.01</td></tr><tr><td>tarjan all</td><td>226.43</td><td>4.42</td><td>0.01</td></tr><tr><td>topologicalSort</td><td>180.71</td><td>5.53</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'>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.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 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.69</td><td>213.13</td><td>1.63e-4</td></tr><tr><td>10,000 fib add & pop</td><td>367.49</td><td>2.72</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 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 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>221.10</td><td>4.52</td><td>0.06</td></tr><tr><td>1,000,000 unshift & shift</td><td>179.99</td><td>5.56</td><td>0.03</td></tr><tr><td>1,000,000 insertBefore</td><td>331.29</td><td>3.02</td><td>0.06</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>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 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>216.59</td><td>4.62</td><td>0.01</td></tr><tr><td>10,000 insertBefore</td><td>255.08</td><td>3.92</td><td>0.01</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>max-priority-queue</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 refill & poll</td><td>11.72</td><td>85.32</td><td>2.97e-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>12.00</td><td>83.34</td><td>6.62e-4</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>deque</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 push</td><td>233.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 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>222.01</td><td>4.50</td><td>0.05</td></tr><tr><td>1,000,000 shift</td><td>25.35</td><td>39.45</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.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 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.31</td><td>22.07</td><td>0.01</td></tr><tr><td>1,000,000 push & shift</td><td>83.92</td><td>11.92</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'>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>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 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.08</td><td>16.92</td><td>0.01</td></tr><tr><td>100,000 getWords</td><td>95.74</td><td>10.44</td><td>0.01</td></tr></table></div>
</div>
[//]: # (No deletion!!! End of Replace Section)

View file

@ -1,6 +1,6 @@
{
"name": "data-structure-typed",
"version": "1.42.6",
"version": "1.42.7",
"description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.",
"main": "dist/cjs/src/index.js",
"module": "dist/mjs/src/index.js",

View file

@ -71,12 +71,12 @@ export class AVLTree<V = any, N extends AVLTreeNode<V, N> = AVLTreeNode<V, AVLTr
* @param callback - The `callback` parameter is a function that takes a node as input and returns a
* 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`
* `this._defaultOneParamCallback`
* @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
callback: C = this._defaultOneParamCallback as C
): BiTreeDeleteResult<N>[] {
if ((identifier as any) instanceof AVLTreeNode) callback = (node => node) as C;
const deletedResults = super.delete(identifier, callback);
@ -97,8 +97,8 @@ export class AVLTree<V = any, N extends AVLTreeNode<V, N> = AVLTreeNode<V, AVLTr
* @returns The method is returning the `destNode` after swapping its properties with the `srcNode`.
*/
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);
srcNode = this.ensureNotKey(srcNode);
destNode = this.ensureNotKey(destNode);
if (srcNode && destNode) {
const {key, value, height} = destNode;

View file

@ -7,7 +7,7 @@
*/
import type {BinaryTreeNodeNested, BinaryTreeOptions, BTNCallback, BTNKey} from '../../types';
import {BiTreeDeleteResult, CP, DFSOrderPattern, FamilyPosition, IterationType} from '../../types';
import {BiTreeDeleteResult, DFSOrderPattern, FamilyPosition, IterationType} from '../../types';
import {IBinaryTree} from '../../interfaces';
import {trampoline} from '../../utils';
import {Queue} from '../queue';
@ -26,12 +26,12 @@ export class BinaryTreeNode<V = any, N extends BinaryTreeNode<V, N> = BinaryTree
/**
* The value stored in the node.
*/
value: V | undefined;
value?: V;
/**
* The parent node of the current node.
*/
parent: N | null | undefined;
parent?: N | null;
/**
* Creates a new instance of BinaryTreeNode.
@ -43,7 +43,7 @@ export class BinaryTreeNode<V = any, N extends BinaryTreeNode<V, N> = BinaryTree
this.value = value;
}
protected _left: N | null | undefined;
protected _left?: N | null;
/**
* Get the left child node.
@ -63,7 +63,7 @@ export class BinaryTreeNode<V = any, N extends BinaryTreeNode<V, N> = BinaryTree
this._left = v;
}
protected _right: N | null | undefined;
protected _right?: N | null;
/**
* Get the right child node.
@ -121,9 +121,10 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
const {iterationType = IterationType.ITERATIVE} = options;
this.iterationType = iterationType;
}
this._size = 0;
}
protected _root: N | null | undefined = undefined;
protected _root?: N | null;
/**
* Get the root node of the binary tree.
@ -132,7 +133,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return this._root;
}
protected _size = 0;
protected _size: number;
/**
* Get the number of nodes in the binary tree.
@ -151,22 +152,6 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return new BinaryTreeNode<V, N>(key, value) as N;
}
/**
* Clear the binary tree, removing all nodes.
*/
clear() {
this._setRoot(undefined);
this._size = 0;
}
/**
* Check if the binary tree is empty.
* @returns {boolean} - True if the binary tree is empty, false otherwise.
*/
isEmpty(): boolean {
return this.size === 0;
}
/**
* Add a node with the given key and value to the binary tree.
* @param {BTNKey | N | null} keyOrNode - The key or node to add to the binary tree.
@ -196,7 +181,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
if (keyOrNode === null) {
needInsert = null;
} else if (typeof keyOrNode === 'number') {
} else if (this.isNodeKey(keyOrNode)) {
needInsert = this.createNode(keyOrNode, value);
} else if (keyOrNode instanceof BinaryTreeNode) {
needInsert = keyOrNode;
@ -253,7 +238,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* array. Each value in the `data` array will be assigned to the
* @returns The method is returning a boolean value.
*/
refill(keysOrNodes: (BTNKey | null | undefined)[] | (N | null | undefined)[], values?: Array<V | undefined>): boolean {
refill(keysOrNodes: (BTNKey | N | null | undefined)[], values?: (V | undefined)[]): boolean {
this.clear();
return keysOrNodes.length === this.addMany(keysOrNodes, values).length;
}
@ -276,18 +261,18 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @param callback - The `callback` parameter is a function that takes a node as input and returns a
* 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`, which
* `this._defaultOneParamCallback`, which
*/
delete<C extends BTNCallback<N>>(
identifier: ReturnType<C> | null | undefined,
callback: C = this.defaultOneParamCallback as C
callback: C = this._defaultOneParamCallback as C
): BiTreeDeleteResult<N>[] {
const deleteResult: BiTreeDeleteResult<N>[] = [];
if (!this.root) return deleteResult;
const deletedResult: BiTreeDeleteResult<N>[] = [];
if (!this.root) return deletedResult;
if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C;
const curr = this.getNode(identifier, callback);
if (!curr) return deleteResult;
if (!curr) return deletedResult;
const parent: N | null | undefined = curr?.parent ? curr.parent : null;
let needBalanced: N | null | undefined = undefined;
@ -321,8 +306,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
}
this._size = this.size - 1;
deleteResult.push({deleted: orgCurrent, needBalanced});
return deleteResult;
deletedResult.push({deleted: orgCurrent, needBalanced});
return deletedResult;
}
/**
@ -338,8 +323,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @returns the depth of the `distNode` relative to the `beginRoot`.
*/
getDepth(distNode: BTNKey | N | null | undefined, beginRoot: BTNKey | N | null | undefined = this.root): number {
if (typeof distNode === 'number') distNode = this.getNode(distNode);
if (this.isNodeKey(beginRoot)) beginRoot = this._getNodeByKey(beginRoot);
distNode = this.ensureNotKey(distNode);
beginRoot = this.ensureNotKey(beginRoot);
let depth = 0;
while (distNode?.parent) {
if (distNode === beginRoot) {
@ -364,7 +349,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 (this.isNodeKey(beginRoot)) beginRoot = this._getNodeByKey(beginRoot);
beginRoot = this.ensureNotKey(beginRoot);
if (!beginRoot) return -1;
if (iterationType === IterationType.RECURSIVE) {
@ -387,14 +372,9 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
while (stack.length > 0) {
const {node, depth} = stack.pop()!;
if (node.left) {
stack.push({node: node.left, depth: depth + 1});
}
if (node.right) {
stack.push({node: node.right, depth: depth + 1});
}
if (node.left) stack.push({node: node.left, depth: depth + 1});
if (node.right) stack.push({node: node.right, depth: depth + 1});
maxHeight = Math.max(maxHeight, depth);
}
@ -413,8 +393,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @returns The function `getMinHeight` returns the minimum height of a binary tree.
*/
getMinHeight(beginRoot: BTNKey | N | null | undefined = this.root, iterationType = this.iterationType): number {
if (!beginRoot) return -1;
if (this.isNodeKey(beginRoot)) beginRoot = this._getNodeByKey(beginRoot);
beginRoot = this.ensureNotKey(beginRoot);
if (!beginRoot) return -1;
if (iterationType === IterationType.RECURSIVE) {
@ -500,7 +479,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @param callback - The `callback` parameter is a function that takes a node as input and returns a
* 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`, which
* `this._defaultOneParamCallback`, which
* @param [onlyOne=false] - A boolean value indicating whether to stop searching after finding the
* first node that matches the identifier. If set to true, the function will return an array with
* only one element (or an empty array if no matching node is found). If set to false (default), the
@ -514,14 +493,14 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
*/
getNodes<C extends BTNCallback<N>>(
identifier: ReturnType<C> | null | undefined,
callback: C = this.defaultOneParamCallback as C,
callback: C = this._defaultOneParamCallback as C,
onlyOne = false,
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);
beginRoot = this.ensureNotKey(beginRoot);
if (!beginRoot) return [];
const ans: N[] = [];
@ -585,7 +564,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @param callback - The `callback` parameter is a function that is used to determine whether a node
* matches the desired criteria. It takes a node as input and returns a boolean value indicating
* whether the node matches the criteria or not. The default callback function
* `this.defaultOneParamCallback` is used if no callback function is
* `this._defaultOneParamCallback` is used if no callback function is
* @param beginRoot - The `beginRoot` parameter is the starting point for the search. It specifies
* the node from which the search should begin. By default, it is set to `this.root`, which means the
* search will start from the root node of the binary tree. However, you can provide a different node
@ -596,7 +575,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,
callback: C = this._defaultOneParamCallback as C,
beginRoot: BTNKey | N | null | undefined = this.root,
iterationType = this.iterationType
): boolean {
@ -634,7 +613,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @param callback - The `callback` parameter is a function that is used to determine whether a node
* matches the desired criteria. It takes a node as input and returns a boolean value indicating
* whether the node matches the criteria or not. The default callback function
* (`this.defaultOneParamCallback`) is used if no callback function is
* (`this._defaultOneParamCallback`) is used if no callback function is
* @param beginRoot - The `beginRoot` parameter is the starting point for the search. It specifies
* the root node from which the search should begin.
* @param iterationType - The `iterationType` parameter specifies the type of iteration to be
@ -643,7 +622,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,
callback: C = this._defaultOneParamCallback as C,
beginRoot: BTNKey | N | null | undefined = this.root,
iterationType = this.iterationType
): N | null | undefined {
@ -652,7 +631,18 @@ 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 {
/**
* The function `getNodeByKey` searches for a node in a binary tree by its key, using either
* recursive or iterative iteration.
* @param {BTNKey} key - The `key` parameter is the key value that we are searching for in the tree.
* It is used to find the node with the matching key value.
* @param iterationType - The `iterationType` parameter is used to determine whether the search for
* the node with the given key should be performed iteratively or recursively. It has two possible
* values:
* @returns The function `getNodeByKey` returns a node (`N`) if a node with the specified key is
* found in the binary tree. If no node is found, it returns `undefined`.
*/
getNodeByKey(key: BTNKey, iterationType = IterationType.ITERATIVE): N | undefined {
if (!this.root) return undefined;
if (iterationType === IterationType.RECURSIVE) {
const _dfs = (cur: N): N | undefined => {
@ -677,6 +667,21 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
}
}
/**
* The function `ensureNotKey` returns the node corresponding to the given key if it is a valid node
* key, otherwise it returns the key itself.
* @param {BTNKey | N | null | undefined} key - The `key` parameter can be of type `BTNKey`, `N`,
* `null`, or `undefined`. It represents a key used to identify a node in a binary tree.
* @param iterationType - The `iterationType` parameter is an optional parameter that specifies the
* type of iteration to be used when searching for a node by key. It has a default value of
* `IterationType.ITERATIVE`.
* @returns either the node corresponding to the given key if it is a valid node key, or the key
* itself if it is not a valid node key.
*/
ensureNotKey(key: BTNKey | N | null | undefined, iterationType = IterationType.ITERATIVE): N | null | undefined {
return this.isNodeKey(key) ? this.getNodeByKey(key, iterationType) : key;
}
get<C extends BTNCallback<N, BTNKey>>(
identifier: BTNKey,
callback?: C,
@ -706,7 +711,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @param callback - The `callback` parameter is a function that is used to determine whether a node
* matches the desired criteria. It takes a node as input and returns a boolean value indicating
* whether the node matches the criteria or not. The default callback function
* (`this.defaultOneParamCallback`) is used if no callback function is
* (`this._defaultOneParamCallback`) is used if no callback function is
* @param beginRoot - The `beginRoot` parameter is the starting point for the search. It specifies
* the root node from which the search should begin.
* @param iterationType - The `iterationType` parameter specifies the type of iteration to be
@ -715,7 +720,7 @@ 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,
callback: C = this._defaultOneParamCallback as C,
beginRoot:BTNKey | N | null | undefined = this.root,
iterationType = this.iterationType
): V | undefined {
@ -724,6 +729,22 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return this.getNode(identifier, callback, beginRoot, iterationType)?.value ?? undefined;
}
/**
* Clear the binary tree, removing all nodes.
*/
clear() {
this._setRoot(undefined);
this._size = 0;
}
/**
* Check if the binary tree is empty.
* @returns {boolean} - True if the binary tree is empty, false otherwise.
*/
isEmpty(): boolean {
return this.size === 0;
}
/**
* 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.
@ -737,7 +758,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
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);
beginRoot = this.ensureNotKey(beginRoot);
if (!beginRoot) return result;
@ -763,13 +784,13 @@ 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 (this.isNodeKey(beginRoot)) beginRoot = this._getNodeByKey(beginRoot);
beginRoot = this.ensureNotKey(beginRoot);
if (!beginRoot) return beginRoot;
if (iterationType === IterationType.RECURSIVE) {
const _traverse = (cur: N): N => {
if (!cur.left) return cur;
if (!this.isRealNode(cur.left)) return cur;
return _traverse(cur.left);
};
@ -777,7 +798,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
} else {
// Indirect implementation of iteration using tail recursion optimization
const _traverse = trampoline((cur: N) => {
if (!cur.left) return cur;
if (!this.isRealNode(cur.left)) return cur;
return _traverse.cont(cur.left);
});
@ -798,12 +819,12 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
*/
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);
beginRoot = this.ensureNotKey(beginRoot);
if (!beginRoot) return beginRoot;
if (iterationType === IterationType.RECURSIVE) {
const _traverse = (cur: N): N => {
if (!cur.right) return cur;
if (!this.isRealNode(cur.right)) return cur;
return _traverse(cur.right);
};
@ -811,7 +832,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
} else {
// Indirect implementation of iteration using tail recursion optimization
const _traverse = trampoline((cur: N) => {
if (!cur.right) return cur;
if (!this.isRealNode(cur.right)) return cur;
return _traverse.cont(cur.right);
});
@ -830,7 +851,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
*/
isSubtreeBST(beginRoot: BTNKey | N | null | undefined, iterationType = this.iterationType): boolean {
// TODO there is a bug
if (this.isNodeKey(beginRoot)) beginRoot = this._getNodeByKey(beginRoot);
beginRoot = this.ensureNotKey(beginRoot);
if (!beginRoot) return true;
if (iterationType === IterationType.RECURSIVE) {
@ -909,12 +930,12 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @returns The function `subTreeTraverse` returns an array of `ReturnType<BTNCallback<N>>`.
*/
subTreeTraverse<C extends BTNCallback<N | null | undefined>>(
callback: C = this.defaultOneParamCallback as C,
callback: C = this._defaultOneParamCallback as C,
beginRoot: BTNKey | N | null | undefined = this.root,
iterationType = this.iterationType,
includeNull = false
): ReturnType<C>[] {
if (this.isNodeKey(beginRoot)) beginRoot = this._getNodeByKey(beginRoot);
beginRoot = this.ensureNotKey(beginRoot);
const ans: (ReturnType<BTNCallback<N>> | null | undefined)[] = [];
if (!beginRoot) return ans;
@ -954,18 +975,40 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
return ans;
}
isNode(node: any): node is N {
/**
* 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: any): node is N {
return node instanceof BinaryTreeNode && node.key.toString() !== '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: any) {
return node instanceof BinaryTreeNode && node.key.toString() === '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: any): node is (N | null){
return this.isNode(node) || node === null;
return this.isRealNode(node) || node === null;
}
/**
* The function "isNodeKey" checks if a potential key is a number.
* @param {any} potentialKey - The potentialKey parameter is of type any, which means it can be any
* data type.
* @returns a boolean value indicating whether the potentialKey is of type number or not.
*/
isNodeKey(potentialKey: any) : potentialKey is number {
return typeof potentialKey === 'number';
}
@ -999,7 +1042,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* function on each node according to a specified order pattern.
* @param callback - The `callback` parameter is a function that will be called on each node during
* the depth-first search traversal. It takes a node as input and returns a value. The default value
* is `this.defaultOneParamCallback`, which is a callback function defined elsewhere in the code.
* is `this._defaultOneParamCallback`, which is a callback function defined elsewhere in the code.
* @param {DFSOrderPattern} [pattern=in] - The `pattern` parameter determines the order in which the
* nodes are visited during the depth-first search. There are three possible values for `pattern`:
* @param {N | null | undefined} beginRoot - The `beginRoot` parameter is the starting node for the depth-first
@ -1011,14 +1054,14 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @returns The function `dfs` returns an array of `ReturnType<BTNCallback<N>>` values.
*/
dfs<C extends BTNCallback<N | null | undefined>>(
callback: C = this.defaultOneParamCallback as C,
callback: C = this._defaultOneParamCallback as C,
pattern: DFSOrderPattern = 'in',
beginRoot: BTNKey | N | null | undefined = this.root,
iterationType: IterationType = IterationType.ITERATIVE,
includeNull = false
): ReturnType<C>[] {
if (this.isNodeKey(beginRoot)) beginRoot = this._getNodeByKey(beginRoot);
beginRoot = this.ensureNotKey(beginRoot);
if (!beginRoot) return [];
const ans: ReturnType<C>[] = [];
if (iterationType === IterationType.RECURSIVE) {
@ -1031,7 +1074,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
if (node && this.isNodeOrNull(node.right)) _traverse(node.right);
} else {
if (node && node.left) _traverse(node.left);
this.isNode(node) && ans.push(callback(node));
this.isRealNode(node) && ans.push(callback(node));
if (node && node.right) _traverse(node.right);
}
break;
@ -1041,7 +1084,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
if (node && this.isNodeOrNull(node.left)) _traverse(node.left);
if (node && this.isNodeOrNull(node.right)) _traverse(node.right);
} else {
this.isNode(node) && ans.push(callback(node));
this.isRealNode(node) && ans.push(callback(node));
if (node && node.left) _traverse(node.left);
if (node && node.right) _traverse(node.right);
}
@ -1054,7 +1097,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
} else {
if (node && node.left) _traverse(node.left);
if (node && node.right) _traverse(node.right);
this.isNode(node) && ans.push(callback(node));
this.isRealNode(node) && ans.push(callback(node));
}
break;
@ -1132,7 +1175,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* function on each node.
* @param callback - The `callback` parameter is a function that will be called for each node in the
* breadth-first search. It takes a node of type `N` as its argument and returns a value of type
* `ReturnType<BTNCallback<N>>`. The default value for this parameter is `this.defaultOneParamCallback
* `ReturnType<BTNCallback<N>>`. The default value for this parameter is `this._defaultOneParamCallback
* @param {N | null | undefined} beginRoot - The `beginRoot` parameter is the starting node for the breadth-first
* search. It determines from which node the search will begin. If `beginRoot` is `null`, the search
* will not be performed and an empty array will be returned.
@ -1142,12 +1185,12 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @returns The function `bfs` returns an array of `ReturnType<BTNCallback<N>>[]`.
*/
bfs<C extends BTNCallback<N | null | undefined>>(
callback: C = this.defaultOneParamCallback as C,
callback: C = this._defaultOneParamCallback as C,
beginRoot: BTNKey | N | null | undefined = this.root,
iterationType = this.iterationType,
includeNull = false
): ReturnType<C>[] {
if (this.isNodeKey(beginRoot)) beginRoot = this._getNodeByKey(beginRoot);
beginRoot = this.ensureNotKey(beginRoot);
if (!beginRoot) return [];
const ans: ReturnType<BTNCallback<N>>[] = [];
@ -1233,14 +1276,14 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* function `C` applied to the nodes at that level.
*/
listLevels<C extends BTNCallback<N | null | undefined>>(
callback: C = this.defaultOneParamCallback as C,
callback: C = this._defaultOneParamCallback as C,
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 [];
beginRoot = this.ensureNotKey(beginRoot);
const levelsNodes: ReturnType<C>[][] = [];
if (!beginRoot) return levelsNodes;
if (iterationType === IterationType.RECURSIVE) {
const _recursive = (node: N | null | undefined, level: number) => {
@ -1287,12 +1330,12 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @returns The function `getPredecessor` returns the predecessor node of the given node `node`.
*/
getPredecessor(node: BTNKey | N | null | undefined): N | undefined{
if (this.isNodeKey(node)) node = this.getNode(node);
if (!node) return undefined;
node = this.ensureNotKey(node);
if (!this.isRealNode(node)) return undefined;
if (node.left) {
let predecessor: N | null | undefined = node.left;
while (!predecessor || (predecessor.right && predecessor.right !== node)) {
while (!this.isRealNode(predecessor) || (this.isRealNode(predecessor.right) && predecessor.right !== node)) {
if (predecessor) {
predecessor = predecessor.right;
}
@ -1310,8 +1353,8 @@ 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: BTNKey | N | null | undefined): N | null | undefined {
if (this.isNodeKey(x)) x = this.getNode(x);
getSuccessor(x?: BTNKey | N | null): N | null | undefined {
x = this.ensureNotKey(x);
if (!x) return undefined;
if (x.right) {
@ -1331,7 +1374,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* algorithm and returns an array of values obtained by applying a callback function to each node.
* @param callback - The `callback` parameter is a function that will be called on each node in the
* tree. It takes a node of type `N` as input and returns a value of type `ReturnType<BTNCallback<N>>`. The
* default value for this parameter is `this.defaultOneParamCallback`.
* default value for this parameter is `this._defaultOneParamCallback`.
* @param {DFSOrderPattern} [pattern=in] - The `pattern` parameter in the `morris` function
* determines the order in which the nodes of a binary tree are traversed. It can have one of the
* following values:
@ -1341,11 +1384,11 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @returns The `morris` function returns an array of `ReturnType<BTNCallback<N>>` values.
*/
morris<C extends BTNCallback<N>>(
callback: C = this.defaultOneParamCallback as C,
callback: C = this._defaultOneParamCallback as C,
pattern: DFSOrderPattern = 'in',
beginRoot: BTNKey | N | null | undefined = this.root
): ReturnType<C>[] {
if (this.isNodeKey(beginRoot)) beginRoot = this._getNodeByKey(beginRoot);
beginRoot = this.ensureNotKey(beginRoot);
if (beginRoot === null) return [];
const ans: ReturnType<BTNCallback<N>>[] = [];
@ -1470,7 +1513,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
}
}
protected defaultOneParamCallback = (node: N) => node.key;
protected _defaultOneParamCallback = (node: N) => node.key;
/**
* Swap the data of two nodes in the binary tree.
@ -1479,8 +1522,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
* @returns {N} - The destination node after the swap.
*/
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);
srcNode = this.ensureNotKey(srcNode);
destNode = this.ensureNotKey(destNode);
if (srcNode && destNode) {
const {key, value} = destNode;
@ -1550,7 +1593,16 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
this._root = v;
}
print(beginRoot: N | null | undefined = this.root) {
/**
* The `print` function is used to display a binary tree structure in a visually appealing way.
* @param {N | null | undefined} root - The `root` parameter in the `print` function represents the
* root node of a binary tree. It can have one of the following types: `BTNKey`, `N`, `null`, or
* `undefined`. The default value is `this.root`, which suggests that `this.root` is the
*/
print(beginRoot: BTNKey | N | null | undefined = this.root): void {
beginRoot = this.ensureNotKey(beginRoot);
if (!beginRoot) return;
const display = (root: N | null | undefined): void => {
const [lines, , ,] = _displayAux(root);
for (const line of lines) {

View file

@ -12,7 +12,7 @@ import {IBinaryTree} from '../../interfaces';
import {Queue} from '../queue';
export class BSTNode<V = any, N extends BSTNode<V, N> = BSTNodeNested<V>> extends BinaryTreeNode<V, N> {
override parent: N | undefined;
override parent?: N ;
constructor(key: BTNKey, value?: V) {
super(key, value);
@ -21,7 +21,7 @@ export class BSTNode<V = any, N extends BSTNode<V, N> = BSTNodeNested<V>> extend
this._right = undefined;
}
protected override _left: N | undefined;
protected override _left?: N ;
/**
* Get the left child node.
@ -42,7 +42,7 @@ export class BSTNode<V = any, N extends BSTNode<V, N> = BSTNodeNested<V>> extend
}
protected override _right: N | undefined;
protected override _right?: N ;
/**
* Get the right child node.
@ -83,7 +83,7 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
}
}
protected override _root: N | undefined = undefined;
protected override _root?: N ;
/**
* Get the root node of the binary tree.
@ -115,16 +115,13 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
* was not added or if the parameters were invalid, it returns undefined or undefined.
*/
override add(keyOrNode: BTNKey | N | null | undefined, value?: V): N | undefined {
if (keyOrNode === 8) {
debugger
}
if (keyOrNode === null) return undefined;
// TODO support node as a parameter
let inserted: N | undefined;
let newNode: N | undefined;
if (keyOrNode instanceof BSTNode) {
newNode = keyOrNode;
} else if (typeof keyOrNode === 'number') {
} else if (this.isNodeKey(keyOrNode)) {
newNode = this.createNode(keyOrNode, value);
} else {
newNode = undefined;
@ -197,7 +194,6 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
* It can have two possible values:
* @returns The `addMany` function returns an array of `N`, `undefined`, or `undefined` values.
*/
override addMany(
keysOrNodes: (BTNKey | N | undefined)[],
data?: (V | undefined)[],
@ -205,51 +201,53 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
iterationType = this.iterationType
): (N | undefined)[] {
// TODO this addMany function is inefficient, it should be optimized
function hasNoNull(arr: (BTNKey | N | undefined)[]): arr is (BTNKey | N)[] {
function hasNoUndefined(arr: (BTNKey | N | undefined)[]): arr is (BTNKey | N)[] {
return arr.indexOf(undefined) === -1;
}
if (!isBalanceAdd || !hasNoNull(keysOrNodes)) {
if (!isBalanceAdd || !hasNoUndefined(keysOrNodes)) {
return super.addMany(keysOrNodes, data).map(n => n ?? undefined);
}
const inserted: (N | undefined)[] = [];
const combinedArr: [BTNKey | N, V][] = keysOrNodes.map(
(value: BTNKey | N, index) => [value, data?.[index]] as [BTNKey | N, V]
);
let sorted = [];
function isNodeOrNullTuple(arr: [BTNKey | N, V][]): arr is [N, V][] {
function _isNodeOrUndefinedTuple(arr: [BTNKey | N, V][]): arr is [N, V][] {
for (const [keyOrNode] of arr) if (keyOrNode instanceof BSTNode) return true;
return false;
}
function isBinaryTreeKeyOrNullTuple(arr: [BTNKey | N, V][]): arr is [BTNKey, V][] {
for (const [keyOrNode] of arr) if (typeof keyOrNode === 'number') return true;
const _isBinaryTreeKeyOrNullTuple = (arr: [BTNKey | N, V][]): arr is [BTNKey, V][] => {
for (const [keyOrNode] of arr) if (this.isNodeKey(keyOrNode)) return true;
return false;
}
let sortedKeysOrNodes: (number | N | undefined)[] = [],
sortedData: (V | undefined)[] | undefined = [];
if (isNodeOrNullTuple(combinedArr)) {
if (_isNodeOrUndefinedTuple(combinedArr)) {
sorted = combinedArr.sort((a, b) => a[0].key - b[0].key);
} else if (isBinaryTreeKeyOrNullTuple(combinedArr)) {
} else if (_isBinaryTreeKeyOrNullTuple(combinedArr)) {
sorted = combinedArr.sort((a, b) => a[0] - b[0]);
} else {
throw new Error('Invalid input keysOrNodes');
}
sortedKeysOrNodes = sorted.map(([keyOrNode]) => keyOrNode);
sortedData = sorted.map(([, value]) => value);
const recursive = (arr: (BTNKey | undefined | N)[], data?: (V | undefined)[]) => {
const _dfs = (arr: (BTNKey | undefined | N)[], data?: (V | undefined)[]) => {
if (arr.length === 0) return;
const mid = Math.floor((arr.length - 1) / 2);
const newNode = this.add(arr[mid], data?.[mid]);
inserted.push(newNode);
recursive(arr.slice(0, mid), data?.slice(0, mid));
recursive(arr.slice(mid + 1), data?.slice(mid + 1));
_dfs(arr.slice(0, mid), data?.slice(0, mid));
_dfs(arr.slice(mid + 1), data?.slice(mid + 1));
};
const iterative = () => {
const _iterate = () => {
const n = sorted.length;
const stack: [[number, number]] = [[0, n - 1]];
while (stack.length > 0) {
@ -267,9 +265,9 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
}
};
if (iterationType === IterationType.RECURSIVE) {
recursive(sortedKeysOrNodes, sortedData);
_dfs(sortedKeysOrNodes, sortedData);
} else {
iterative();
_iterate();
}
return inserted;
@ -296,13 +294,24 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
else return this.getRightMost(beginRoot, iterationType)?.key ?? 0;
}
protected override _getNodeByKey(key: BTNKey, iterationType = IterationType.ITERATIVE): N | undefined {
/**
* The function `getNodeByKey` searches for a node in a binary tree based on a given key, using
* either recursive or iterative methods.
* @param {BTNKey} key - The `key` parameter is the key value that we are searching for in the tree.
* It is used to find the node with the matching key value.
* @param iterationType - The `iterationType` parameter is an optional parameter that specifies the
* type of iteration to use when searching for a node in the binary tree. It can have two possible
* values:
* @returns The function `getNodeByKey` returns a node (`N`) if a node with the specified key is
* found in the binary tree. If no node is found, it returns `undefined`.
*/
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);
};
@ -321,6 +330,19 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
}
}
/**
* The function `ensureNotKey` returns the node corresponding to the given key if it is a node key,
* otherwise it returns the key itself.
* @param {BTNKey | N | undefined} key - The `key` parameter can be of type `BTNKey`, `N`, or
* `undefined`.
* @param iterationType - The `iterationType` parameter is an optional parameter that specifies the
* type of iteration to be performed. It has a default value of `IterationType.ITERATIVE`.
* @returns either a node object (N) or undefined.
*/
override ensureNotKey(key: BTNKey | N | undefined, iterationType = IterationType.ITERATIVE): N | undefined {
return this.isNodeKey(key) ? this.getNodeByKey(key, iterationType) : key;
}
/**
* The function `getNodes` retrieves nodes from a binary tree based on a given node property or key,
* using either recursive or iterative traversal.
@ -329,7 +351,7 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
* generic type `N`.
* @param callback - The `callback` parameter is a function that takes a node as input and returns a
* value. This value is compared with the `nodeProperty` parameter to determine if the node should be
* included in the result. The default value for `callback` is `this.defaultOneParamCallback`, which is
* included in the result. The default value for `callback` is `this._defaultOneParamCallback`, which is
* a
* @param [onlyOne=false] - A boolean value indicating whether to stop the traversal after finding
* the first node that matches the nodeProperty. If set to true, the function will return an array
@ -344,12 +366,12 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
*/
override getNodes<C extends BTNCallback<N>>(
identifier: ReturnType<C> | undefined,
callback: C = this.defaultOneParamCallback as C,
callback: C = this._defaultOneParamCallback as C,
onlyOne = false,
beginRoot: BTNKey | N | undefined = this.root,
iterationType = this.iterationType
): N[] {
if (this.isNodeKey(beginRoot)) beginRoot = this._getNodeByKey(beginRoot);
beginRoot = this.ensureNotKey(beginRoot);
if (!beginRoot) return [];
const ans: N[] = [];
@ -363,7 +385,7 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
if (!cur.left && !cur.right) return;
// TODO potential bug
if (callback === this.defaultOneParamCallback) {
if (callback === this._defaultOneParamCallback) {
if (this._compare(cur.key, identifier as number) === CP.gt) cur.left && _traverse(cur.left);
if (this._compare(cur.key, identifier as number) === CP.lt) cur.right && _traverse(cur.right);
} else {
@ -384,7 +406,7 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
if (onlyOne) return ans;
}
// TODO potential bug
if (callback === this.defaultOneParamCallback) {
if (callback === this._defaultOneParamCallback) {
if (this._compare(cur.key, identifier as number) === CP.gt) cur.left && queue.push(cur.left);
if (this._compare(cur.key, identifier as number) === CP.lt) cur.right && queue.push(cur.right);
} else {
@ -418,17 +440,18 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
* @returns The function `lesserOrGreaterTraverse` returns an array of `ReturnType<BTNCallback<N>>`.
*/
lesserOrGreaterTraverse<C extends BTNCallback<N>>(
callback: C = this.defaultOneParamCallback as C,
callback: C = this._defaultOneParamCallback as C,
lesserOrGreater: CP = CP.lt,
targetNode: BTNKey | N | undefined = this.root,
iterationType = this.iterationType
): ReturnType<C>[] {
if (typeof targetNode === 'number') targetNode = this.getNode(targetNode) ?? undefined;
targetNode = this.ensureNotKey(targetNode);
const ans: ReturnType<BTNCallback<N>>[] = [];
if (!targetNode) return ans;
const targetKey = targetNode.key;
if (!this.root) return ans;
const targetKey = targetNode.key;
if (iterationType === IterationType.RECURSIVE) {
const _traverse = (cur: N) => {
const compared = this._compare(cur.key, targetKey);

View file

@ -12,14 +12,14 @@ import {
BTNKey,
IterationType,
RBTNColor,
RBTreeNodeNested,
RedBlackTreeNodeNested,
RBTreeOptions
} from '../../types';
import {BST, BSTNode} from "./bst";
import {IBinaryTree} from "../../interfaces";
import {BinaryTreeNode} from "./binary-tree";
export class RBTreeNode<V = any, N extends RBTreeNode<V, N> = RBTreeNodeNested<V>> extends BSTNode<V, N> {
export class RedBlackTreeNode<V = any, N extends RedBlackTreeNode<V, N> = RedBlackTreeNodeNested<V>> extends BSTNode<V, N> {
color: RBTNColor;
constructor(key: BTNKey, value?: V, color: RBTNColor = RBTNColor.BLACK) {
super(key, value);
@ -34,7 +34,7 @@ export class RBTreeNode<V = any, N extends RBTreeNode<V, N> = RBTreeNodeNested<V
* 4. Red nodes must have black children.
* 5. Black balance: Every path from any node to each of its leaf nodes contains the same number of black nodes.
*/
export class RedBlackTree<V = any, N extends RBTreeNode<V, N> = RBTreeNode<V, RBTreeNodeNested<V>>>
export class RedBlackTree<V = any, N extends RedBlackTreeNode<V, N> = RedBlackTreeNode<V, RedBlackTreeNodeNested<V>>>
extends BST<V, N>
implements IBinaryTree<V, N>
{
@ -56,13 +56,21 @@ export class RedBlackTree<V = any, N extends RBTreeNode<V, N> = RBTreeNode<V, RB
return this._size;
}
NIL: N = new RBTreeNode<V>(NaN) as unknown as N;
NIL: N = new RedBlackTreeNode<V>(NaN) as unknown as N;
/**
* The `add` function adds a new node to a Red-Black Tree data structure.
* @param {BTNKey | N | null | undefined} keyOrNode - The `keyOrNode` parameter can be one of the
* following types:
* @param {V} [value] - The `value` parameter is an optional value that can be associated with the
* key in the node being added to the Red-Black Tree.
* @returns The method returns either a node (`N`) or `undefined`.
*/
override add(keyOrNode: BTNKey | N | null | undefined, value?: V): N | undefined {
let node: N;
if (typeof keyOrNode === 'number') {
if (this.isNodeKey(keyOrNode)) {
node = this.createNode(keyOrNode, value, RBTNColor.RED);
} else if(keyOrNode instanceof RBTreeNode) {
} else if(keyOrNode instanceof RedBlackTreeNode) {
node = keyOrNode;
} else if (keyOrNode === null) {
return;
@ -112,13 +120,24 @@ export class RedBlackTree<V = any, N extends RBTreeNode<V, N> = RBTreeNode<V, RB
}
override createNode(key: BTNKey, value?: V, color: RBTNColor = RBTNColor.BLACK): N {
return new RBTreeNode<V, N>(key, value, color) as N;
return new RedBlackTreeNode<V, N>(key, value, color) as N;
}
/**
* The `delete` function removes a node from a binary tree based on a given identifier and updates
* the tree accordingly.
* @param {ReturnType<C> | null | undefined} identifier - The `identifier` parameter is the value
* that you want to use to identify the node that you want to delete from the binary tree. It can be
* of any type that is returned by the callback function `C`. It can also be `null` or `undefined` if
* you don't want to
* @param {C} callback - The `callback` parameter is a function that takes a node of type `N` and
* returns a value of type `ReturnType<C>`. It is used to determine if a node should be deleted based
* on its identifier. The `callback` function is optional and defaults to `this._defaultOneParam
* @returns an array of `BiTreeDeleteResult<N>`.
*/
delete<C extends BTNCallback<N>>(
identifier: ReturnType<C> | null | undefined,
callback: C = this.defaultOneParamCallback as C
callback: C = this._defaultOneParamCallback as C
): BiTreeDeleteResult<N>[] {
const ans: BiTreeDeleteResult<N>[] = [];
if (identifier === null) return ans;
@ -151,7 +170,7 @@ export class RedBlackTree<V = any, N extends RBTreeNode<V, N> = RBTreeNode<V, RB
x = z.left;
this._rbTransplant(z, z.left!);
} else {
y = this.getLeftMost(z.right);
y = this.getLeftMost(z.right)!;
yOriginalColor = y.color;
x = y.right;
if (y.parent === z) {
@ -177,7 +196,7 @@ export class RedBlackTree<V = any, N extends RBTreeNode<V, N> = RBTreeNode<V, RB
return ans;
}
isNode(node: N | undefined): node is N {
override isRealNode(node: N | undefined): node is N {
return node !== this.NIL && node !== undefined;
}
@ -210,7 +229,7 @@ export class RedBlackTree<V = any, N extends RBTreeNode<V, N> = RBTreeNode<V, RB
* @param callback - The `callback` parameter is a function that is used to determine whether a node
* matches the desired criteria. It takes a node as input and returns a boolean value indicating
* whether the node matches the criteria or not. The default callback function
* (`this.defaultOneParamCallback`) is used if no callback function is
* (`this._defaultOneParamCallback`) is used if no callback function is
* @param beginRoot - The `beginRoot` parameter is the starting point for the search. It specifies
* the root node from which the search should begin.
* @param iterationType - The `iterationType` parameter specifies the type of iteration to be
@ -219,48 +238,23 @@ export class RedBlackTree<V = any, N extends RBTreeNode<V, N> = RBTreeNode<V, RB
*/
getNode<C extends BTNCallback<N>>(
identifier: ReturnType<C> | undefined,
callback: C = this.defaultOneParamCallback as C,
beginRoot = this.root,
callback: C = this._defaultOneParamCallback as C,
beginRoot: BTNKey | N | undefined = this.root,
iterationType = this.iterationType
): N | null | undefined {
if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C;
beginRoot = this.ensureNotKey(beginRoot);
return this.getNodes(identifier, callback, true, beginRoot, iterationType)[0] ?? undefined;
}
/**
* The function returns the leftmost node in a red-black tree.
* @param {RBTreeNode} node - The parameter "node" is of type RBTreeNode, which represents a node in
* a Red-Black Tree.
* @returns The leftmost node in the given RBTreeNode.
*/
getLeftMost(node: N = this.root): N {
while (node.left !== undefined && node.left !== this.NIL) {
node = node.left;
}
return node;
}
/**
* The function returns the rightmost node in a red-black tree.
* @param {RBTreeNode} node - The parameter "node" is of type RBTreeNode.
* @returns the rightmost node in a red-black tree.
*/
getRightMost(node: N): N {
while (node.right !== undefined && node.right !== this.NIL) {
node = node.right;
}
return node;
}
/**
* The function returns the successor of a given node in a red-black tree.
* @param {RBTreeNode} x - RBTreeNode - The node for which we want to find the successor.
* @returns the successor of the given RBTreeNode.
* @param {RedBlackTreeNode} x - RedBlackTreeNode - The node for which we want to find the successor.
* @returns the successor of the given RedBlackTreeNode.
*/
getSuccessor(x: N): N | undefined {
override getSuccessor(x: N): N | undefined {
if (x.right !== this.NIL) {
return this.getLeftMost(x.right);
return this.getLeftMost(x.right) ?? undefined;
}
let y: N | undefined = x.parent;
@ -273,13 +267,13 @@ export class RedBlackTree<V = any, N extends RBTreeNode<V, N> = RBTreeNode<V, RB
/**
* The function returns the predecessor of a given node in a red-black tree.
* @param {RBTreeNode} x - The parameter `x` is of type `RBTreeNode`, which represents a node in a
* @param {RedBlackTreeNode} x - The parameter `x` is of type `RedBlackTreeNode`, which represents a node in a
* Red-Black Tree.
* @returns the predecessor of the given RBTreeNode 'x'.
* @returns the predecessor of the given RedBlackTreeNode 'x'.
*/
getPredecessor(x: N): N {
override getPredecessor(x: N): N {
if (x.left !== this.NIL) {
return this.getRightMost(x.left!);
return this.getRightMost(x.left!)!;
}
let y: N | undefined = x.parent;
@ -305,7 +299,7 @@ export class RedBlackTree<V = any, N extends RBTreeNode<V, N> = RBTreeNode<V, RB
/**
* The function performs a left rotation on a red-black tree node.
* @param {RBTreeNode} x - The parameter `x` is a RBTreeNode object.
* @param {RedBlackTreeNode} x - The parameter `x` is a RedBlackTreeNode object.
*/
protected _leftRotate(x: N): void {
if (x.right) {
@ -329,7 +323,7 @@ export class RedBlackTree<V = any, N extends RBTreeNode<V, N> = RBTreeNode<V, RB
/**
* The function performs a right rotation on a red-black tree node.
* @param {RBTreeNode} x - x is a RBTreeNode, which represents the node that needs to be right
* @param {RedBlackTreeNode} x - x is a RedBlackTreeNode, which represents the node that needs to be right
* rotated.
*/
protected _rightRotate(x: N): void {
@ -354,7 +348,7 @@ export class RedBlackTree<V = any, N extends RBTreeNode<V, N> = RBTreeNode<V, RB
/**
* The _fixDelete function is used to rebalance the Red-Black Tree after a node deletion.
* @param {RBTreeNode} x - The parameter `x` is of type `RBTreeNode`, which represents a node in a
* @param {RedBlackTreeNode} x - The parameter `x` is of type `RedBlackTreeNode`, which represents a node in a
* red-black tree.
*/
protected _fixDelete(x: N): void {
@ -419,8 +413,8 @@ export class RedBlackTree<V = any, N extends RBTreeNode<V, N> = RBTreeNode<V, RB
/**
* The function `_rbTransplant` replaces one node in a red-black tree with another node.
* @param {RBTreeNode} u - The parameter "u" represents a RBTreeNode object.
* @param {RBTreeNode} v - The parameter "v" is a RBTreeNode object.
* @param {RedBlackTreeNode} u - The parameter "u" represents a RedBlackTreeNode object.
* @param {RedBlackTreeNode} v - The parameter "v" is a RedBlackTreeNode object.
*/
protected _rbTransplant(u: N, v: N): void {
if (u.parent === undefined) {
@ -435,7 +429,7 @@ export class RedBlackTree<V = any, N extends RBTreeNode<V, N> = RBTreeNode<V, RB
/**
* The `_fixInsert` function is used to fix the red-black tree after an insertion operation.
* @param {RBTreeNode} k - The parameter `k` is a RBTreeNode object, which represents a node in a
* @param {RedBlackTreeNode} k - The parameter `k` is a RedBlackTreeNode object, which represents a node in a
* red-black tree.
*/
protected _fixInsert(k: N): void {

View file

@ -37,8 +37,7 @@ export class TreeMultimapNode<
*/
export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultimapNode<V, TreeMultimapNodeNested<V>>>
extends AVLTree<V, N>
implements IBinaryTree<V, N>
{
implements IBinaryTree<V, N> {
/**
* The constructor function for a TreeMultimap class in TypeScript, which extends another class and sets an option to
* merge duplicated values.
@ -82,8 +81,8 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
* @returns The function `add` returns a value of type `N | undefined | undefined`.
*/
override add(keyOrNode: BTNKey | N | null | undefined, value?: V, count = 1): N | undefined {
if(keyOrNode === null) return undefined;
let inserted: N | undefined = undefined,
if (keyOrNode === null) return undefined;
let inserted: N | undefined = undefined,
newNode: N | undefined;
if (keyOrNode instanceof TreeMultimapNode) {
newNode = this.createNode(keyOrNode.key, keyOrNode.value, keyOrNode.count);
@ -95,7 +94,7 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
if (!this.root) {
this._setRoot(newNode);
this._size = this.size + 1;
newNode && this._setCount(this.count + newNode.count);
if (newNode) this._count += newNode.count;
inserted = this.root;
} else {
let cur = this.root;
@ -106,7 +105,7 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
if (this._compare(cur.key, newNode.key) === CP.eq) {
cur.value = newNode.value;
cur.count += newNode.count;
this._setCount(this.count + newNode.count);
this._count += newNode.count;
traversing = false;
inserted = cur;
} else if (this._compare(cur.key, newNode.key) === CP.gt) {
@ -115,7 +114,7 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
//Add to the left of the current node
cur.left = newNode;
this._size = this.size + 1;
this._setCount(this.count + newNode.count);
this._count += newNode.count;
traversing = false;
inserted = cur.left;
@ -129,7 +128,7 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
//Add to the right of the current node
cur.right = newNode;
this._size = this.size + 1;
this._setCount(this.count + newNode.count);
this._count += newNode.count;
traversing = false;
inserted = cur.right;
@ -158,13 +157,14 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
* be added as a child.
* @returns The method `_addTo` returns either the `parent.left`, `parent.right`, or `undefined`.
*/
override _addTo(newNode: N | undefined, parent: N): N | undefined {
protected override _addTo(newNode: N | undefined, parent: BTNKey | N | undefined): N | undefined {
parent = this.ensureNotKey(parent);
if (parent) {
if (parent.left === undefined) {
parent.left = newNode;
if (newNode !== undefined) {
this._size = this.size + 1;
this._setCount(this.count + newNode.count);
this._count += newNode.count;
}
return parent.left;
@ -172,7 +172,7 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
parent.right = newNode;
if (newNode !== undefined) {
this._size = this.size + 1;
this._setCount(this.count + newNode.count);
this._count += newNode.count;
}
return parent.right;
} else {
@ -193,8 +193,8 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
* each key or node.
* @returns The function `addMany` returns an array of `N`, `undefined`, or `undefined` values.
*/
override addMany(keysOrNodes: (BTNKey | undefined)[] | (N | undefined)[], data?: V[]): (N | undefined)[] {
const inserted: (N | undefined | undefined)[] = [];
override addMany(keysOrNodes: (BTNKey | N | undefined)[], data?: V[]): (N | undefined)[] {
const inserted: (N | undefined)[] = [];
for (let i = 0; i < keysOrNodes.length; i++) {
const keyOrNode = keysOrNodes[i];
@ -269,7 +269,7 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
* @param callback - The `callback` parameter is a function that takes a node as input and returns a
* 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`
* `this._defaultOneParamCallback`
* @param [ignoreCount=false] - A boolean flag indicating whether to ignore the count of the node
* 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
@ -278,22 +278,21 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
*/
override delete<C extends BTNCallback<N>>(
identifier: ReturnType<C>,
callback: C = this.defaultOneParamCallback as C,
callback: C = this._defaultOneParamCallback as C,
ignoreCount = false
): BiTreeDeleteResult<N>[] {
const bstDeletedResult: BiTreeDeleteResult<N>[] = [];
if (!this.root) return bstDeletedResult;
const deletedResult: BiTreeDeleteResult<N>[] = [];
if (!this.root) return deletedResult;
const curr: N | undefined = this.getNode(identifier, callback) ?? undefined;
if (!curr) return bstDeletedResult;
if (!curr) return deletedResult;
const parent: N | undefined = curr?.parent ? curr.parent : undefined;
let needBalanced: N | undefined = undefined,
orgCurrent = curr;
let needBalanced: N | undefined = undefined,orgCurrent: N | undefined = curr;
if (curr.count > 1 && !ignoreCount) {
curr.count--;
this._setCount(this.count - 1);
this._count--;
} else {
if (!curr.left) {
if (!parent) {
@ -324,24 +323,24 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
}
this._size = this.size - 1;
// TODO How to handle when the count of target node is lesser than current node's count
this._setCount(this.count - orgCurrent.count);
if (orgCurrent) this._count -= orgCurrent.count;
}
bstDeletedResult.push({deleted: orgCurrent, needBalanced});
deletedResult.push({deleted: orgCurrent, needBalanced});
if (needBalanced) {
this._balancePath(needBalanced);
}
return bstDeletedResult;
return deletedResult;
}
/**
* The clear() function clears the contents of a data structure and sets the count to zero.
*/
clear() {
override clear() {
super.clear();
this._setCount(0);
this._count = 0;
}
/**
@ -351,31 +350,28 @@ export class TreeMultimap<V = any, N extends TreeMultimapNode<V, N> = TreeMultim
* from `srcNode` will be swapped into.
* @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, count, height} = destNode;
const tempNode = this.createNode(key, value, count);
if (tempNode) {
tempNode.height = height;
protected _swap(srcNode: BTNKey | N | undefined, destNode:BTNKey | N | undefined): N | undefined{
srcNode = this.ensureNotKey(srcNode);
destNode = this.ensureNotKey(destNode);
if (srcNode && destNode) {
const {key, value, count, height} = destNode;
const tempNode = this.createNode(key, value, count);
if (tempNode) {
tempNode.height = height;
destNode.key = srcNode.key;
destNode.value = srcNode.value;
destNode.count = srcNode.count;
destNode.height = srcNode.height;
destNode.key = srcNode.key;
destNode.value = srcNode.value;
destNode.count = srcNode.count;
destNode.height = srcNode.height;
srcNode.key = tempNode.key;
srcNode.value = tempNode.value;
srcNode.count = tempNode.count;
srcNode.height = tempNode.height;
srcNode.key = tempNode.key;
srcNode.value = tempNode.value;
srcNode.count = tempNode.count;
srcNode.height = tempNode.height;
}
return destNode;
}
return destNode;
}
/**
* The function sets the value of the "_count" property.
* @param {number} v - number
*/
protected _setCount(v: number) {
this._count = v;
return undefined;
}
}

View file

@ -29,3 +29,9 @@ export type BiTreeDeleteResult<N> = { deleted: N | null | undefined; needBalance
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>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type BinaryTreeOptions = { iterationType?: IterationType }
//
// export type BTNIdentifierOrNU<N> = BTNKey | N | null | undefined;
//
// export type BTNIdentifierOrU<N> = BTNKey | N | undefined;
//
// export type BTNOrNU<N> = N | null | undefined;

View file

@ -1,8 +1,8 @@
import {RBTreeNode} from '../../../data-structures';
import {RedBlackTreeNode} from '../../../data-structures';
import {BSTOptions} from "./bst";
export enum RBTNColor { RED = 1, BLACK = 0}
export type RBTreeNodeNested<T> = RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, RBTreeNode<T, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type RedBlackTreeNodeNested<T> = RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, RedBlackTreeNode<T, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type RBTreeOptions = BSTOptions & {};

View file

@ -1,4 +1,4 @@
import {IterationType, RBTNColor, RBTreeNode, RedBlackTree} from '../../../../src';
import {IterationType, RBTNColor, RedBlackTreeNode, RedBlackTree} from '../../../../src';
import {getRandomInt} from '../../../utils';
import {isDebugTest} from '../../../config';
@ -17,9 +17,9 @@ describe('RedBlackTree', () => {
tree.add(20);
tree.add(5);
expect(tree.getNode(10)).toBeInstanceOf(RBTreeNode);
expect(tree.getNode(20)).toBeInstanceOf(RBTreeNode);
expect(tree.getNode(5)).toBeInstanceOf(RBTreeNode);
expect(tree.getNode(10)).toBeInstanceOf(RedBlackTreeNode);
expect(tree.getNode(20)).toBeInstanceOf(RedBlackTreeNode);
expect(tree.getNode(5)).toBeInstanceOf(RedBlackTreeNode);
expect(tree.getNode(15)).toBe(undefined);
});
@ -27,8 +27,8 @@ describe('RedBlackTree', () => {
tree.add(-10);
tree.add(-20);
expect(tree.getNode(-10)).toBeInstanceOf(RBTreeNode);
expect(tree.getNode(-20)).toBeInstanceOf(RBTreeNode);
expect(tree.getNode(-10)).toBeInstanceOf(RedBlackTreeNode);
expect(tree.getNode(-20)).toBeInstanceOf(RedBlackTreeNode);
});
});
@ -61,7 +61,7 @@ describe('RedBlackTree', () => {
tree.add(3);
const minNode = tree.getLeftMost(tree.root);
expect(minNode.key).toBe(3);
expect(minNode?.key).toBe(3);
});
test('should handle an empty tree', () => {
@ -79,7 +79,7 @@ describe('RedBlackTree', () => {
tree.add(25);
const maxNode = tree.getRightMost(tree.root);
expect(maxNode.key).toBe(25);
expect(maxNode?.key).toBe(25);
});
test('should handle an empty tree', () => {
@ -387,7 +387,7 @@ describe('RedBlackTree', () => {
tree.add(15);
const nodeLM = tree.getLeftMost();
expect(nodeLM.key).toBe(1);
expect(nodeLM?.key).toBe(1);
const node50 = tree.getNode(50);
expect(node50?.key).toBe(50);