min-heap-typed 1.42.2 → 1.42.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,20 +7,17 @@
7
7
  * @license MIT License
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.RedBlackTree = exports.NIL = exports.RBTreeNode = void 0;
10
+ exports.RedBlackTree = exports.RBTreeNode = void 0;
11
11
  const types_1 = require("../../types");
12
- class RBTreeNode {
13
- constructor(key, color = types_1.RBTNColor.BLACK) {
14
- this.color = types_1.RBTNColor.BLACK;
15
- this.key = key;
12
+ const bst_1 = require("./bst");
13
+ const binary_tree_1 = require("./binary-tree");
14
+ class RBTreeNode extends bst_1.BSTNode {
15
+ constructor(key, value, color = types_1.RBTNColor.BLACK) {
16
+ super(key, value);
16
17
  this.color = color;
17
- this.parent = null;
18
- this.left = null;
19
- this.right = null;
20
18
  }
21
19
  }
22
20
  exports.RBTreeNode = RBTreeNode;
23
- exports.NIL = new RBTreeNode(0);
24
21
  /**
25
22
  * 1. Each node is either red or black.
26
23
  * 2. The root node is always black.
@@ -28,10 +25,12 @@ exports.NIL = new RBTreeNode(0);
28
25
  * 4. Red nodes must have black children.
29
26
  * 5. Black balance: Every path from any node to each of its leaf nodes contains the same number of black nodes.
30
27
  */
31
- class RedBlackTree {
32
- constructor() {
28
+ class RedBlackTree extends bst_1.BST {
29
+ constructor(options) {
30
+ super(options);
33
31
  this._size = 0;
34
- this._root = exports.NIL;
32
+ this.NIL = new RBTreeNode(NaN);
33
+ this._root = this.NIL;
35
34
  }
36
35
  get root() {
37
36
  return this._root;
@@ -39,31 +38,39 @@ class RedBlackTree {
39
38
  get size() {
40
39
  return this._size;
41
40
  }
42
- /**
43
- * The `insert` function inserts a new node with a given key into a red-black tree and fixes any
44
- * violations of the red-black tree properties.
45
- * @param {number} key - The key parameter is a number that represents the value to be inserted into
46
- * the RBTree.
47
- * @returns The function does not explicitly return anything.
48
- */
49
- add(key) {
50
- const node = new RBTreeNode(key, types_1.RBTNColor.RED);
51
- node.left = exports.NIL;
52
- node.right = exports.NIL;
53
- let y = null;
41
+ add(keyOrNode, value) {
42
+ let node;
43
+ if (typeof keyOrNode === 'number') {
44
+ node = this.createNode(keyOrNode, value, types_1.RBTNColor.RED);
45
+ }
46
+ else if (keyOrNode instanceof RBTreeNode) {
47
+ node = keyOrNode;
48
+ }
49
+ else if (keyOrNode === null) {
50
+ return;
51
+ }
52
+ else if (keyOrNode === undefined) {
53
+ return;
54
+ }
55
+ else {
56
+ return;
57
+ }
58
+ node.left = this.NIL;
59
+ node.right = this.NIL;
60
+ let y = undefined;
54
61
  let x = this.root;
55
- while (x !== exports.NIL) {
62
+ while (x !== this.NIL) {
56
63
  y = x;
57
- if (node.key < x.key) {
64
+ if (x && node.key < x.key) {
58
65
  x = x.left;
59
66
  }
60
67
  else {
61
- x = x.right;
68
+ x = x === null || x === void 0 ? void 0 : x.right;
62
69
  }
63
70
  }
64
71
  node.parent = y;
65
- if (y === null) {
66
- this._root = node;
72
+ if (y === undefined) {
73
+ this._setRoot(node);
67
74
  }
68
75
  else if (node.key < y.key) {
69
76
  y.left = node;
@@ -71,51 +78,50 @@ class RedBlackTree {
71
78
  else {
72
79
  y.right = node;
73
80
  }
74
- if (node.parent === null) {
81
+ if (node.parent === undefined) {
75
82
  node.color = types_1.RBTNColor.BLACK;
76
83
  this._size++;
77
84
  return;
78
85
  }
79
- if (node.parent.parent === null) {
86
+ if (node.parent.parent === undefined) {
80
87
  this._size++;
81
88
  return;
82
89
  }
83
90
  this._fixInsert(node);
84
91
  this._size++;
85
92
  }
86
- /**
87
- * The `delete` function in TypeScript is used to remove a node with a specific key from a red-black
88
- * tree.
89
- * @param {number} key - The `node` parameter is of type `RBTreeNode` and represents the current
90
- * node being processed in the delete operation.
91
- * @returns The `delete` function does not return anything. It has a return type of `void`.
92
- */
93
- delete(key) {
93
+ createNode(key, value, color = types_1.RBTNColor.BLACK) {
94
+ return new RBTreeNode(key, value, color);
95
+ }
96
+ delete(identifier, callback = this.defaultOneParamCallback) {
97
+ const ans = [];
98
+ if (identifier === null)
99
+ return ans;
94
100
  const helper = (node) => {
95
- let z = exports.NIL;
101
+ let z = this.NIL;
96
102
  let x, y;
97
- while (node !== exports.NIL) {
98
- if (node.key === key) {
103
+ while (node !== this.NIL) {
104
+ if (node && callback(node) === identifier) {
99
105
  z = node;
100
106
  }
101
- if (node.key <= key) {
107
+ if (node && identifier && callback(node) <= identifier) {
102
108
  node = node.right;
103
109
  }
104
110
  else {
105
- node = node.left;
111
+ node = node === null || node === void 0 ? void 0 : node.left;
106
112
  }
107
113
  }
108
- if (z === exports.NIL) {
114
+ if (z === this.NIL) {
109
115
  this._size--;
110
116
  return;
111
117
  }
112
118
  y = z;
113
119
  let yOriginalColor = y.color;
114
- if (z.left === exports.NIL) {
120
+ if (z.left === this.NIL) {
115
121
  x = z.right;
116
122
  this._rbTransplant(z, z.right);
117
123
  }
118
- else if (z.right === exports.NIL) {
124
+ else if (z.right === this.NIL) {
119
125
  x = z.left;
120
126
  this._rbTransplant(z, z.left);
121
127
  }
@@ -142,35 +148,32 @@ class RedBlackTree {
142
148
  this._size--;
143
149
  };
144
150
  helper(this.root);
151
+ // TODO
152
+ return ans;
145
153
  }
146
- isRealNode(node) {
147
- return node !== exports.NIL && node !== null;
154
+ isNode(node) {
155
+ return node !== this.NIL && node !== undefined;
148
156
  }
149
157
  /**
150
- * The function `getNode` is a recursive depth-first search algorithm that searches for a node with a
151
- * given key in a red-black tree.
152
- * @param {number} key - The key parameter is a number that represents the value we are searching for
153
- * in the RBTree.
154
- * @param beginRoot - The `beginRoot` parameter is an optional parameter that represents the starting
155
- * point for the search in the binary search tree. If no value is provided for `beginRoot`, it
156
- * defaults to the root of the binary search tree (`this.root`).
157
- * @returns a RBTreeNode.
158
+ * The function `get` returns the first node in a binary tree that matches the given property or key.
159
+ * @param {BTNKey | N} identifier - The `identifier` parameter is the key or value of
160
+ * the node that you want to find in the binary tree. It can be either a `BTNKey` or `N`
161
+ * type.
162
+ * @param callback - The `callback` parameter is a function that is used to determine whether a node
163
+ * matches the desired criteria. It takes a node as input and returns a boolean value indicating
164
+ * whether the node matches the criteria or not. The default callback function
165
+ * (`this.defaultOneParamCallback`) is used if no callback function is
166
+ * @param beginRoot - The `beginRoot` parameter is the starting point for the search. It specifies
167
+ * the root node from which the search should begin.
168
+ * @param iterationType - The `iterationType` parameter specifies the type of iteration to be
169
+ * performed when searching for a node in the binary tree. It can have one of the following values:
170
+ * @returns either the found node (of type N) or null if no node is found.
158
171
  */
159
- getNode(key, beginRoot = this.root) {
160
- const dfs = (node) => {
161
- if (this.isRealNode(node)) {
162
- if (key === node.key) {
163
- return node;
164
- }
165
- if (key < node.key)
166
- return dfs(node.left);
167
- return dfs(node.right);
168
- }
169
- else {
170
- return null;
171
- }
172
- };
173
- return dfs(beginRoot);
172
+ getNode(identifier, callback = this.defaultOneParamCallback, beginRoot = this.root, iterationType = this.iterationType) {
173
+ var _a;
174
+ if (identifier instanceof binary_tree_1.BinaryTreeNode)
175
+ callback = (node => node);
176
+ return (_a = this.getNodes(identifier, callback, true, beginRoot, iterationType)[0]) !== null && _a !== void 0 ? _a : undefined;
174
177
  }
175
178
  /**
176
179
  * The function returns the leftmost node in a red-black tree.
@@ -179,7 +182,7 @@ class RedBlackTree {
179
182
  * @returns The leftmost node in the given RBTreeNode.
180
183
  */
181
184
  getLeftMost(node = this.root) {
182
- while (node.left !== null && node.left !== exports.NIL) {
185
+ while (node.left !== undefined && node.left !== this.NIL) {
183
186
  node = node.left;
184
187
  }
185
188
  return node;
@@ -190,7 +193,7 @@ class RedBlackTree {
190
193
  * @returns the rightmost node in a red-black tree.
191
194
  */
192
195
  getRightMost(node) {
193
- while (node.right !== null && node.right !== exports.NIL) {
196
+ while (node.right !== undefined && node.right !== this.NIL) {
194
197
  node = node.right;
195
198
  }
196
199
  return node;
@@ -201,11 +204,11 @@ class RedBlackTree {
201
204
  * @returns the successor of the given RBTreeNode.
202
205
  */
203
206
  getSuccessor(x) {
204
- if (x.right !== exports.NIL) {
207
+ if (x.right !== this.NIL) {
205
208
  return this.getLeftMost(x.right);
206
209
  }
207
210
  let y = x.parent;
208
- while (y !== exports.NIL && y !== null && x === y.right) {
211
+ while (y !== this.NIL && y !== undefined && x === y.right) {
209
212
  x = y;
210
213
  y = y.parent;
211
214
  }
@@ -218,95 +221,51 @@ class RedBlackTree {
218
221
  * @returns the predecessor of the given RBTreeNode 'x'.
219
222
  */
220
223
  getPredecessor(x) {
221
- if (x.left !== exports.NIL) {
224
+ if (x.left !== this.NIL) {
222
225
  return this.getRightMost(x.left);
223
226
  }
224
227
  let y = x.parent;
225
- while (y !== exports.NIL && x === y.left) {
228
+ while (y !== this.NIL && x === y.left) {
226
229
  x = y;
227
230
  y = y.parent;
228
231
  }
229
232
  return y;
230
233
  }
231
234
  clear() {
232
- this._root = exports.NIL;
235
+ this._root = this.NIL;
233
236
  this._size = 0;
234
237
  }
235
- print(beginRoot = this.root) {
236
- const display = (root) => {
237
- const [lines, , ,] = _displayAux(root);
238
- for (const line of lines) {
239
- console.log(line);
240
- }
241
- };
242
- const _displayAux = (node) => {
243
- if (node === null) {
244
- return [[], 0, 0, 0];
245
- }
246
- if (node.right === null && node.left === null) {
247
- const line = `${node.key}`;
248
- const width = line.length;
249
- const height = 1;
250
- const middle = Math.floor(width / 2);
251
- return [[line], width, height, middle];
252
- }
253
- if (node.right === null) {
254
- const [lines, n, p, x] = _displayAux(node.left);
255
- const s = `${node.key}`;
256
- const u = s.length;
257
- const first_line = ' '.repeat(x + 1) + '_'.repeat(n - x - 1) + s;
258
- const second_line = ' '.repeat(x) + '/' + ' '.repeat(n - x - 1 + u);
259
- const shifted_lines = lines.map(line => line + ' '.repeat(u));
260
- return [[first_line, second_line, ...shifted_lines], n + u, p + 2, n + Math.floor(u / 2)];
261
- }
262
- if (node.left === null) {
263
- const [lines, n, p, u] = _displayAux(node.right);
264
- const s = `${node.key}`;
265
- const x = s.length;
266
- const first_line = s + '_'.repeat(x) + ' '.repeat(n - x);
267
- const second_line = ' '.repeat(u + x) + '\\' + ' '.repeat(n - x - 1);
268
- const shifted_lines = lines.map(line => ' '.repeat(u) + line);
269
- return [[first_line, second_line, ...shifted_lines], n + x, p + 2, Math.floor(u / 2)];
270
- }
271
- const [left, n, p, x] = _displayAux(node.left);
272
- const [right, m, q, y] = _displayAux(node.right);
273
- const s = `${node.key}`;
274
- const u = s.length;
275
- const first_line = ' '.repeat(x + 1) + '_'.repeat(n - x - 1) + s + '_'.repeat(y) + ' '.repeat(m - y);
276
- const second_line = ' '.repeat(x) + '/' + ' '.repeat(n - x - 1 + u + y) + '\\' + ' '.repeat(m - y - 1);
277
- if (p < q) {
278
- left.push(...new Array(q - p).fill(' '.repeat(n)));
279
- }
280
- else if (q < p) {
281
- right.push(...new Array(p - q).fill(' '.repeat(m)));
282
- }
283
- const zipped_lines = left.map((a, i) => a + ' '.repeat(u) + right[i]);
284
- return [[first_line, second_line, ...zipped_lines], n + m + u, Math.max(p, q) + 2, n + Math.floor(u / 2)];
285
- };
286
- display(beginRoot);
238
+ _setRoot(v) {
239
+ if (v) {
240
+ v.parent = undefined;
241
+ }
242
+ this._root = v;
287
243
  }
288
244
  /**
289
245
  * The function performs a left rotation on a red-black tree node.
290
246
  * @param {RBTreeNode} x - The parameter `x` is a RBTreeNode object.
291
247
  */
292
248
  _leftRotate(x) {
293
- const y = x.right;
294
- x.right = y.left;
295
- if (y.left !== exports.NIL) {
296
- y.left.parent = x;
297
- }
298
- y.parent = x.parent;
299
- if (x.parent === null) {
300
- this._root = y;
301
- }
302
- else if (x === x.parent.left) {
303
- x.parent.left = y;
304
- }
305
- else {
306
- x.parent.right = y;
249
+ if (x.right) {
250
+ const y = x.right;
251
+ x.right = y.left;
252
+ if (y.left !== this.NIL) {
253
+ if (y.left)
254
+ y.left.parent = x;
255
+ }
256
+ y.parent = x.parent;
257
+ if (x.parent === undefined) {
258
+ this._setRoot(y);
259
+ }
260
+ else if (x === x.parent.left) {
261
+ x.parent.left = y;
262
+ }
263
+ else {
264
+ x.parent.right = y;
265
+ }
266
+ y.left = x;
267
+ x.parent = y;
307
268
  }
308
- y.left = x;
309
- x.parent = y;
310
269
  }
311
270
  /**
312
271
  * The function performs a right rotation on a red-black tree node.
@@ -314,23 +273,26 @@ class RedBlackTree {
314
273
  * rotated.
315
274
  */
316
275
  _rightRotate(x) {
317
- const y = x.left;
318
- x.left = y.right;
319
- if (y.right !== exports.NIL) {
320
- y.right.parent = x;
321
- }
322
- y.parent = x.parent;
323
- if (x.parent === null) {
324
- this._root = y;
325
- }
326
- else if (x === x.parent.right) {
327
- x.parent.right = y;
328
- }
329
- else {
330
- x.parent.left = y;
276
+ if (x.left) {
277
+ const y = x.left;
278
+ x.left = y.right;
279
+ if (y.right !== this.NIL) {
280
+ if (y.right)
281
+ y.right.parent = x;
282
+ }
283
+ y.parent = x.parent;
284
+ if (x.parent === undefined) {
285
+ this._setRoot(y);
286
+ }
287
+ else if (x === x.parent.right) {
288
+ x.parent.right = y;
289
+ }
290
+ else {
291
+ x.parent.left = y;
292
+ }
293
+ y.right = x;
294
+ x.parent = y;
331
295
  }
332
- y.right = x;
333
- x.parent = y;
334
296
  }
335
297
  /**
336
298
  * The _fixDelete function is used to rebalance the Red-Black Tree after a node deletion.
@@ -340,7 +302,7 @@ class RedBlackTree {
340
302
  _fixDelete(x) {
341
303
  let s;
342
304
  while (x !== this.root && x.color === types_1.RBTNColor.BLACK) {
343
- if (x === x.parent.left) {
305
+ if (x.parent && x === x.parent.left) {
344
306
  s = x.parent.right;
345
307
  if (s.color === 1) {
346
308
  s.color = types_1.RBTNColor.BLACK;
@@ -348,20 +310,23 @@ class RedBlackTree {
348
310
  this._leftRotate(x.parent);
349
311
  s = x.parent.right;
350
312
  }
351
- if (s.left !== null && s.left.color === types_1.RBTNColor.BLACK && s.right.color === types_1.RBTNColor.BLACK) {
313
+ if (s.left !== undefined && s.left.color === types_1.RBTNColor.BLACK && s.right && s.right.color === types_1.RBTNColor.BLACK) {
352
314
  s.color = types_1.RBTNColor.RED;
353
315
  x = x.parent;
354
316
  }
355
317
  else {
356
- if (s.right.color === types_1.RBTNColor.BLACK) {
357
- s.left.color = types_1.RBTNColor.BLACK;
318
+ if (s.right && s.right.color === types_1.RBTNColor.BLACK) {
319
+ if (s.left)
320
+ s.left.color = types_1.RBTNColor.BLACK;
358
321
  s.color = types_1.RBTNColor.RED;
359
322
  this._rightRotate(s);
360
323
  s = x.parent.right;
361
324
  }
362
- s.color = x.parent.color;
325
+ if (s)
326
+ s.color = x.parent.color;
363
327
  x.parent.color = types_1.RBTNColor.BLACK;
364
- s.right.color = types_1.RBTNColor.BLACK;
328
+ if (s && s.right)
329
+ s.right.color = types_1.RBTNColor.BLACK;
365
330
  this._leftRotate(x.parent);
366
331
  x = this.root;
367
332
  }
@@ -374,20 +339,23 @@ class RedBlackTree {
374
339
  this._rightRotate(x.parent);
375
340
  s = x.parent.left;
376
341
  }
377
- if (s.right.color === types_1.RBTNColor.BLACK && s.right.color === types_1.RBTNColor.BLACK) {
342
+ if (s && s.right && s.right.color === types_1.RBTNColor.BLACK && s.right.color === types_1.RBTNColor.BLACK) {
378
343
  s.color = types_1.RBTNColor.RED;
379
344
  x = x.parent;
380
345
  }
381
346
  else {
382
- if (s.left.color === types_1.RBTNColor.BLACK) {
383
- s.right.color = types_1.RBTNColor.BLACK;
347
+ if (s && s.left && s.left.color === types_1.RBTNColor.BLACK) {
348
+ if (s.right)
349
+ s.right.color = types_1.RBTNColor.BLACK;
384
350
  s.color = types_1.RBTNColor.RED;
385
351
  this._leftRotate(s);
386
352
  s = x.parent.left;
387
353
  }
388
- s.color = x.parent.color;
354
+ if (s)
355
+ s.color = x.parent.color;
389
356
  x.parent.color = types_1.RBTNColor.BLACK;
390
- s.left.color = types_1.RBTNColor.BLACK;
357
+ if (s && s.left)
358
+ s.left.color = types_1.RBTNColor.BLACK;
391
359
  this._rightRotate(x.parent);
392
360
  x = this.root;
393
361
  }
@@ -401,8 +369,8 @@ class RedBlackTree {
401
369
  * @param {RBTreeNode} v - The parameter "v" is a RBTreeNode object.
402
370
  */
403
371
  _rbTransplant(u, v) {
404
- if (u.parent === null) {
405
- this._root = v;
372
+ if (u.parent === undefined) {
373
+ this._setRoot(v);
406
374
  }
407
375
  else if (u === u.parent.left) {
408
376
  u.parent.left = v;
@@ -419,10 +387,10 @@ class RedBlackTree {
419
387
  */
420
388
  _fixInsert(k) {
421
389
  let u;
422
- while (k.parent.color === 1) {
423
- if (k.parent === k.parent.parent.right) {
390
+ while (k.parent && k.parent.color === 1) {
391
+ if (k.parent.parent && k.parent === k.parent.parent.right) {
424
392
  u = k.parent.parent.left;
425
- if (u.color === 1) {
393
+ if (u && u.color === 1) {
426
394
  u.color = types_1.RBTNColor.BLACK;
427
395
  k.parent.color = types_1.RBTNColor.BLACK;
428
396
  k.parent.parent.color = types_1.RBTNColor.RED;
@@ -440,7 +408,7 @@ class RedBlackTree {
440
408
  }
441
409
  else {
442
410
  u = k.parent.parent.right;
443
- if (u.color === 1) {
411
+ if (u && u.color === 1) {
444
412
  u.color = types_1.RBTNColor.BLACK;
445
413
  k.parent.color = types_1.RBTNColor.BLACK;
446
414
  k.parent.parent.color = types_1.RBTNColor.RED;
@@ -49,37 +49,37 @@ export declare class TreeMultiset<V = any, N extends TreeMultisetNode<V, N> = Tr
49
49
  /**
50
50
  * The `add` function adds a new node to a binary search tree, updating the count if the key already
51
51
  * exists, and balancing the tree if necessary.
52
- * @param {BTNKey | N | null} keyOrNode - The `keyOrNode` parameter can be either a
52
+ * @param {BTNKey | N | undefined} keyOrNode - The `keyOrNode` parameter can be either a
53
53
  * `BTNKey` (which represents the key of the node to be added), a `N` (which represents a
54
- * node to be added), or `null` (which represents a null node).
54
+ * node to be added), or `undefined` (which represents a undefined node).
55
55
  * @param [value] - The `value` parameter represents the value associated with the key that is being
56
56
  * added to the binary tree.
57
57
  * @param [count=1] - The `count` parameter represents the number of occurrences of the key/value
58
58
  * pair that will be added to the binary tree. It has a default value of 1, which means that if no
59
59
  * count is specified, the default count will be 1.
60
- * @returns The function `add` returns a value of type `N | null | undefined`.
60
+ * @returns The function `add` returns a value of type `N | undefined | undefined`.
61
61
  */
62
- add(keyOrNode: BTNKey | N | null, value?: V, count?: number): N | null | undefined;
62
+ add(keyOrNode: BTNKey | N | null | undefined, value?: V, count?: number): N | undefined;
63
63
  /**
64
64
  * The function adds a new node to a binary tree if there is an available slot in the parent node.
65
- * @param {N | null} newNode - The `newNode` parameter represents the node that needs to be added to
66
- * the tree. It can be either a node object (`N`) or `null`.
65
+ * @param {N | undefined} newNode - The `newNode` parameter represents the node that needs to be added to
66
+ * the tree. It can be either a node object (`N`) or `undefined`.
67
67
  * @param {N} parent - The `parent` parameter represents the parent node to which the new node will
68
68
  * be added as a child.
69
69
  * @returns The method `_addTo` returns either the `parent.left`, `parent.right`, or `undefined`.
70
70
  */
71
- _addTo(newNode: N | null, parent: N): N | null | undefined;
71
+ _addTo(newNode: N | undefined, parent: N): N | undefined;
72
72
  /**
73
73
  * The `addMany` function adds multiple keys or nodes to a TreeMultiset and returns an array of the
74
74
  * inserted nodes.
75
- * @param {(BTNKey | null)[] | (N | null)[]} keysOrNodes - An array of keys or nodes to be
75
+ * @param {(BTNKey | undefined)[] | (N | undefined)[]} keysOrNodes - An array of keys or nodes to be
76
76
  * added to the multiset. Each element can be either a BTNKey or a TreeMultisetNode.
77
77
  * @param {V[]} [data] - The `data` parameter is an optional array of values that correspond
78
78
  * to the keys or nodes being added to the multiset. It is used to associate additional data with
79
79
  * each key or node.
80
- * @returns The function `addMany` returns an array of `N`, `null`, or `undefined` values.
80
+ * @returns The function `addMany` returns an array of `N`, `undefined`, or `undefined` values.
81
81
  */
82
- addMany(keysOrNodes: (BTNKey | null)[] | (N | null)[], data?: V[]): (N | null | undefined)[];
82
+ addMany(keysOrNodes: (BTNKey | undefined)[] | (N | undefined)[], data?: V[]): (N | undefined)[];
83
83
  /**
84
84
  * The `perfectlyBalance` function in TypeScript takes a sorted array of nodes and builds a balanced
85
85
  * binary search tree using either a recursive or iterative approach.