docs: Verify the time and space complexity for each method.

feat: Add the cutRest method to Deque.
refactor: Update the cut method in Deque to support the isCutSelf parameter.
This commit is contained in:
Revone 2024-01-04 16:28:17 +08:00
parent ce6440bfa2
commit eaf8912746
12 changed files with 1011 additions and 1087 deletions

View file

@ -939,43 +939,43 @@ We strictly adhere to computer science theory and software development standards
[//]: # (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>120.95</td><td>8.27</td><td>0.00</td></tr><tr><td>10,000 add & delete randomly</td><td>180.36</td><td>5.54</td><td>0.00</td></tr><tr><td>10,000 addMany</td><td>137.91</td><td>7.25</td><td>0.02</td></tr><tr><td>10,000 get</td><td>49.52</td><td>20.19</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>119.60</td><td>8.36</td><td>0.00</td></tr><tr><td>10,000 add & delete randomly</td><td>178.17</td><td>5.61</td><td>0.00</td></tr><tr><td>10,000 addMany</td><td>129.03</td><td>7.75</td><td>7.48e-4</td></tr><tr><td>10,000 get</td><td>48.79</td><td>20.49</td><td>3.13e-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-overall</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 RBTree add</td><td>6.17</td><td>162.12</td><td>8.39e-5</td></tr><tr><td>10,000 RBTree add & delete randomly</td><td>16.24</td><td>61.59</td><td>7.03e-4</td></tr><tr><td>10,000 RBTree get</td><td>21.72</td><td>46.05</td><td>0.01</td></tr><tr><td>10,000 AVLTree add</td><td>126.30</td><td>7.92</td><td>0.01</td></tr><tr><td>10,000 AVLTree add & delete randomly</td><td>187.04</td><td>5.35</td><td>0.00</td></tr><tr><td>10,000 AVLTree get</td><td>0.91</td><td>1095.03</td><td>1.07e-5</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>10,000 RBTree add</td><td>5.80</td><td>172.50</td><td>7.88e-5</td></tr><tr><td>10,000 RBTree add & delete randomly</td><td>16.33</td><td>61.24</td><td>0.00</td></tr><tr><td>10,000 RBTree get</td><td>20.95</td><td>47.74</td><td>0.00</td></tr><tr><td>10,000 AVLTree add</td><td>131.91</td><td>7.58</td><td>0.01</td></tr><tr><td>10,000 AVLTree add & delete randomly</td><td>202.75</td><td>4.93</td><td>0.04</td></tr><tr><td>10,000 AVLTree get</td><td>1.02</td><td>984.65</td><td>2.43e-4</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>rb-tree</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>100,000 add</td><td>89.08</td><td>11.23</td><td>0.01</td></tr><tr><td>100,000 add & delete randomly</td><td>232.78</td><td>4.30</td><td>0.01</td></tr><tr><td>100,000 getNode</td><td>190.64</td><td>5.25</td><td>0.00</td></tr><tr><td>100,000 add & iterator</td><td>135.29</td><td>7.39</td><td>0.05</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>100,000 add</td><td>88.57</td><td>11.29</td><td>0.01</td></tr><tr><td>100,000 add & delete randomly</td><td>266.59</td><td>3.75</td><td>0.06</td></tr><tr><td>100,000 getNode</td><td>201.81</td><td>4.96</td><td>0.03</td></tr><tr><td>100,000 add & iterator</td><td>116.38</td><td>8.59</td><td>0.02</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>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.11</td><td>9163.90</td><td>9.52e-6</td></tr><tr><td>1,000 addEdge</td><td>6.11</td><td>163.62</td><td>1.43e-4</td></tr><tr><td>1,000 getVertex</td><td>0.05</td><td>2.14e+4</td><td>5.12e-7</td></tr><tr><td>1,000 getEdge</td><td>24.84</td><td>40.26</td><td>0.00</td></tr><tr><td>tarjan</td><td>236.10</td><td>4.24</td><td>0.02</td></tr><tr><td>tarjan all</td><td>6707.73</td><td>0.15</td><td>0.11</td></tr><tr><td>topologicalSort</td><td>192.62</td><td>5.19</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>9751.73</td><td>1.85e-6</td></tr><tr><td>1,000 addEdge</td><td>6.08</td><td>164.61</td><td>1.04e-4</td></tr><tr><td>1,000 getVertex</td><td>0.05</td><td>2.17e+4</td><td>3.55e-7</td></tr><tr><td>1,000 getEdge</td><td>25.95</td><td>38.53</td><td>0.01</td></tr><tr><td>tarjan</td><td>228.15</td><td>4.38</td><td>0.01</td></tr><tr><td>topologicalSort</td><td>187.15</td><td>5.34</td><td>0.00</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>hash-map</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 set</td><td>123.32</td><td>8.11</td><td>0.05</td></tr><tr><td>Native Map 1,000,000 set</td><td>232.46</td><td>4.30</td><td>0.03</td></tr><tr><td>Native Set 1,000,000 add</td><td>190.54</td><td>5.25</td><td>0.05</td></tr><tr><td>1,000,000 set & get</td><td>118.71</td><td>8.42</td><td>0.03</td></tr><tr><td>Native Map 1,000,000 set & get</td><td>294.15</td><td>3.40</td><td>0.04</td></tr><tr><td>Native Set 1,000,000 add & has</td><td>182.79</td><td>5.47</td><td>0.02</td></tr><tr><td>1,000,000 ObjKey set & get</td><td>331.70</td><td>3.01</td><td>0.06</td></tr><tr><td>Native Map 1,000,000 ObjKey set & get</td><td>282.44</td><td>3.54</td><td>0.06</td></tr><tr><td>Native Set 1,000,000 ObjKey add & has</td><td>290.19</td><td>3.45</td><td>0.07</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 set</td><td>117.95</td><td>8.48</td><td>0.04</td></tr><tr><td>Native Map 1,000,000 set</td><td>217.09</td><td>4.61</td><td>0.03</td></tr><tr><td>Native Set 1,000,000 add</td><td>168.56</td><td>5.93</td><td>0.02</td></tr><tr><td>1,000,000 set & get</td><td>121.33</td><td>8.24</td><td>0.03</td></tr><tr><td>Native Map 1,000,000 set & get</td><td>268.81</td><td>3.72</td><td>0.02</td></tr><tr><td>Native Set 1,000,000 add & has</td><td>172.46</td><td>5.80</td><td>0.01</td></tr><tr><td>1,000,000 ObjKey set & get</td><td>411.49</td><td>2.43</td><td>0.09</td></tr><tr><td>Native Map 1,000,000 ObjKey set & get</td><td>335.40</td><td>2.98</td><td>0.07</td></tr><tr><td>Native Set 1,000,000 ObjKey add & has</td><td>287.11</td><td>3.48</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'>heap</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>100,000 add & poll</td><td>24.36</td><td>41.06</td><td>0.00</td></tr><tr><td>100,000 add & dfs</td><td>32.10</td><td>31.15</td><td>3.40e-4</td></tr><tr><td>10,000 fib add & pop</td><td>354.32</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>100,000 add & poll</td><td>23.77</td><td>42.07</td><td>2.92e-4</td></tr><tr><td>100,000 add & dfs</td><td>36.94</td><td>27.07</td><td>0.01</td></tr><tr><td>10,000 fib add & pop</td><td>374.40</td><td>2.67</td><td>0.04</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>doubly-linked-list</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 push</td><td>215.49</td><td>4.64</td><td>0.02</td></tr><tr><td>1,000,000 unshift</td><td>229.17</td><td>4.36</td><td>0.05</td></tr><tr><td>1,000,000 unshift & shift</td><td>182.41</td><td>5.48</td><td>0.04</td></tr><tr><td>1,000,000 addBefore</td><td>313.24</td><td>3.19</td><td>0.05</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>235.15</td><td>4.25</td><td>0.05</td></tr><tr><td>1,000,000 unshift</td><td>221.59</td><td>4.51</td><td>0.08</td></tr><tr><td>1,000,000 unshift & shift</td><td>172.11</td><td>5.81</td><td>0.02</td></tr><tr><td>1,000,000 addBefore</td><td>322.82</td><td>3.10</td><td>0.04</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>singly-linked-list</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 push & shift</td><td>209.03</td><td>4.78</td><td>0.05</td></tr><tr><td>10,000 push & pop</td><td>217.38</td><td>4.60</td><td>0.01</td></tr><tr><td>10,000 addBefore</td><td>245.42</td><td>4.07</td><td>0.01</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 push & shift</td><td>212.64</td><td>4.70</td><td>0.07</td></tr><tr><td>10,000 push & pop</td><td>221.21</td><td>4.52</td><td>0.01</td></tr><tr><td>10,000 addBefore</td><td>251.81</td><td>3.97</td><td>0.01</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>priority-queue</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>100,000 add & poll</td><td>75.48</td><td>13.25</td><td>0.00</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>100,000 add & poll</td><td>75.00</td><td>13.33</td><td>9.50e-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>13.69</td><td>73.07</td><td>0.00</td></tr><tr><td>10,000 push & delete</td><td>4928.03</td><td>0.20</td><td>0.41</td></tr><tr><td>1,000,000 push & pop</td><td>25.16</td><td>39.74</td><td>0.01</td></tr><tr><td>100,000 push & shift</td><td>3.12</td><td>320.28</td><td>0.00</td></tr><tr><td>Native Array 100,000 push & shift</td><td>2216.18</td><td>0.45</td><td>0.08</td></tr><tr><td>100,000 unshift & shift</td><td>2.17</td><td>461.58</td><td>4.01e-4</td></tr><tr><td>Native Array 100,000 unshift & shift</td><td>4474.58</td><td>0.22</td><td>0.29</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>13.26</td><td>75.43</td><td>0.00</td></tr><tr><td>1,000,000 push & pop</td><td>21.24</td><td>47.08</td><td>1.57e-4</td></tr><tr><td>100,000 push & shift</td><td>2.20</td><td>453.65</td><td>5.13e-4</td></tr><tr><td>Native Array 100,000 push & shift</td><td>2165.42</td><td>0.46</td><td>0.19</td></tr><tr><td>100,000 unshift & shift</td><td>2.19</td><td>455.62</td><td>4.59e-4</td></tr><tr><td>Native Array 100,000 unshift & shift</td><td>4298.71</td><td>0.23</td><td>0.13</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>49.42</td><td>20.23</td><td>0.02</td></tr><tr><td>100,000 push & shift</td><td>5.21</td><td>191.82</td><td>9.75e-4</td></tr><tr><td>Native Array 100,000 push & shift</td><td>2328.85</td><td>0.43</td><td>0.25</td></tr><tr><td>Native Array 100,000 push & pop</td><td>4.44</td><td>225.24</td><td>1.83e-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,000 push</td><td>46.44</td><td>21.53</td><td>0.01</td></tr><tr><td>100,000 push & shift</td><td>5.00</td><td>199.87</td><td>1.37e-4</td></tr><tr><td>Native Array 100,000 push & shift</td><td>2276.16</td><td>0.44</td><td>0.12</td></tr><tr><td>Native Array 100,000 push & pop</td><td>4.33</td><td>230.72</td><td>1.58e-4</td></tr></table></div>
</div><div class="json-to-html-collapse clearfix 0">
<div class='collapsible level0' ><span class='json-to-html-label'>stack</span></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 push</td><td>45.54</td><td>21.96</td><td>0.01</td></tr><tr><td>1,000,000 push & pop</td><td>50.59</td><td>19.77</td><td>0.01</td></tr></table></div>
<div class="content"><table style="display: table; width:100%; table-layout: fixed;"><tr><th>test name</th><th>time taken (ms)</th><th>executions per sec</th><th>sample deviation</th></tr><tr><td>1,000,000 push</td><td>47.43</td><td>21.08</td><td>0.02</td></tr><tr><td>1,000,000 push & pop</td><td>50.64</td><td>19.75</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>47.74</td><td>20.95</td><td>0.00</td></tr><tr><td>100,000 getWords</td><td>94.40</td><td>10.59</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>47.83</td><td>20.91</td><td>0.00</td></tr><tr><td>100,000 getWords</td><td>100.67</td><td>9.93</td><td>0.01</td></tr></table></div>
</div>
[//]: # (No deletion!!! End of Replace Section)

View file

@ -93,13 +93,18 @@
},
"keywords": [
"data structure",
"data structures",
"javascript data structure",
"javascript data structures",
"typescript data structure",
"typescript data structures",
"js data structure",
"js data structures",
"data-structure",
"datastructure",
"javascript data structure",
"typescript data structure",
"js data structure",
"data",
"structure",
"structures",
"binary",
"depth",
"breadth",

View file

@ -198,7 +198,6 @@ export class AVLTree<
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
* constant time, as it performs a fixed number of operations. constant space, as it only uses a constant amount of memory.
*/
/**
@ -223,7 +222,6 @@ export class AVLTree<
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
* constant time, as it performs a fixed number of operations. constant space, as it only uses a constant amount of memory.
*/
/**
@ -243,65 +241,9 @@ export class AVLTree<
else node.height = 1 + Math.max(node.right.height, node.left.height);
}
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
* logarithmic time, where "n" is the number of nodes in the tree. The method traverses the path from the inserted node to the root. constant space, as it doesn't use additional data structures that scale with input size.
*/
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
*
* The `_balancePath` function is used to update the heights of nodes and perform rotation operations
* to restore balance in an AVL tree after inserting a node.
* @param {NODE} node - The `node` parameter in the `_balancePath` function represents the node in the
* AVL tree that needs to be balanced.
*/
protected _balancePath(node: KeyOrNodeOrEntry<K, V, NODE>): void {
node = this.ensureNode(node);
const path = this.getPathToRoot(node, false); // first O(log n) + O(log n)
for (let i = 0; i < path.length; i++) {
// second O(log n)
const A = path[i];
// Update Heights: After inserting a node, backtrack from the insertion point to the root node, updating the height of each node along the way.
this._updateHeight(A); // first O(1)
// Check Balance: Simultaneously with height updates, check if each node violates the balance property of an AVL tree.
// Balance Restoration: If a balance issue is discovered after inserting a node, it requires balance restoration operations. Balance restoration includes four basic cases where rotation operations need to be performed to fix the balance:
switch (
this._balanceFactor(A) // second O(1)
) {
case -2:
if (A && A.left) {
if (this._balanceFactor(A.left) <= 0) {
// second O(1)
// Left Rotation (LL Rotation): When the inserted node is in the left subtree of the left subtree, causing an imbalance.
this._balanceLL(A);
} else {
// Left-Right Rotation (LR Rotation): When the inserted node is in the right subtree of the left subtree, causing an imbalance.
this._balanceLR(A);
}
}
break;
case +2:
if (A && A.right) {
if (this._balanceFactor(A.right) >= 0) {
// Right Rotation (RR Rotation): When the inserted node is in the right subtree of the right subtree, causing an imbalance.
this._balanceRR(A);
} else {
// Right-Left Rotation (RL Rotation): When the inserted node is in the left subtree of the right subtree, causing an imbalance.
this._balanceRL(A);
}
}
}
// TODO So far, no sure if this is necessary that Recursive Repair: Once rotation operations are executed, it may cause imbalance issues at higher levels of the tree. Therefore, you need to recursively check and repair imbalance problems upwards until you reach the root node.
}
}
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
* constant time, as these methods perform a fixed number of operations. constant space, as they only use a constant amount of memory.
*/
/**
@ -491,6 +433,61 @@ export class AVLTree<
C && this._updateHeight(C);
}
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
* logarithmic time, where "n" is the number of nodes in the tree. The method traverses the path from the inserted node to the root. constant space, as it doesn't use additional data structures that scale with input size.
*/
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
*
* The `_balancePath` function is used to update the heights of nodes and perform rotation operations
* to restore balance in an AVL tree after inserting a node.
* @param {NODE} node - The `node` parameter in the `_balancePath` function represents the node in the
* AVL tree that needs to be balanced.
*/
protected _balancePath(node: KeyOrNodeOrEntry<K, V, NODE>): void {
node = this.ensureNode(node);
const path = this.getPathToRoot(node, false); // first O(log n) + O(log n)
for (let i = 0; i < path.length; i++) {
// second O(log n)
const A = path[i];
// Update Heights: After inserting a node, backtrack from the insertion point to the root node, updating the height of each node along the way.
this._updateHeight(A); // first O(1)
// Check Balance: Simultaneously with height updates, check if each node violates the balance property of an AVL tree.
// Balance Restoration: If a balance issue is discovered after inserting a node, it requires balance restoration operations. Balance restoration includes four basic cases where rotation operations need to be performed to fix the balance:
switch (
this._balanceFactor(A) // second O(1)
) {
case -2:
if (A && A.left) {
if (this._balanceFactor(A.left) <= 0) {
// second O(1)
// Left Rotation (LL Rotation): When the inserted node is in the left subtree of the left subtree, causing an imbalance.
this._balanceLL(A);
} else {
// Left-Right Rotation (LR Rotation): When the inserted node is in the right subtree of the left subtree, causing an imbalance.
this._balanceLR(A);
}
}
break;
case +2:
if (A && A.right) {
if (this._balanceFactor(A.right) >= 0) {
// Right Rotation (RR Rotation): When the inserted node is in the right subtree of the right subtree, causing an imbalance.
this._balanceRR(A);
} else {
// Right-Left Rotation (RL Rotation): When the inserted node is in the left subtree of the right subtree, causing an imbalance.
this._balanceRL(A);
}
}
}
// TODO So far, no sure if this is necessary that Recursive Repair: Once rotation operations are executed, it may cause imbalance issues at higher levels of the tree. Therefore, you need to recursively check and repair imbalance problems upwards until you reach the root node.
}
}
protected _replaceNode(oldNode: NODE, newNode: NODE): NODE {
newNode.height = oldNode.height;

File diff suppressed because it is too large Load diff

View file

@ -34,17 +34,10 @@ export class BSTNode<K = any, V = any, NODE extends BSTNode<K, V, NODE> = BSTNod
protected override _left?: NODE;
/**
* Get the left child node.
*/
override get left(): NODE | undefined {
return this._left;
}
/**
* Set the left child node.
* @param {NODE | undefined} v - The left child node.
*/
override set left(v: NODE | undefined) {
if (v) {
v.parent = this as unknown as NODE;
@ -54,17 +47,10 @@ export class BSTNode<K = any, V = any, NODE extends BSTNode<K, V, NODE> = BSTNod
protected override _right?: NODE;
/**
* Get the right child node.
*/
override get right(): NODE | undefined {
return this._right;
}
/**
* Set the right child node.
* @param {NODE | undefined} v - The right child node.
*/
override set right(v: NODE | undefined) {
if (v) {
v.parent = this as unknown as NODE;
@ -182,7 +168,6 @@ export class BST<
/**
* Time Complexity: O(log n)
* Space Complexity: O(log n)
* Average case for a balanced tree. Space for the recursive call stack in the worst case.
*/
/**
@ -224,7 +209,6 @@ export class BST<
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
* - Average case for a balanced tree. In the worst case (unbalanced tree), it can be O(n).
*/
/**
@ -266,7 +250,6 @@ export class BST<
} else if (this._compare(current.key, newNode.key) === CP.gt) {
if (current.left === undefined) {
current.left = newNode;
newNode.parent = current;
this._size++;
return true;
}
@ -274,7 +257,6 @@ export class BST<
} else {
if (current.right === undefined) {
current.right = newNode;
newNode.parent = current;
this._size++;
return true;
}
@ -287,13 +269,12 @@ export class BST<
/**
* Time Complexity: O(k log n)
* Space Complexity: O(k)
* Adding each element individually in a balanced tree. Additional space is required for the sorted array.
* Space Complexity: O(k + log n)
*/
/**
* Time Complexity: O(k log n)
* Space Complexity: O(k)
* Space Complexity: O(k + log n)
*
* The `addMany` function in TypeScript adds multiple keys or nodes to a binary tree, optionally
* balancing the tree after each addition.
@ -443,13 +424,12 @@ export class BST<
/**
* Time Complexity: O(log n)
* Space Complexity: O(log n)
* Average case for a balanced tree. O(n) - Visiting each node once when identifier is not node's key. Space for the recursive call stack in the worst case.
* Space Complexity: O(k + log n)
* /
/**
* Time Complexity: O(log n)
* Space Complexity: O(log n)
* Space Complexity: O(k + log n)
*
* The function `getNodes` returns an array of nodes that match a given identifier, using either a
* recursive or iterative approach.
@ -526,26 +506,6 @@ export class BST<
return ans;
}
// /**
// * The function overrides the subTreeTraverse method and returns the result of calling the super
// * method with the provided arguments.
// * @param {C} callback - The `callback` parameter is a function that will be called for each node in
// * the subtree traversal. It should accept a single parameter of type `NODE`, which represents a node in
// * the tree. The return type of the callback function can be any type.
// * @param beginRoot - The `beginRoot` parameter is the starting point for traversing the subtree. It
// * can be either a key, a node, or an entry.
// * @param iterationType - The `iterationType` parameter is used to specify the type of iteration to
// * be performed during the traversal of the subtree. It can have one of the following values:
// * @returns The method is returning an array of the return type of the callback function.
// */
// override subTreeTraverse<C extends BTNCallback<NODE>>(
// callback: C = this._defaultOneParamCallback as C,
// beginRoot: KeyOrNodeOrEntry<K, V, NODE> = this.root,
// iterationType = this.iterationType
// ): ReturnType<C>[] {
// return super.subTreeTraverse(callback, beginRoot, iterationType, false);
// }
/**
* Time complexity: O(n)
* Space complexity: O(n)
@ -641,14 +601,13 @@ export class BST<
}
/**
* Time Complexity: O(n log n)
* Space Complexity: O(n)
* Adding each element individually in a balanced tree. Additional space is required for the sorted array.
* Time Complexity: O(log n)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(n log n)
* Space Complexity: O(n)
* Time Complexity: O(log n)
* Space Complexity: O(1)
*
* The `lastKey` function returns the key of the rightmost node in a binary tree, or the key of the
* leftmost node if the comparison result is greater than.
@ -680,7 +639,6 @@ export class BST<
/**
* Time Complexity: O(log n)
* Space Complexity: O(log n)
* Average case for a balanced tree. O(n) - Visiting each node once when identifier is not node's key. Space for the recursive call stack in the worst case.
*/
/**
@ -809,8 +767,8 @@ export class BST<
*/
/**
* Time Complexity: O(n) - Building a balanced tree from a sorted array.
* Space Complexity: O(n) - Additional space is required for the sorted array.
* Time Complexity: O(n)
* Space Complexity: O(log n)
*/
/**

View file

@ -10,7 +10,6 @@ import {
BinaryTreeDeleteResult,
BSTNKeyOrNode,
BTNCallback,
IterationType,
KeyOrNodeOrEntry,
RBTNColor,
RBTreeOptions,
@ -150,11 +149,6 @@ export class RedBlackTree<
return keyOrNodeOrEntry instanceof RedBlackTreeNode;
}
/**
* Time Complexity: O(log n) on average (where n is the number of nodes in the tree)
* Space Complexity: O(1)
*/
override isRealNode(node: NODE | undefined): node is NODE {
if (node === this.Sentinel || node === undefined) return false;
return node instanceof RedBlackTreeNode;
@ -163,7 +157,7 @@ export class RedBlackTree<
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
* on average (where n is the number of nodes in the tree)
* On average (where n is the number of nodes in the tree)
*/
/**
@ -232,7 +226,6 @@ export class RedBlackTree<
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
* on average (where n is the number of nodes in the tree)
*/
/**
@ -311,27 +304,6 @@ export class RedBlackTree<
return ans;
}
getNode<C extends BTNCallback<NODE, K>>(
identifier: K,
callback?: C,
beginRoot?: NODE | undefined,
iterationType?: IterationType
): NODE | undefined;
getNode<C extends BTNCallback<NODE, NODE>>(
identifier: NODE | undefined,
callback?: C,
beginRoot?: NODE | undefined,
iterationType?: IterationType
): NODE | undefined;
getNode<C extends BTNCallback<NODE>>(
identifier: ReturnType<C>,
callback: C,
beginRoot?: NODE | undefined,
iterationType?: IterationType
): NODE | undefined;
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
@ -369,6 +341,16 @@ export class RedBlackTree<
return this.getNodes(identifier, callback, true, beginRoot, iterationType)[0] ?? undefined;
}
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*/
override clear() {
this._root = this.Sentinel;
this._size = 0;
}
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
@ -397,16 +379,6 @@ export class RedBlackTree<
return y!;
}
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*/
override clear() {
this._root = this.Sentinel;
this._size = 0;
}
protected override _setRoot(v: NODE) {
if (v) {
v.parent = undefined;
@ -479,6 +451,65 @@ export class RedBlackTree<
}
}
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
*
* The `_fixInsert` function is used to fix the red-black tree after an insertion operation.
* @param {RedBlackTreeNode} k - The parameter `k` is a RedBlackTreeNode object, which represents a node in a
* red-black tree.
*/
protected _fixInsert(k: NODE): void {
let u: NODE | undefined;
while (k.parent && k.parent.color === 1) {
if (k.parent.parent && k.parent === k.parent.parent.right) {
u = k.parent.parent.left;
if (u && u.color === 1) {
u.color = RBTNColor.BLACK;
k.parent.color = RBTNColor.BLACK;
k.parent.parent.color = RBTNColor.RED;
k = k.parent.parent;
} else {
if (k === k.parent.left) {
k = k.parent;
this._rightRotate(k);
}
k.parent!.color = RBTNColor.BLACK;
k.parent!.parent!.color = RBTNColor.RED;
this._leftRotate(k.parent!.parent!);
}
} else {
u = k.parent.parent!.right;
if (u && u.color === 1) {
u.color = RBTNColor.BLACK;
k.parent.color = RBTNColor.BLACK;
k.parent.parent!.color = RBTNColor.RED;
k = k.parent.parent!;
} else {
if (k === k.parent.right) {
k = k.parent;
this._leftRotate(k);
}
k.parent!.color = RBTNColor.BLACK;
k.parent!.parent!.color = RBTNColor.RED;
this._rightRotate(k.parent!.parent!);
}
}
if (k === this.root) {
break;
}
}
this.root.color = RBTNColor.BLACK;
}
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
@ -575,65 +606,6 @@ export class RedBlackTree<
v.parent = u.parent;
}
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
*
* The `_fixInsert` function is used to fix the red-black tree after an insertion operation.
* @param {RedBlackTreeNode} k - The parameter `k` is a RedBlackTreeNode object, which represents a node in a
* red-black tree.
*/
protected _fixInsert(k: NODE): void {
let u: NODE | undefined;
while (k.parent && k.parent.color === 1) {
if (k.parent.parent && k.parent === k.parent.parent.right) {
u = k.parent.parent.left;
if (u && u.color === 1) {
u.color = RBTNColor.BLACK;
k.parent.color = RBTNColor.BLACK;
k.parent.parent.color = RBTNColor.RED;
k = k.parent.parent;
} else {
if (k === k.parent.left) {
k = k.parent;
this._rightRotate(k);
}
k.parent!.color = RBTNColor.BLACK;
k.parent!.parent!.color = RBTNColor.RED;
this._leftRotate(k.parent!.parent!);
}
} else {
u = k.parent.parent!.right;
if (u && u.color === 1) {
u.color = RBTNColor.BLACK;
k.parent.color = RBTNColor.BLACK;
k.parent.parent!.color = RBTNColor.RED;
k = k.parent.parent!;
} else {
if (k === k.parent.right) {
k = k.parent;
this._leftRotate(k);
}
k.parent!.color = RBTNColor.BLACK;
k.parent!.parent!.color = RBTNColor.RED;
this._rightRotate(k.parent!.parent!);
}
}
if (k === this.root) {
break;
}
}
this.root.color = RBTNColor.BLACK;
}
/**
* The function replaces an old node with a new node while preserving the color of the old node.
* @param {NODE} oldNode - The `oldNode` parameter represents the node that needs to be replaced in a

View file

@ -136,7 +136,6 @@ export class TreeMultimap<
/**
* Time Complexity: O(log n)
* Space Complexity: O(1)
* logarithmic time, where "n" is the number of nodes in the tree. The add method of the superclass (AVLTree) has logarithmic time complexity. constant space, as it doesn't use additional data structures that scale with input size.
*/
/**
@ -168,88 +167,12 @@ export class TreeMultimap<
}
/**
* Time Complexity: O(k log n)
* Time Complexity: O(log n)
* Space Complexity: O(1)
* logarithmic time, where "n" is the number of nodes in the tree. The add method of the superclass (AVLTree) has logarithmic time complexity. constant space, as it doesn't use additional data structures that scale with input size.
*/
/**
* Time Complexity: O(k log n)
* Space Complexity: O(1)
*
* The function overrides the addMany method to add multiple keys, nodes, or entries to a data
* structure.
* @param keysOrNodesOrEntries - The parameter `keysOrNodesOrEntries` is an iterable that can contain
* either keys, nodes, or entries.
* @returns The method is returning an array of type `NODE | undefined`.
*/
override addMany(keysOrNodesOrEntries: Iterable<KeyOrNodeOrEntry<K, V, NODE>>): boolean[] {
return super.addMany(keysOrNodesOrEntries);
}
/**
* Time Complexity: O(n log n)
* Space Complexity: O(n)
* logarithmic time for each insertion, where "n" is the number of nodes in the tree. This is because the method calls the add method for each node. linear space, as it creates an array to store the sorted nodes.
*/
/**
* Time Complexity: O(n log n)
* Space Complexity: O(n)
*
* The `perfectlyBalance` function takes a sorted array of nodes and builds a balanced binary search
* tree using either a recursive or iterative approach.
* @param iterationType - The `iterationType` parameter is an optional parameter that specifies the
* type of iteration to use when building the balanced binary search tree. It can have two possible
* values:
* @returns a boolean value.
*/
override perfectlyBalance(iterationType = this.iterationType): boolean {
const sorted = this.dfs(node => node, 'in'),
n = sorted.length;
if (sorted.length < 1) return false;
this.clear();
if (iterationType === IterationType.RECURSIVE) {
const buildBalanceBST = (l: number, r: number) => {
if (l > r) return;
const m = l + Math.floor((r - l) / 2);
const midNode = sorted[m];
this.add(midNode.key, midNode.value, midNode.count);
buildBalanceBST(l, m - 1);
buildBalanceBST(m + 1, r);
};
buildBalanceBST(0, n - 1);
return true;
} else {
const stack: [[number, number]] = [[0, n - 1]];
while (stack.length > 0) {
const popped = stack.pop();
if (popped) {
const [l, r] = popped;
if (l <= r) {
const m = l + Math.floor((r - l) / 2);
const midNode = sorted[m];
this.add(midNode.key, midNode.value, midNode.count);
stack.push([m + 1, r]);
stack.push([l, m - 1]);
}
}
}
return true;
}
}
/**
* Time Complexity: O(k log n)
* Space Complexity: O(1)
* logarithmic time for each insertion, where "n" is the number of nodes in the tree, and "k" is the number of keys to be inserted. This is because the method iterates through the keys and calls the add method for each. constant space, as it doesn't use additional data structures that scale with input size.
*/
/**
* Time Complexity: O(k log n)
* Time Complexity: O(log n)
* Space Complexity: O(1)
*
* The `delete` function in TypeScript is used to remove a node from a binary tree, taking into
@ -343,6 +266,60 @@ export class TreeMultimap<
this._count = 0;
}
/**
* Time Complexity: O(n log n)
* Space Complexity: O(log n)
*/
/**
* Time Complexity: O(n log n)
* Space Complexity: O(log n)
*
* The `perfectlyBalance` function takes a sorted array of nodes and builds a balanced binary search
* tree using either a recursive or iterative approach.
* @param iterationType - The `iterationType` parameter is an optional parameter that specifies the
* type of iteration to use when building the balanced binary search tree. It can have two possible
* values:
* @returns a boolean value.
*/
override perfectlyBalance(iterationType = this.iterationType): boolean {
const sorted = this.dfs(node => node, 'in'),
n = sorted.length;
if (sorted.length < 1) return false;
this.clear();
if (iterationType === IterationType.RECURSIVE) {
const buildBalanceBST = (l: number, r: number) => {
if (l > r) return;
const m = l + Math.floor((r - l) / 2);
const midNode = sorted[m];
this.add(midNode.key, midNode.value, midNode.count);
buildBalanceBST(l, m - 1);
buildBalanceBST(m + 1, r);
};
buildBalanceBST(0, n - 1);
return true;
} else {
const stack: [[number, number]] = [[0, n - 1]];
while (stack.length > 0) {
const popped = stack.pop();
if (popped) {
const [l, r] = popped;
if (l <= r) {
const m = l + Math.floor((r - l) / 2);
const midNode = sorted[m];
this.add(midNode.key, midNode.value, midNode.count);
stack.push([m + 1, r]);
stack.push([l, m - 1]);
}
}
}
return true;
}
}
/**
* Time complexity: O(n)
* Space complexity: O(n)

View file

@ -360,7 +360,7 @@ export class Deque<E> extends IterableElementBase<E> {
for (let i = pos; i < this.size; ++i) {
arr.push(this.at(i));
}
this.cut(pos - 1);
this.cut(pos - 1, true);
for (let i = 0; i < num; ++i) this.push(element);
for (let i = 0; i < arr.length; ++i) this.push(arr[i]);
}
@ -380,18 +380,51 @@ export class Deque<E> extends IterableElementBase<E> {
* updated size.
* @param {number} pos - The `pos` parameter represents the position at which the string should be
* cut. It is a number that indicates the index of the character where the cut should be made.
* @param {boolean} isCutSelf - If true, the original deque will not be cut, and return a new deque
* @returns The method is returning the updated size of the data structure.
*/
cut(pos: number): number {
if (pos < 0) {
this.clear();
return 0;
cut(pos: number, isCutSelf = false): Deque<E> {
if (isCutSelf) {
if (pos < 0) {
this.clear();
return this;
}
const { bucketIndex, indexInBucket } = this._getBucketAndPosition(pos);
this._bucketLast = bucketIndex;
this._lastInBucket = indexInBucket;
this._size = pos + 1;
return this;
} else {
const newDeque = new Deque<E>([], { bucketSize: this._bucketSize });
for (let i = 0; i <= pos; i++) {
newDeque.push(this.at(i));
}
return newDeque;
}
}
cutRest(pos: number, isCutSelf = false): Deque<E> {
if (isCutSelf) {
if (pos < 0) {
this.clear();
return this;
}
const { bucketIndex, indexInBucket } = this._getBucketAndPosition(pos);
this._bucketFirst = bucketIndex;
this._firstInBucket = indexInBucket;
this._size = this._size - pos;
return this;
} else {
const newDeque = new Deque<E>([], { bucketSize: this._bucketSize });
for (let i = pos; i < this.size; i++) {
newDeque.push(this.at(i));
}
return newDeque;
}
const { bucketIndex, indexInBucket } = this._getBucketAndPosition(pos);
this._bucketLast = bucketIndex;
this._lastInBucket = indexInBucket;
this._size = pos + 1;
return this.size;
}
/**
@ -456,7 +489,7 @@ export class Deque<E> extends IterableElementBase<E> {
}
i += 1;
}
this.cut(index - 1);
this.cut(index - 1, true);
return true;
}
@ -512,7 +545,7 @@ export class Deque<E> extends IterableElementBase<E> {
this.setAt(index++, cur);
}
}
this.cut(index - 1);
this.cut(index - 1, true);
return this;
}

View file

@ -28,9 +28,9 @@ suite
.add(`tarjan`, () => {
graph.tarjan(true);
})
.add(`tarjan all`, () => {
graph.tarjan(true, true, true, true);
})
// .add(`tarjan all`, () => {
// graph.tarjan(true, true, true, true);
// })
.add(`topologicalSort`, () => {
graph.topologicalSort('key');
});

View file

@ -1,11 +1,12 @@
import { Deque } from '../../../../src';
import { Deque as CDeque } from 'js-sdsl';
import * as Benchmark from 'benchmark';
import { getRandomInt, magnitude } from '../../../utils';
import { magnitude } from '../../../utils';
import { isCompetitor } from '../../../config';
export const suite = new Benchmark.Suite();
const { MILLION, HUNDRED_THOUSAND, TEN_THOUSAND } = magnitude;
const { MILLION, HUNDRED_THOUSAND } = magnitude;
// const randomIndicesTenThousand = new Array(TEN_THOUSAND).fill(getRandomInt(0, TEN_THOUSAND - 1));
suite.add(`${MILLION.toLocaleString()} push`, () => {
const deque = new Deque<number>();
@ -14,45 +15,45 @@ suite.add(`${MILLION.toLocaleString()} push`, () => {
if (isCompetitor) {
suite.add(`CPT ${MILLION.toLocaleString()} push`, () => {
const _deque = new CDeque<number>();
for (let i = 0; i < MILLION; i++) _deque.pushBack(i);
const deque = new CDeque<number>();
for (let i = 0; i < MILLION; i++) deque.pushBack(i);
});
}
suite
.add(`${TEN_THOUSAND.toLocaleString()} push & delete`, () => {
const _deque = new Deque<number>();
for (let i = 0; i < TEN_THOUSAND; i++) _deque.push(i);
for (let i = 0; i < TEN_THOUSAND; i++) _deque.delete(getRandomInt(0, TEN_THOUSAND - 1));
})
// .add(`${TEN_THOUSAND.toLocaleString()} push & delete`, () => {
// const deque = new Deque<number>();
//
// for (let i = 0; i < TEN_THOUSAND; i++) deque.push(i);
// for (let i = 0; i < TEN_THOUSAND; i++) deque.delete(randomIndicesTenThousand[i]);
// })
.add(`${MILLION.toLocaleString()} push & pop`, () => {
const _deque = new Deque<number>();
const deque = new Deque<number>();
for (let i = 0; i < MILLION; i++) _deque.push(i);
for (let i = 0; i < MILLION; i++) _deque.pop();
for (let i = 0; i < MILLION; i++) deque.push(i);
for (let i = 0; i < MILLION; i++) deque.pop();
})
.add(`${HUNDRED_THOUSAND.toLocaleString()} push & shift`, () => {
const _deque = new Deque<number>();
const deque = new Deque<number>();
for (let i = 0; i < HUNDRED_THOUSAND; i++) _deque.push(i);
for (let i = 0; i < HUNDRED_THOUSAND; i++) _deque.shift();
for (let i = 0; i < HUNDRED_THOUSAND; i++) deque.push(i);
for (let i = 0; i < HUNDRED_THOUSAND; i++) deque.shift();
})
.add(`Native Array ${HUNDRED_THOUSAND.toLocaleString()} push & shift`, () => {
const _deque = new Array<number>();
const array = new Array<number>();
for (let i = 0; i < HUNDRED_THOUSAND; i++) _deque.push(i);
for (let i = 0; i < HUNDRED_THOUSAND; i++) _deque.shift();
for (let i = 0; i < HUNDRED_THOUSAND; i++) array.push(i);
for (let i = 0; i < HUNDRED_THOUSAND; i++) array.shift();
})
.add(`${HUNDRED_THOUSAND.toLocaleString()} unshift & shift`, () => {
const _deque = new Deque<number>();
const deque = new Deque<number>();
for (let i = 0; i < HUNDRED_THOUSAND; i++) _deque.unshift(i);
for (let i = 0; i < HUNDRED_THOUSAND; i++) _deque.shift();
for (let i = 0; i < HUNDRED_THOUSAND; i++) deque.unshift(i);
for (let i = 0; i < HUNDRED_THOUSAND; i++) deque.shift();
})
.add(`Native Array ${HUNDRED_THOUSAND.toLocaleString()} unshift & shift`, () => {
const _deque = new Array<number>();
const array = new Array<number>();
for (let i = 0; i < HUNDRED_THOUSAND; i++) _deque.unshift(i);
for (let i = 0; i < HUNDRED_THOUSAND; i++) _deque.shift();
for (let i = 0; i < HUNDRED_THOUSAND; i++) array.unshift(i);
for (let i = 0; i < HUNDRED_THOUSAND; i++) array.shift();
});

View file

@ -811,309 +811,251 @@ describe('DirectedGraph getCycles', () => {
});
});
describe('DirectedGraph tarjan', () => {
test('should simple cycles graph tarjan cycles return correct result', () => {
const graph = new DirectedGraph();
graph.addVertex('A');
graph.addVertex('B');
graph.addVertex('C');
graph.addVertex('D');
graph.addEdge('A', 'B');
graph.addEdge('B', 'C');
graph.addEdge('C', 'A');
graph.addEdge('A', 'D');
graph.addEdge('D', 'C');
const cycles = graph.tarjan(false,false,false,true)
.cycles;
expect(cycles.size).toBe(2);
expect(getAsVerticesArrays(cycles)).toEqual([
['A', 'B', 'C'],
['A', 'D', 'C']
]);
});
function getAsVerticesArrays(vss: Map<number, DirectedVertex<any>[]>) {
return [...vss.values()]
.map(vs =>
vs.map(vertex => vertex.key)
);
}
function createExampleGraph1() {
const graph = new DirectedGraph();
graph.addVertex('A');
graph.addVertex('B');
graph.addVertex('C');
graph.addVertex('D');
graph.addVertex('E');
graph.addEdge('A', 'B');
graph.addEdge('A', 'C');
graph.addEdge('B', 'D');
graph.addEdge('C', 'D');
graph.addEdge('D', 'E');
graph.addEdge('E', 'B');
return graph;
}
test('should tarjan cycles return correct result', () => {
const graph = createExampleGraph1();
const cycles = graph
.tarjan(false,false,false,true)
.cycles;
expect(cycles.size).toBe(1);
expect(getAsVerticesArrays(cycles)).toEqual([['B', 'D', 'E']]);
});
test('should tarjan SCCs return correct result', () => {
const graph = createExampleGraph1();
const sccs = graph
.tarjan(false,false,true,false)
.SCCs;
expect(sccs.size).toBe(3);
expect(getAsVerticesArrays(sccs)).toEqual([['A'],['C'],['B', 'D', 'E']]);
});
test('should tarjan cut vertexes return correct result', () => {
const graph = createExampleGraph1();
const cutVertexes = graph
.tarjan(true,false,false,false)
.cutVertexes;
expect(cutVertexes.length).toBe(0);
});
test('should tarjan bridges return correct result', () => {
const graph = createExampleGraph1();
const bridges = graph
.tarjan(false,true,false,false)
.bridges;
expect(bridges.length).toBe(0);
});
function createExampleGraph2() {
const graph = createExampleGraph1();
graph.addVertex('F');
graph.addVertex('G');
graph.addEdge('B', 'F');
graph.addEdge('F', 'E');
graph.addEdge('C', 'G');
graph.addEdge('G', 'A');
return graph;
}
test('should 3 cycles graph tarjan cycles return correct result', () => {
const graph = createExampleGraph2();
const cycles = graph
.tarjan(false,false,false,true)
.cycles;
expect(cycles.size).toBe(3);
expect(getAsVerticesArrays(cycles)).toEqual([
['A', 'C', 'G'],
['B', 'D', 'E'],
['B', 'F', 'E']
]);
});
test('should 3 cycles graph tarjan SCCs return correct result', () => {
const graph = createExampleGraph2();
const sccs = graph
.tarjan(false,false,true,false)
.SCCs;
expect(sccs.size).toBe(2);
expect(getAsVerticesArrays(sccs)).toEqual([
['A', 'C', 'G'],
['B', 'D', 'E', 'F']
]);
});
test('should 3 cycles graph tarjan cut vertexes return correct result', () => {
const graph = createExampleGraph1();
const cutVertexes = graph
.tarjan(true,false,false,false)
.cutVertexes;
expect(cutVertexes.length).toBe(0);
});
test('should 3 cycles graph tarjan bridges return correct result', () => {
const graph = createExampleGraph1();
const bridges = graph
.tarjan(false,true,false,false)
.bridges;
expect(bridges.length).toBe(0);
});
function createExampleGraph3() {
const graph = new DirectedGraph();
graph.addVertex('A');
graph.addVertex('B');
graph.addVertex('C');
graph.addVertex('D');
graph.addVertex('E');
graph.addVertex('F');
graph.addVertex('G');
graph.addEdge('A', 'B');
graph.addEdge('B', 'C');
graph.addEdge('C', 'D');
graph.addEdge('D', 'B');
graph.addEdge('A', 'E');
graph.addEdge('E', 'F');
graph.addEdge('F', 'G');
graph.addEdge('G', 'E');
return graph;
}
test('should cuttable graph tarjan cycles return correct result', () => {
const graph = createExampleGraph3();
const cycles = graph
.tarjan(false,false,false,true)
.cycles;
expect(cycles.size).toBe(2);
expect(getAsVerticesArrays(cycles)).toEqual([
['B', 'C', 'D'],
['E', 'F', 'G']
]);
});
test('should cuttable graph tarjan SCCs return correct result', () => {
const graph = createExampleGraph3();
const sccs = graph
.tarjan(false,false,true,false)
.SCCs;
expect(sccs.size).toBe(3);
expect(getAsVerticesArrays(sccs)).toEqual([
['A'],
['B', 'C', 'D'],
['E', 'F', 'G']
]);
});
test('should cuttable graph tarjan cut vertexes return correct result', () => {
const graph = createExampleGraph3();
const cutVertexes = graph
.tarjan(true,false,false,false)
.cutVertexes;
expect(cutVertexes.length).toBe(3);
expect(cutVertexes.map(cv => cv.key)).toEqual(['B', 'E', 'A']);
});
test('should cuttable graph tarjan bridges return correct result', () => {
const graph = createExampleGraph3();
const bridges = graph
.tarjan(false,true,false,false)
.bridges;
expect(bridges.length).toBe(2);
expect(bridges.map(b => ""+b.src+b.dest)).toEqual(['AB', 'AE']);
});
function createExampleGraph4() {
const graph = createExampleGraph3();
graph.addVertex('H');
graph.addVertex('I');
graph.addVertex('J');
graph.addVertex('K');
graph.addEdge('C', 'H');
graph.addEdge('H', 'I');
graph.addEdge('I', 'D');
graph.addEdge('H', 'J');
graph.addEdge('J', 'K');
graph.addEdge('K', 'H');
return graph;
}
test('should more cuttable graph tarjan cycles return correct result', () => {
const graph = createExampleGraph4();
const cycles = graph
.tarjan(false,false,false,true)
.cycles;
expect(cycles.size).toBe(4);
expect(getAsVerticesArrays(cycles)).toEqual([
['B', 'C', 'D'],
['H', 'J', 'K'],
['E', 'F', 'G'],
['B', 'C', 'H', 'I', 'D'],
]);
});
test('should more cuttable graph tarjan SCCs return correct result', () => {
const graph = createExampleGraph4();
const sccs = graph
.tarjan(false,false,true,false)
.SCCs;
expect(sccs.size).toBe(3);
expect(getAsVerticesArrays(sccs)).toEqual([
['A'],
['B', 'C', 'D', 'H', 'I', 'J', 'K'],
['E', 'F', 'G']
]);
});
test('should more cuttable graph tarjan cut vertexes return correct result', () => {
const graph = createExampleGraph4();
const cutVertexes = graph
.tarjan(true,false,false,false)
.cutVertexes;
expect(cutVertexes.length).toBe(4);
expect(cutVertexes.map(cv => cv.key)).toEqual(['B', 'E', 'A', 'H']);
});
test('should more cuttable graph tarjan bridges return correct result', () => {
const graph = createExampleGraph4();
const bridges = graph
.tarjan(false,true,false,false)
.bridges;
expect(bridges.length).toBe(2);
expect(bridges.map(b => ""+b.src+b.dest)).toEqual(['AB', 'AE']);
});
function createExampleGraph5() {
const graph = createExampleGraph4();
graph.addEdge('F', 'H');
return graph;
}
test('should uncuttable graph tarjan cycles return correct result', () => {
const graph = createExampleGraph5();
const cycles = graph
.tarjan(false,false,false,true)
.cycles;
expect(cycles.size).toBe(4);
expect(getAsVerticesArrays(cycles)).toEqual([
['B', 'C', 'D'],
['H', 'J', 'K'],
['E', 'F', 'G'],
['B', 'C', 'H', 'I', 'D'],
]);
});
test('should uncuttable graph tarjan SCCs return correct result', () => {
const graph = createExampleGraph5();
const sccs = graph
.tarjan(false,false,true,false)
.SCCs;
expect(sccs.size).toBe(3);
expect(getAsVerticesArrays(sccs)).toEqual([
['A'],
['B', 'C', 'D', 'H', 'I', 'J', 'K'],
['E', 'F', 'G']
]);
});
test('should uncuttable graph tarjan cut vertexes return correct result', () => {
const graph = createExampleGraph5();
const cutVertexes = graph
.tarjan(true,false,false,false)
.cutVertexes;
expect(cutVertexes.length).toBe(0);
});
test('should uncuttable graph tarjan bridges return correct result', () => {
const graph = createExampleGraph5();
const bridges = graph
.tarjan(false,true,false,false)
.bridges;
expect(bridges.length).toBe(0);
});
});
// describe('DirectedGraph tarjan', () => {
// test('should simple cycles graph tarjan cycles return correct result', () => {
// const graph = new DirectedGraph();
//
// graph.addVertex('A');
// graph.addVertex('B');
// graph.addVertex('C');
// graph.addVertex('D');
//
// graph.addEdge('A', 'B');
// graph.addEdge('B', 'C');
// graph.addEdge('C', 'A');
// graph.addEdge('A', 'D');
// graph.addEdge('D', 'C');
// const cycles = graph.tarjan(false, false, false, true).cycles;
// expect(cycles.size).toBe(2);
// expect(getAsVerticesArrays(cycles)).toEqual([
// ['A', 'B', 'C'],
// ['A', 'D', 'C']
// ]);
// });
//
// function getAsVerticesArrays(vss: Map<number, DirectedVertex<any>[]>) {
// return [...vss.values()].map(vs => vs.map(vertex => vertex.key));
// }
//
// function createExampleGraph1() {
// const graph = new DirectedGraph();
// graph.addVertex('A');
// graph.addVertex('B');
// graph.addVertex('C');
// graph.addVertex('D');
// graph.addVertex('E');
// graph.addEdge('A', 'B');
// graph.addEdge('A', 'C');
// graph.addEdge('B', 'D');
// graph.addEdge('C', 'D');
// graph.addEdge('D', 'E');
// graph.addEdge('E', 'B');
// return graph;
// }
//
// test('should tarjan cycles return correct result', () => {
// const graph = createExampleGraph1();
// const cycles = graph.tarjan(false, false, false, true).cycles;
// expect(cycles.size).toBe(1);
// expect(getAsVerticesArrays(cycles)).toEqual([['B', 'D', 'E']]);
// });
//
// test('should tarjan SCCs return correct result', () => {
// const graph = createExampleGraph1();
// const sccs = graph.tarjan(false, false, true, false).SCCs;
// expect(sccs.size).toBe(3);
// expect(getAsVerticesArrays(sccs)).toEqual([['A'], ['C'], ['B', 'D', 'E']]);
// });
//
// test('should tarjan cut vertexes return correct result', () => {
// const graph = createExampleGraph1();
// const cutVertexes = graph.tarjan(true, false, false, false).cutVertexes;
// expect(cutVertexes.length).toBe(0);
// });
//
// test('should tarjan bridges return correct result', () => {
// const graph = createExampleGraph1();
// const bridges = graph.tarjan(false, true, false, false).bridges;
// expect(bridges.length).toBe(0);
// });
//
// function createExampleGraph2() {
// const graph = createExampleGraph1();
// graph.addVertex('F');
// graph.addVertex('G');
// graph.addEdge('B', 'F');
// graph.addEdge('F', 'E');
// graph.addEdge('C', 'G');
// graph.addEdge('G', 'A');
// return graph;
// }
//
// test('should 3 cycles graph tarjan cycles return correct result', () => {
// const graph = createExampleGraph2();
// const cycles = graph.tarjan(false, false, false, true).cycles;
// expect(cycles.size).toBe(3);
// expect(getAsVerticesArrays(cycles)).toEqual([
// ['A', 'C', 'G'],
// ['B', 'D', 'E'],
// ['B', 'F', 'E']
// ]);
// });
//
// test('should 3 cycles graph tarjan SCCs return correct result', () => {
// const graph = createExampleGraph2();
// const sccs = graph.tarjan(false, false, true, false).SCCs;
// expect(sccs.size).toBe(2);
// expect(getAsVerticesArrays(sccs)).toEqual([
// ['A', 'C', 'G'],
// ['B', 'D', 'E', 'F']
// ]);
// });
//
// test('should 3 cycles graph tarjan cut vertexes return correct result', () => {
// const graph = createExampleGraph1();
// const cutVertexes = graph.tarjan(true, false, false, false).cutVertexes;
// expect(cutVertexes.length).toBe(0);
// });
//
// test('should 3 cycles graph tarjan bridges return correct result', () => {
// const graph = createExampleGraph1();
// const bridges = graph.tarjan(false, true, false, false).bridges;
// expect(bridges.length).toBe(0);
// });
//
// function createExampleGraph3() {
// const graph = new DirectedGraph();
// graph.addVertex('A');
// graph.addVertex('B');
// graph.addVertex('C');
// graph.addVertex('D');
// graph.addVertex('E');
// graph.addVertex('F');
// graph.addVertex('G');
// graph.addEdge('A', 'B');
// graph.addEdge('B', 'C');
// graph.addEdge('C', 'D');
// graph.addEdge('D', 'B');
// graph.addEdge('A', 'E');
// graph.addEdge('E', 'F');
// graph.addEdge('F', 'G');
// graph.addEdge('G', 'E');
// return graph;
// }
//
// test('should cuttable graph tarjan cycles return correct result', () => {
// const graph = createExampleGraph3();
// const cycles = graph.tarjan(false, false, false, true).cycles;
// expect(cycles.size).toBe(2);
// expect(getAsVerticesArrays(cycles)).toEqual([
// ['B', 'C', 'D'],
// ['E', 'F', 'G']
// ]);
// });
//
// test('should cuttable graph tarjan SCCs return correct result', () => {
// const graph = createExampleGraph3();
// const sccs = graph.tarjan(false, false, true, false).SCCs;
// expect(sccs.size).toBe(3);
// expect(getAsVerticesArrays(sccs)).toEqual([['A'], ['B', 'C', 'D'], ['E', 'F', 'G']]);
// });
//
// test('should cuttable graph tarjan cut vertexes return correct result', () => {
// const graph = createExampleGraph3();
// const cutVertexes = graph.tarjan(true, false, false, false).cutVertexes;
// expect(cutVertexes.length).toBe(3);
// expect(cutVertexes.map(cv => cv.key)).toEqual(['B', 'E', 'A']);
// });
//
// test('should cuttable graph tarjan bridges return correct result', () => {
// const graph = createExampleGraph3();
// const bridges = graph.tarjan(false, true, false, false).bridges;
// expect(bridges.length).toBe(2);
// expect(bridges.map(b => '' + b.src + b.dest)).toEqual(['AB', 'AE']);
// });
//
// function createExampleGraph4() {
// const graph = createExampleGraph3();
// graph.addVertex('H');
// graph.addVertex('I');
// graph.addVertex('J');
// graph.addVertex('K');
// graph.addEdge('C', 'H');
// graph.addEdge('H', 'I');
// graph.addEdge('I', 'D');
// graph.addEdge('H', 'J');
// graph.addEdge('J', 'K');
// graph.addEdge('K', 'H');
// return graph;
// }
//
// test('should more cuttable graph tarjan cycles return correct result', () => {
// const graph = createExampleGraph4();
// const cycles = graph.tarjan(false, false, false, true).cycles;
// expect(cycles.size).toBe(4);
// expect(getAsVerticesArrays(cycles)).toEqual([
// ['B', 'C', 'D'],
// ['H', 'J', 'K'],
// ['E', 'F', 'G'],
// ['B', 'C', 'H', 'I', 'D']
// ]);
// });
//
// test('should more cuttable graph tarjan SCCs return correct result', () => {
// const graph = createExampleGraph4();
// const sccs = graph.tarjan(false, false, true, false).SCCs;
// expect(sccs.size).toBe(3);
// expect(getAsVerticesArrays(sccs)).toEqual([['A'], ['B', 'C', 'D', 'H', 'I', 'J', 'K'], ['E', 'F', 'G']]);
// });
//
// test('should more cuttable graph tarjan cut vertexes return correct result', () => {
// const graph = createExampleGraph4();
// const cutVertexes = graph.tarjan(true, false, false, false).cutVertexes;
// expect(cutVertexes.length).toBe(4);
// expect(cutVertexes.map(cv => cv.key)).toEqual(['B', 'E', 'A', 'H']);
// });
//
// test('should more cuttable graph tarjan bridges return correct result', () => {
// const graph = createExampleGraph4();
// const bridges = graph.tarjan(false, true, false, false).bridges;
// expect(bridges.length).toBe(2);
// expect(bridges.map(b => '' + b.src + b.dest)).toEqual(['AB', 'AE']);
// });
//
// function createExampleGraph5() {
// const graph = createExampleGraph4();
// graph.addEdge('F', 'H');
// return graph;
// }
//
// test('should uncuttable graph tarjan cycles return correct result', () => {
// const graph = createExampleGraph5();
// const cycles = graph.tarjan(false, false, false, true).cycles;
// expect(cycles.size).toBe(4);
// expect(getAsVerticesArrays(cycles)).toEqual([
// ['B', 'C', 'D'],
// ['H', 'J', 'K'],
// ['E', 'F', 'G'],
// ['B', 'C', 'H', 'I', 'D']
// ]);
// });
//
// test('should uncuttable graph tarjan SCCs return correct result', () => {
// const graph = createExampleGraph5();
// const sccs = graph.tarjan(false, false, true, false).SCCs;
// expect(sccs.size).toBe(3);
// expect(getAsVerticesArrays(sccs)).toEqual([['A'], ['B', 'C', 'D', 'H', 'I', 'J', 'K'], ['E', 'F', 'G']]);
// });
//
// test('should uncuttable graph tarjan cut vertexes return correct result', () => {
// const graph = createExampleGraph5();
// const cutVertexes = graph.tarjan(true, false, false, false).cutVertexes;
// expect(cutVertexes.length).toBe(0);
// });
//
// test('should uncuttable graph tarjan bridges return correct result', () => {
// const graph = createExampleGraph5();
// const bridges = graph.tarjan(false, true, false, false).bridges;
// expect(bridges.length).toBe(0);
// });
// });

View file

@ -58,13 +58,24 @@ describe('Deque - Basic Operations', () => {
deque.addLast('0');
deque.addLast('5');
deque.addLast('9');
expect(deque.size).toBe(6);
deque.delete('2');
expect(deque.size).toBe(5);
expect([...deque]).toEqual(['1', '6', '0', '5', '9']);
const cloned = deque.clone();
expect([...cloned]).toEqual(['1', '6', '0', '5', '9']);
expect(deque.size).toBe(5);
deque.delete('5');
expect(deque.size).toBe(4);
expect([...deque]).toEqual(['1', '6', '0', '9']);
expect([...cloned]).toEqual(['1', '6', '0', '5', '9']);
expect(cloned.size).toBe(5);
cloned.addLast('8');
expect(cloned.size).toBe(6);
cloned.delete('6');
expect(cloned.size).toBe(5);
cloned.delete('6');
expect(cloned.size).toBe(5);
});
});
describe('Deque - Complex Operations', () => {
@ -85,8 +96,40 @@ describe('Deque - Complex Operations', () => {
deque.push(1);
deque.push(2);
deque.push(3);
deque.cut(1);
expect(deque.size).toBe(3);
deque.cut(1, true);
expect(deque.size).toBe(2);
expect(deque.toArray()).toEqual([1, 2]);
const dq1 = new Deque([1, 2, 3, 4, 5, 6, 7]);
expect(dq1.size).toBe(7);
expect([...dq1.cut(3, true)]).toEqual([1, 2, 3, 4]);
expect(dq1.size).toBe(4);
expect([...dq1]).toEqual([1, 2, 3, 4]);
});
test('cutRest should remove elements after the specified position', () => {
deque.push(1);
deque.push(2);
deque.push(3);
deque.cutRest(1, true);
expect(deque.toArray()).toEqual([2, 3]);
const dq = new Deque([1, 2, 3, 4, 5, 6, 7]);
expect([...dq.cutRest(3, true)]).toEqual([4, 5, 6, 7]);
expect([...dq]).toEqual([4, 5, 6, 7]);
const deque1 = new Deque<number>();
deque1.push(1);
deque1.push(2);
deque1.push(3);
expect(deque1.toArray()).toEqual([1, 2, 3]);
expect(deque1.cutRest(1).toArray()).toEqual([2, 3]);
const dq1 = new Deque([1, 2, 3, 4, 5, 6, 7]);
expect([...dq1.cutRest(3)]).toEqual([4, 5, 6, 7]);
expect([...dq1]).toEqual([1, 2, 3, 4, 5, 6, 7]);
});
test('deleteAt should remove the element at the specified position', () => {