data-structure-typed 2.0.1 → 2.0.3

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.
Files changed (28) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/package.json +1 -1
  3. package/src/data-structures/queue/queue.ts +1 -1
  4. package/test/unit/data-structures/queue/queue.test.ts +1 -1
  5. package/test/unit/utils/utils.test.ts +3 -2
  6. package/dist/individuals/binary-tree/avl-tree-counter.mjs +0 -4701
  7. package/dist/individuals/binary-tree/avl-tree-multi-map.mjs +0 -4514
  8. package/dist/individuals/binary-tree/avl-tree.mjs +0 -4321
  9. package/dist/individuals/binary-tree/binary-tree.mjs +0 -3097
  10. package/dist/individuals/binary-tree/bst.mjs +0 -3858
  11. package/dist/individuals/binary-tree/red-black-tree.mjs +0 -4391
  12. package/dist/individuals/binary-tree/tree-counter.mjs +0 -4806
  13. package/dist/individuals/binary-tree/tree-multi-map.mjs +0 -4582
  14. package/dist/individuals/graph/directed-graph.mjs +0 -2910
  15. package/dist/individuals/graph/undirected-graph.mjs +0 -2745
  16. package/dist/individuals/hash/hash-map.mjs +0 -1040
  17. package/dist/individuals/heap/heap.mjs +0 -909
  18. package/dist/individuals/heap/max-heap.mjs +0 -671
  19. package/dist/individuals/heap/min-heap.mjs +0 -659
  20. package/dist/individuals/linked-list/doubly-linked-list.mjs +0 -1495
  21. package/dist/individuals/linked-list/singly-linked-list.mjs +0 -1479
  22. package/dist/individuals/priority-queue/max-priority-queue.mjs +0 -768
  23. package/dist/individuals/priority-queue/min-priority-queue.mjs +0 -757
  24. package/dist/individuals/priority-queue/priority-queue.mjs +0 -670
  25. package/dist/individuals/queue/deque.mjs +0 -1262
  26. package/dist/individuals/queue/queue.mjs +0 -1865
  27. package/dist/individuals/stack/stack.mjs +0 -415
  28. package/dist/individuals/trie/trie.mjs +0 -687
@@ -1,4582 +0,0 @@
1
- // src/utils/utils.ts
2
- var THUNK_SYMBOL = Symbol("thunk");
3
- var isThunk = (fnOrValue) => {
4
- return typeof fnOrValue === "function" && fnOrValue.__THUNK__ === THUNK_SYMBOL;
5
- };
6
- var toThunk = (fn) => {
7
- const thunk = () => fn();
8
- thunk.__THUNK__ = THUNK_SYMBOL;
9
- return thunk;
10
- };
11
- var trampoline = (fn) => {
12
- const cont = (...args) => toThunk(() => fn(...args));
13
- return Object.assign(
14
- (...args) => {
15
- let result = fn(...args);
16
- while (isThunk(result) && typeof result === "function") {
17
- result = result();
18
- }
19
- return result;
20
- },
21
- { cont }
22
- );
23
- };
24
- function isPrimitiveComparable(value) {
25
- const valueType = typeof value;
26
- if (valueType === "number") return true;
27
- return valueType === "bigint" || valueType === "string" || valueType === "boolean";
28
- }
29
- function tryObjectToPrimitive(obj) {
30
- if (typeof obj.valueOf === "function") {
31
- const valueOfResult = obj.valueOf();
32
- if (valueOfResult !== obj) {
33
- if (isPrimitiveComparable(valueOfResult)) return valueOfResult;
34
- if (typeof valueOfResult === "object" && valueOfResult !== null) return tryObjectToPrimitive(valueOfResult);
35
- }
36
- }
37
- if (typeof obj.toString === "function") {
38
- const stringResult = obj.toString();
39
- if (stringResult !== "[object Object]") return stringResult;
40
- }
41
- return null;
42
- }
43
- function isComparable(value, isForceObjectComparable = false) {
44
- if (value === null || value === void 0) return false;
45
- if (isPrimitiveComparable(value)) return true;
46
- if (typeof value !== "object") return false;
47
- if (value instanceof Date) return true;
48
- if (isForceObjectComparable) return true;
49
- const comparableValue = tryObjectToPrimitive(value);
50
- if (comparableValue === null || comparableValue === void 0) return false;
51
- return isPrimitiveComparable(comparableValue);
52
- }
53
-
54
- // src/data-structures/base/iterable-element-base.ts
55
- var IterableElementBase = class {
56
- /**
57
- * The protected constructor initializes the options for the IterableElementBase class, including the
58
- * toElementFn function.
59
- * @param [options] - An optional object that contains the following properties:
60
- */
61
- constructor(options) {
62
- if (options) {
63
- const { toElementFn } = options;
64
- if (typeof toElementFn === "function") this._toElementFn = toElementFn;
65
- else if (toElementFn) throw new TypeError("toElementFn must be a function type");
66
- }
67
- }
68
- _toElementFn;
69
- get toElementFn() {
70
- return this._toElementFn;
71
- }
72
- /**
73
- * Time Complexity: O(n)
74
- * Space Complexity: O(1)
75
- *
76
- * The function is an implementation of the Symbol.iterator method that returns an IterableIterator.
77
- * @param {any[]} args - The `args` parameter in the code snippet represents a rest parameter. It
78
- * allows the function to accept any number of arguments as an array. In this case, the `args`
79
- * parameter is used to pass any number of arguments to the `_getIterator` method.
80
- */
81
- *[Symbol.iterator](...args) {
82
- yield* this._getIterator(...args);
83
- }
84
- /**
85
- * Time Complexity: O(n)
86
- * Space Complexity: O(n)
87
- *
88
- * The function returns an iterator that yields all the values in the object.
89
- */
90
- *values() {
91
- for (const item of this) {
92
- yield item;
93
- }
94
- }
95
- /**
96
- * Time Complexity: O(n)
97
- * Space Complexity: O(1)
98
- *
99
- * The `every` function checks if every element in the array satisfies a given predicate.
100
- * @param predicate - The `predicate` parameter is a callback function that takes three arguments:
101
- * the current element being processed, its index, and the array it belongs to. It should return a
102
- * boolean value indicating whether the element satisfies a certain condition or not.
103
- * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value
104
- * to be used as `this` when executing the `predicate` function. If `thisArg` is provided, it will be
105
- * passed as the `this` value to the `predicate` function. If `thisArg` is
106
- * @returns The `every` method is returning a boolean value. It returns `true` if every element in
107
- * the array satisfies the provided predicate function, and `false` otherwise.
108
- */
109
- every(predicate, thisArg) {
110
- let index = 0;
111
- for (const item of this) {
112
- if (!predicate.call(thisArg, item, index++, this)) {
113
- return false;
114
- }
115
- }
116
- return true;
117
- }
118
- /**
119
- * Time Complexity: O(n)
120
- * Space Complexity: O(1)
121
- *
122
- * The "some" function checks if at least one element in a collection satisfies a given predicate.
123
- * @param predicate - The `predicate` parameter is a callback function that takes three arguments:
124
- * `value`, `index`, and `array`. It should return a boolean value indicating whether the current
125
- * element satisfies the condition.
126
- * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value
127
- * to be used as the `this` value when executing the `predicate` function. If `thisArg` is provided,
128
- * it will be passed as the `this` value to the `predicate` function. If `thisArg
129
- * @returns a boolean value. It returns true if the predicate function returns true for any element
130
- * in the collection, and false otherwise.
131
- */
132
- some(predicate, thisArg) {
133
- let index = 0;
134
- for (const item of this) {
135
- if (predicate.call(thisArg, item, index++, this)) {
136
- return true;
137
- }
138
- }
139
- return false;
140
- }
141
- /**
142
- * Time Complexity: O(n)
143
- * Space Complexity: O(1)
144
- *
145
- * The `forEach` function iterates over each element in an array-like object and calls a callback
146
- * function for each element.
147
- * @param callbackfn - The callbackfn parameter is a function that will be called for each element in
148
- * the array. It takes three arguments: the current element being processed, the index of the current
149
- * element, and the array that forEach was called upon.
150
- * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value
151
- * to be used as `this` when executing the `callbackfn` function. If `thisArg` is provided, it will
152
- * be passed as the `this` value to the `callbackfn` function. If `thisArg
153
- */
154
- forEach(callbackfn, thisArg) {
155
- let index = 0;
156
- for (const item of this) {
157
- callbackfn.call(thisArg, item, index++, this);
158
- }
159
- }
160
- /**
161
- * Time Complexity: O(n)
162
- * Space Complexity: O(1)
163
- *
164
- * The `find` function iterates over the elements of an array-like object and returns the first
165
- * element that satisfies the provided callback function.
166
- * @param predicate - The predicate parameter is a function that will be called for each element in
167
- * the array. It takes three arguments: the current element being processed, the index of the current
168
- * element, and the array itself. The function should return a boolean value indicating whether the
169
- * current element matches the desired condition.
170
- * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value
171
- * to be used as `this` when executing the `callbackfn` function. If `thisArg` is provided, it will
172
- * be passed as the `this` value to the `callbackfn` function. If `thisArg
173
- * @returns The `find` method returns the first element in the array that satisfies the provided
174
- * callback function. If no element satisfies the callback function, `undefined` is returned.
175
- */
176
- find(predicate, thisArg) {
177
- let index = 0;
178
- for (const item of this) {
179
- if (predicate.call(thisArg, item, index++, this)) return item;
180
- }
181
- return;
182
- }
183
- /**
184
- * Time Complexity: O(n)
185
- * Space Complexity: O(1)
186
- *
187
- * The function checks if a given element exists in a collection.
188
- * @param {E} element - The parameter "element" is of type E, which means it can be any type. It
189
- * represents the element that we want to check for existence in the collection.
190
- * @returns a boolean value. It returns true if the element is found in the collection, and false
191
- * otherwise.
192
- */
193
- has(element) {
194
- for (const ele of this) {
195
- if (ele === element) return true;
196
- }
197
- return false;
198
- }
199
- /**
200
- * Time Complexity: O(n)
201
- * Space Complexity: O(1)
202
- *
203
- * The `reduce` function iterates over the elements of an array-like object and applies a callback
204
- * function to reduce them into a single value.
205
- * @param callbackfn - The callbackfn parameter is a function that will be called for each element in
206
- * the array. It takes four arguments:
207
- * @param {U} initialValue - The initialValue parameter is the initial value of the accumulator. It
208
- * is the value that the accumulator starts with before the reduction operation begins.
209
- * @returns The `reduce` method is returning the final value of the accumulator after iterating over
210
- * all the elements in the array and applying the callback function to each element.
211
- */
212
- reduce(callbackfn, initialValue) {
213
- let accumulator = initialValue ?? 0;
214
- let index = 0;
215
- for (const item of this) {
216
- accumulator = callbackfn(accumulator, item, index++, this);
217
- }
218
- return accumulator;
219
- }
220
- /**
221
- * Time Complexity: O(n)
222
- * Space Complexity: O(n)
223
- *
224
- * The `toArray` function converts a linked list into an array.
225
- * @returns The `toArray()` method is returning an array of type `E[]`.
226
- */
227
- toArray() {
228
- return [...this];
229
- }
230
- /**
231
- * Time Complexity: O(n)
232
- * Space Complexity: O(n)
233
- *
234
- * The print function logs the elements of an array to the console.
235
- */
236
- toVisual() {
237
- return [...this];
238
- }
239
- /**
240
- * Time Complexity: O(n)
241
- * Space Complexity: O(n)
242
- *
243
- * The print function logs the elements of an array to the console.
244
- */
245
- print() {
246
- console.log(this.toVisual());
247
- }
248
- };
249
-
250
- // src/data-structures/base/linear-base.ts
251
- var LinearBase = class _LinearBase extends IterableElementBase {
252
- /**
253
- * The constructor initializes the LinearBase class with optional options, setting the maximum length
254
- * if provided.
255
- * @param [options] - The `options` parameter is an optional object that can be passed to the
256
- * constructor. It is of type `LinearBaseOptions<E, R>`. The constructor checks if the `options`
257
- * object is provided and then extracts the `maxLen` property from it. If `maxLen` is a
258
- */
259
- constructor(options) {
260
- super(options);
261
- if (options) {
262
- const { maxLen } = options;
263
- if (typeof maxLen === "number" && maxLen > 0 && maxLen % 1 === 0) this._maxLen = maxLen;
264
- }
265
- }
266
- _maxLen = -1;
267
- get maxLen() {
268
- return this._maxLen;
269
- }
270
- /**
271
- * Time Complexity: O(n)
272
- * Space Complexity: O(1)
273
- *
274
- * The function indexOf searches for a specified element starting from a given index in an array-like
275
- * object and returns the index of the first occurrence, or -1 if not found.
276
- * @param {E} searchElement - The `searchElement` parameter in the `indexOf` function represents the
277
- * element that you want to find within the array. The function will search for this element starting
278
- * from the `fromIndex` (if provided) up to the end of the array. If the `searchElement` is found
279
- * within the
280
- * @param {number} [fromIndex=0] - The `fromIndex` parameter in the `indexOf` function represents the
281
- * index at which to start searching for the `searchElement` within the array. If provided, the
282
- * search will begin at this index and continue to the end of the array. If `fromIndex` is not
283
- * specified, the default
284
- * @returns The `indexOf` method is returning the index of the `searchElement` if it is found in the
285
- * array starting from the `fromIndex`. If the `searchElement` is not found, it returns -1.
286
- */
287
- indexOf(searchElement, fromIndex = 0) {
288
- if (this.length === 0) return -1;
289
- if (fromIndex < 0) fromIndex = this.length + fromIndex;
290
- if (fromIndex < 0) fromIndex = 0;
291
- for (let i = fromIndex; i < this.length; i++) {
292
- const element = this.at(i);
293
- if (element === searchElement) return i;
294
- }
295
- return -1;
296
- }
297
- /**
298
- * Time Complexity: O(n)
299
- * Space Complexity: O(1)
300
- *
301
- * The function `lastIndexOf` in TypeScript returns the index of the last occurrence of a specified
302
- * element in an array.
303
- * @param {E} searchElement - The `searchElement` parameter is the element that you want to find the
304
- * last index of within the array. The `lastIndexOf` method will search the array starting from the
305
- * `fromIndex` (or the end of the array if not specified) and return the index of the last occurrence
306
- * of the
307
- * @param {number} fromIndex - The `fromIndex` parameter in the `lastIndexOf` method specifies the
308
- * index at which to start searching for the `searchElement` in the array. By default, it starts
309
- * searching from the last element of the array (`this.length - 1`). If a specific `fromIndex` is
310
- * provided
311
- * @returns The last index of the `searchElement` in the array is being returned. If the
312
- * `searchElement` is not found in the array, -1 is returned.
313
- */
314
- lastIndexOf(searchElement, fromIndex = this.length - 1) {
315
- if (this.length === 0) return -1;
316
- if (fromIndex >= this.length) fromIndex = this.length - 1;
317
- if (fromIndex < 0) fromIndex = this.length + fromIndex;
318
- for (let i = fromIndex; i >= 0; i--) {
319
- const element = this.at(i);
320
- if (element === searchElement) return i;
321
- }
322
- return -1;
323
- }
324
- /**
325
- * Time Complexity: O(n)
326
- * Space Complexity: O(1)
327
- *
328
- * The `findIndex` function iterates over an array and returns the index of the first element that
329
- * satisfies the provided predicate function.
330
- * @param predicate - The `predicate` parameter in the `findIndex` function is a callback function
331
- * that takes three arguments: `item`, `index`, and the array `this`. It should return a boolean
332
- * value indicating whether the current element satisfies the condition being checked for.
333
- * @param {any} [thisArg] - The `thisArg` parameter in the `findIndex` function is an optional
334
- * parameter that specifies the value to use as `this` when executing the `predicate` function. If
335
- * provided, the `predicate` function will be called with `thisArg` as its `this` value. If `
336
- * @returns The `findIndex` method is returning the index of the first element in the array that
337
- * satisfies the provided predicate function. If no such element is found, it returns -1.
338
- */
339
- findIndex(predicate, thisArg) {
340
- for (let i = 0; i < this.length; i++) {
341
- const item = this.at(i);
342
- if (item !== void 0 && predicate.call(thisArg, item, i, this)) return i;
343
- }
344
- return -1;
345
- }
346
- /**
347
- * Time Complexity: O(n + m)
348
- * Space Complexity: O(n + m)
349
- *
350
- * The `concat` function in TypeScript concatenates multiple items into a new list, handling both
351
- * individual elements and instances of `LinearBase`.
352
- * @param {(E | this)[]} items - The `concat` method takes in an array of items, where
353
- * each item can be either of type `E` or an instance of `LinearBase<E, R>`.
354
- * @returns The `concat` method is returning a new instance of the class that it belongs to, with the
355
- * items passed as arguments concatenated to it.
356
- */
357
- concat(...items) {
358
- const newList = this.clone();
359
- for (const item of items) {
360
- if (item instanceof _LinearBase) {
361
- newList.pushMany(item);
362
- } else {
363
- newList.push(item);
364
- }
365
- }
366
- return newList;
367
- }
368
- /**
369
- * Time Complexity: O(n log n)
370
- * Space Complexity: O(n)
371
- *
372
- * The `sort` function in TypeScript sorts the elements of a collection using a specified comparison
373
- * function.
374
- * @param [compareFn] - The `compareFn` parameter is a function that defines the sort order. It takes
375
- * two elements `a` and `b` as input and returns a number indicating their relative order. If the
376
- * returned value is negative, `a` comes before `b`. If the returned value is positive, `
377
- * @returns The `sort` method is returning the instance of the object on which it is called (this),
378
- * after sorting the elements based on the provided comparison function (compareFn).
379
- */
380
- sort(compareFn) {
381
- const arr = this.toArray();
382
- arr.sort(compareFn);
383
- this.clear();
384
- for (const item of arr) this.push(item);
385
- return this;
386
- }
387
- /**
388
- * Time Complexity: O(n + m)
389
- * Space Complexity: O(m)
390
- *
391
- * The `splice` function in TypeScript removes elements from an array and optionally inserts new
392
- * elements at the specified index.
393
- * @param {number} start - The `start` parameter in the `splice` method indicates the index at which
394
- * to start modifying the array. If `start` is a negative number, it will count from the end of the
395
- * array.
396
- * @param {number} [deleteCount=0] - The `deleteCount` parameter in the `splice` method specifies the
397
- * number of elements to remove from the array starting at the specified `start` index. If
398
- * `deleteCount` is not provided or is 0, no elements are removed, and only new elements are inserted
399
- * at the `start`
400
- * @param {E[]} items - The `items` parameter in the `splice` method represents the elements that
401
- * will be inserted into the array at the specified `start` index. These elements can be of any type
402
- * and you can pass multiple elements separated by commas. The `splice` method will insert these
403
- * items into the array at the
404
- * @returns The `splice` method returns a list of elements that were removed from the original list
405
- * during the operation.
406
- */
407
- splice(start, deleteCount = 0, ...items) {
408
- const removedList = this._createInstance();
409
- start = start < 0 ? this.length + start : start;
410
- start = Math.max(0, Math.min(start, this.length));
411
- deleteCount = Math.max(0, Math.min(deleteCount, this.length - start));
412
- for (let i = 0; i < deleteCount; i++) {
413
- const removed = this.deleteAt(start);
414
- if (removed !== void 0) {
415
- removedList.push(removed);
416
- }
417
- }
418
- for (let i = 0; i < items.length; i++) {
419
- this.addAt(start + i, items[i]);
420
- }
421
- return removedList;
422
- }
423
- /**
424
- * Time Complexity: O(n)
425
- * Space Complexity: O(1)
426
- *
427
- * The `join` function in TypeScript returns a string by joining the elements of an array with a
428
- * specified separator.
429
- * @param {string} [separator=,] - The `separator` parameter is a string that specifies the character
430
- * or characters that will be used to separate each element when joining them into a single string.
431
- * By default, the separator is set to a comma (`,`), but you can provide a different separator if
432
- * needed.
433
- * @returns The `join` method is being returned, which takes an optional `separator` parameter
434
- * (defaulting to a comma) and returns a string created by joining all elements of the array after
435
- * converting it to an array.
436
- */
437
- join(separator = ",") {
438
- return this.toArray().join(separator);
439
- }
440
- /**
441
- * Time Complexity: O(n)
442
- * Space Complexity: O(n)
443
- *
444
- * The function `toReversedArray` takes an array and returns a new array with its elements in reverse
445
- * order.
446
- * @returns The `toReversedArray()` function returns an array of elements of type `E` in reverse
447
- * order.
448
- */
449
- toReversedArray() {
450
- const array = [];
451
- for (let i = this.length - 1; i >= 0; i--) {
452
- array.push(this.at(i));
453
- }
454
- return array;
455
- }
456
- /**
457
- * Time Complexity: O(n)
458
- * Space Complexity: O(1)
459
- *
460
- * The `reduceRight` function in TypeScript iterates over an array from right to left and applies a
461
- * callback function to each element, accumulating a single result.
462
- * @param callbackfn - The `callbackfn` parameter in the `reduceRight` method is a function that will
463
- * be called on each element in the array from right to left. It takes four arguments:
464
- * @param {U} [initialValue] - The `initialValue` parameter in the `reduceRight` method is an
465
- * optional parameter that specifies the initial value of the accumulator. If provided, the
466
- * `accumulator` will start with this initial value before iterating over the elements of the array.
467
- * If `initialValue` is not provided, the accumulator will
468
- * @returns The `reduceRight` method is returning the final accumulated value after applying the
469
- * callback function to each element in the array from right to left.
470
- */
471
- reduceRight(callbackfn, initialValue) {
472
- let accumulator = initialValue ?? 0;
473
- for (let i = this.length - 1; i >= 0; i--) {
474
- accumulator = callbackfn(accumulator, this.at(i), i, this);
475
- }
476
- return accumulator;
477
- }
478
- /**
479
- * Time Complexity: O(m)
480
- * Space Complexity: O(m)
481
- *
482
- * The `slice` function in TypeScript creates a new instance by extracting a portion of elements from
483
- * the original instance based on the specified start and end indices.
484
- * @param {number} [start=0] - The `start` parameter in the `slice` method represents the index at
485
- * which to begin extracting elements from an array-like object. If no `start` parameter is provided,
486
- * the default value is 0, meaning the extraction will start from the beginning of the array.
487
- * @param {number} end - The `end` parameter in the `slice` method represents the index at which to
488
- * end the slicing. By default, if no `end` parameter is provided, it will slice until the end of the
489
- * array (i.e., `this.length`).
490
- * @returns The `slice` method is returning a new instance of the object with elements sliced from
491
- * the specified start index (default is 0) to the specified end index (default is the length of the
492
- * object).
493
- */
494
- slice(start = 0, end = this.length) {
495
- start = start < 0 ? this.length + start : start;
496
- end = end < 0 ? this.length + end : end;
497
- const newList = this._createInstance();
498
- for (let i = start; i < end; i++) {
499
- newList.push(this.at(i));
500
- }
501
- return newList;
502
- }
503
- /**
504
- * Time Complexity: O(n)
505
- * Space Complexity: O(1)
506
- *
507
- * The `fill` function in TypeScript fills a specified range in an array-like object with a given
508
- * value.
509
- * @param {E} value - The `value` parameter in the `fill` method represents the element that will be
510
- * used to fill the specified range in the array.
511
- * @param [start=0] - The `start` parameter specifies the index at which to start filling the array
512
- * with the specified value. If not provided, it defaults to 0, indicating the beginning of the
513
- * array.
514
- * @param end - The `end` parameter in the `fill` function represents the index at which the filling
515
- * of values should stop. It specifies the end of the range within the array where the `value` should
516
- * be filled.
517
- * @returns The `fill` method is returning the modified object (`this`) after filling the specified
518
- * range with the provided value.
519
- */
520
- fill(value, start = 0, end = this.length) {
521
- start = start < 0 ? this.length + start : start;
522
- end = end < 0 ? this.length + end : end;
523
- if (start < 0) start = 0;
524
- if (end > this.length) end = this.length;
525
- if (start >= end) return this;
526
- for (let i = start; i < end; i++) {
527
- this.setAt(i, value);
528
- }
529
- return this;
530
- }
531
- };
532
-
533
- // src/data-structures/queue/queue.ts
534
- var Queue = class _Queue extends LinearBase {
535
- constructor(elements = [], options) {
536
- super(options);
537
- if (options) {
538
- const { autoCompactRatio = 0.5 } = options;
539
- this._autoCompactRatio = autoCompactRatio;
540
- }
541
- this.pushMany(elements);
542
- }
543
- _elements = [];
544
- get elements() {
545
- return this._elements;
546
- }
547
- _offset = 0;
548
- get offset() {
549
- return this._offset;
550
- }
551
- get length() {
552
- return this.elements.length - this.offset;
553
- }
554
- _autoCompactRatio = 0.5;
555
- get autoCompactRatio() {
556
- return this._autoCompactRatio;
557
- }
558
- set autoCompactRatio(v) {
559
- this._autoCompactRatio = v;
560
- }
561
- /**
562
- * Time Complexity: O(1)
563
- * Space Complexity: O(1)
564
- *
565
- * The `first` function returns the first element of the array `_elements` if it exists, otherwise it returns `undefined`.
566
- * @returns The `get first()` method returns the first element of the data structure, represented by the `_elements` array at
567
- * the `_offset` index. If the data structure is empty (length is 0), it returns `undefined`.
568
- */
569
- get first() {
570
- return this.length > 0 ? this.elements[this.offset] : void 0;
571
- }
572
- /**
573
- * Time Complexity: O(1)
574
- * Space Complexity: O(1)
575
- *
576
- * The `last` function returns the last element in an array-like data structure, or undefined if the structure is empty.
577
- * @returns The method `get last()` returns the last element of the `_elements` array if the array is not empty. If the
578
- * array is empty, it returns `undefined`.
579
- */
580
- get last() {
581
- return this.length > 0 ? this.elements[this.elements.length - 1] : void 0;
582
- }
583
- /**
584
- * Time Complexity: O(n)
585
- * Space Complexity: O(n)
586
- *
587
- * The function "fromArray" creates a new Queue object from an array of elements.Creates a queue from an existing array.
588
- * @public
589
- * @param {E[]} elements - The "elements" parameter is an array of elements of type E.
590
- * @returns The method is returning a new instance of the Queue class, initialized with the elements from the input
591
- * array.
592
- */
593
- static fromArray(elements) {
594
- return new _Queue(elements);
595
- }
596
- /**
597
- * Time Complexity: O(1)
598
- * Space Complexity: O(1)
599
- *
600
- * The push function adds an element to the end of the queue and returns true. Adds an element at the back of the queue.
601
- * @param {E} element - The `element` parameter represents the element that you want to add to the queue.
602
- * @returns Always returns true, indicating the element was successfully added.
603
- */
604
- push(element) {
605
- this.elements.push(element);
606
- if (this._maxLen > 0 && this.length > this._maxLen) this.shift();
607
- return true;
608
- }
609
- /**
610
- * Time Complexity: O(k)
611
- * Space Complexity: O(k)
612
- *
613
- * The `pushMany` function iterates over elements and pushes them into an array after applying a
614
- * transformation function if provided.
615
- * @param {Iterable<E> | Iterable<R>} elements - The `elements` parameter in the `pushMany` function
616
- * is an iterable containing elements of type `E` or `R`.
617
- * @returns The `pushMany` function is returning an array of boolean values indicating whether each
618
- * element was successfully pushed into the data structure.
619
- */
620
- pushMany(elements) {
621
- const ans = [];
622
- for (const el of elements) {
623
- if (this.toElementFn) ans.push(this.push(this.toElementFn(el)));
624
- else ans.push(this.push(el));
625
- }
626
- return ans;
627
- }
628
- /**
629
- * Time Complexity: O(1)
630
- * Space Complexity: O(1)
631
- *
632
- * The `shift` function removes and returns the first element in the queue, and adjusts the internal data structure if
633
- * necessary to optimize performance.
634
- * @returns The function `shift()` returns either the first element in the queue or `undefined` if the queue is empty.
635
- */
636
- shift() {
637
- if (this.length === 0) return void 0;
638
- const first = this.first;
639
- this._offset += 1;
640
- if (this.offset / this.elements.length > this.autoCompactRatio) this.compact();
641
- return first;
642
- }
643
- /**
644
- * Time Complexity: O(n)
645
- * Space Complexity: O(1)
646
- *
647
- * The delete function removes an element from the list.
648
- * @param {E} element - Specify the element to be deleted
649
- * @return A boolean value indicating whether the element was successfully deleted or not
650
- */
651
- delete(element) {
652
- const index = this.elements.indexOf(element);
653
- return !!this.deleteAt(index);
654
- }
655
- /**
656
- * Time Complexity: O(n)
657
- * Space Complexity: O(1)
658
- *
659
- * The deleteAt function deletes the element at a given index.
660
- * @param {number} index - Determine the index of the element to be deleted
661
- * @return A boolean value
662
- */
663
- deleteAt(index) {
664
- const deleted = this.elements[index];
665
- this.elements.splice(index, 1);
666
- return deleted;
667
- }
668
- /**
669
- * Time Complexity: O(1)
670
- * Space Complexity: O(1)
671
- *
672
- * The `at` function returns the element at a specified index adjusted by an offset, or `undefined`
673
- * if the index is out of bounds.
674
- * @param {number} index - The `index` parameter represents the position of the element you want to
675
- * retrieve from the data structure.
676
- * @returns The `at` method is returning the element at the specified index adjusted by the offset
677
- * `_offset`.
678
- */
679
- at(index) {
680
- return this.elements[index + this._offset];
681
- }
682
- /**
683
- * Time Complexity: O(n)
684
- * Space Complexity: O(1)
685
- *
686
- * The `reverse` function in TypeScript reverses the elements of an array starting from a specified
687
- * offset.
688
- * @returns The `reverse()` method is returning the modified object itself (`this`) after reversing
689
- * the elements in the array and resetting the offset to 0.
690
- */
691
- reverse() {
692
- this._elements = this.elements.slice(this.offset).reverse();
693
- this._offset = 0;
694
- return this;
695
- }
696
- /**
697
- * Time Complexity: O(n)
698
- * Space Complexity: O(1)
699
- *
700
- * The function `addAt` inserts a new element at a specified index in an array, returning true if
701
- * successful and false if the index is out of bounds.
702
- * @param {number} index - The `index` parameter represents the position at which the `newElement`
703
- * should be added in the array.
704
- * @param {E} newElement - The `newElement` parameter represents the element that you want to insert
705
- * into the array at the specified index.
706
- * @returns The `addAt` method returns a boolean value - `true` if the new element was successfully
707
- * added at the specified index, and `false` if the index is out of bounds (less than 0 or greater
708
- * than the length of the array).
709
- */
710
- addAt(index, newElement) {
711
- if (index < 0 || index > this.length) return false;
712
- this._elements.splice(this.offset + index, 0, newElement);
713
- return true;
714
- }
715
- /**
716
- * Time Complexity: O(1)
717
- * Space Complexity: O(1)
718
- *
719
- * The function `setAt` updates an element at a specified index in an array-like data structure.
720
- * @param {number} index - The `index` parameter is a number that represents the position in the
721
- * array where the new element will be set.
722
- * @param {E} newElement - The `newElement` parameter represents the new value that you want to set
723
- * at the specified index in the array.
724
- * @returns The `setAt` method returns a boolean value - `true` if the element was successfully set
725
- * at the specified index, and `false` if the index is out of bounds (less than 0 or greater than the
726
- * length of the array).
727
- */
728
- setAt(index, newElement) {
729
- if (index < 0 || index > this.length) return false;
730
- this._elements[this.offset + index] = newElement;
731
- return true;
732
- }
733
- /**
734
- * Time Complexity: O(1)
735
- * Space Complexity: O(1)
736
- *
737
- * The function checks if a data structure is empty by comparing its length to zero.
738
- * @returns {boolean} A boolean value indicating whether the length of the object is 0 or not.
739
- */
740
- isEmpty() {
741
- return this.length === 0;
742
- }
743
- /**
744
- * Time Complexity: O(1)
745
- * Space Complexity: O(1)
746
- *
747
- * The clear function resets the elements array and offset to their initial values.
748
- */
749
- clear() {
750
- this._elements = [];
751
- this._offset = 0;
752
- }
753
- /**
754
- * Time Complexity: O(n)
755
- * Space Complexity: O(1)
756
- *
757
- * The `compact` function in TypeScript slices the elements array based on the offset and resets the
758
- * offset to zero.
759
- * @returns The `compact()` method is returning a boolean value of `true`.
760
- */
761
- compact() {
762
- this._elements = this.elements.slice(this.offset);
763
- this._offset = 0;
764
- return true;
765
- }
766
- /**
767
- * Time Complexity: O(n)
768
- * Space Complexity: O(n)
769
- *
770
- * The function overrides the splice method to remove and insert elements in a queue-like data
771
- * structure.
772
- * @param {number} start - The `start` parameter in the `splice` method specifies the index at which
773
- * to start changing the array. Items will be added or removed starting from this index.
774
- * @param {number} [deleteCount=0] - The `deleteCount` parameter in the `splice` method specifies the
775
- * number of elements to remove from the array starting at the specified `start` index. If
776
- * `deleteCount` is not provided, it defaults to 0, meaning no elements will be removed but new
777
- * elements can still be inserted at
778
- * @param {E[]} items - The `items` parameter in the `splice` method represents the elements that
779
- * will be added to the array at the specified `start` index. These elements will replace the
780
- * existing elements starting from the `start` index for the `deleteCount` number of elements.
781
- * @returns The `splice` method is returning the `removedQueue`, which is an instance of the same
782
- * class as the original object.
783
- */
784
- splice(start, deleteCount = 0, ...items) {
785
- const removedQueue = this._createInstance();
786
- start = Math.max(0, Math.min(start, this.length));
787
- deleteCount = Math.max(0, Math.min(deleteCount, this.length - start));
788
- const globalStartIndex = this.offset + start;
789
- const removedElements = this._elements.splice(globalStartIndex, deleteCount, ...items);
790
- removedQueue.pushMany(removedElements);
791
- this.compact();
792
- return removedQueue;
793
- }
794
- /**
795
- * Time Complexity: O(n)
796
- * Space Complexity: O(n)
797
- *
798
- * The `clone()` function returns a new Queue object with the same elements as the original Queue.
799
- * @returns The `clone()` method is returning a new instance of the `Queue` class.
800
- */
801
- clone() {
802
- return new _Queue(this.elements.slice(this.offset), { toElementFn: this.toElementFn, maxLen: this._maxLen });
803
- }
804
- /**
805
- * Time Complexity: O(n)
806
- * Space Complexity: O(n)
807
- *
808
- * The `filter` function creates a new `Queue` object containing elements from the original `Queue`
809
- * that satisfy a given predicate function.
810
- * @param predicate - The `predicate` parameter is a callback function that takes three arguments:
811
- * the current element being iterated over, the index of the current element, and the queue itself.
812
- * It should return a boolean value indicating whether the element should be included in the filtered
813
- * queue or not.
814
- * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value
815
- * to be used as `this` when executing the `predicate` function. If `thisArg` is provided, it will be
816
- * passed as the `this` value to the `predicate` function. If `thisArg` is
817
- * @returns The `filter` method is returning a new `Queue` object that contains the elements that
818
- * satisfy the given predicate function.
819
- */
820
- filter(predicate, thisArg) {
821
- const newDeque = this._createInstance({
822
- toElementFn: this._toElementFn,
823
- autoCompactRatio: this._autoCompactRatio,
824
- maxLen: this._maxLen
825
- });
826
- let index = 0;
827
- for (const el of this) {
828
- if (predicate.call(thisArg, el, index, this)) {
829
- newDeque.push(el);
830
- }
831
- index++;
832
- }
833
- return newDeque;
834
- }
835
- /**
836
- * Time Complexity: O(n)
837
- * Space Complexity: O(n)
838
- *
839
- * The `map` function in TypeScript creates a new Queue by applying a callback function to each
840
- * element in the original Queue.
841
- * @param callback - The `callback` parameter is a function that will be applied to each element in
842
- * the queue. It takes the current element, its index, and the queue itself as arguments, and returns
843
- * a new element.
844
- * @param [toElementFn] - The `toElementFn` parameter is an optional function that can be provided to
845
- * convert a raw element of type `RM` to a new element of type `EM`. This function is used within the
846
- * `map` method to transform each raw element before passing it to the `callback` function. If
847
- * @param {any} [thisArg] - The `thisArg` parameter in the `map` function is used to specify the
848
- * value of `this` when executing the `callback` function. It allows you to set the context (the
849
- * value of `this`) within the callback function. If `thisArg` is provided, it will be
850
- * @returns A new Queue object containing elements of type EM, which are the result of applying the
851
- * callback function to each element in the original Queue object.
852
- */
853
- map(callback, toElementFn, thisArg) {
854
- const newDeque = new _Queue([], {
855
- toElementFn,
856
- autoCompactRatio: this._autoCompactRatio,
857
- maxLen: this._maxLen
858
- });
859
- let index = 0;
860
- for (const el of this) {
861
- newDeque.push(callback.call(thisArg, el, index, this));
862
- index++;
863
- }
864
- return newDeque;
865
- }
866
- /**
867
- * Time Complexity: O(n)
868
- * Space Complexity: O(n)
869
- *
870
- * The function `_getIterator` returns an iterable iterator for the elements in the class.
871
- */
872
- *_getIterator() {
873
- for (const item of this.elements.slice(this.offset)) {
874
- yield item;
875
- }
876
- }
877
- /**
878
- * The function `_createInstance` returns a new instance of the `Queue` class with the specified
879
- * options.
880
- * @param [options] - The `options` parameter in the `_createInstance` method is of type
881
- * `QueueOptions<E, R>`, which is used to configure the behavior of the queue being created. It
882
- * allows you to specify settings or properties that can influence how the queue operates.
883
- * @returns An instance of the `Queue` class with an empty array and the provided options is being
884
- * returned.
885
- */
886
- _createInstance(options) {
887
- return new _Queue([], options);
888
- }
889
- /**
890
- * The function `_getReverseIterator` returns an iterator that iterates over elements in reverse
891
- * order.
892
- */
893
- *_getReverseIterator() {
894
- for (let i = this.length - 1; i >= 0; i--) {
895
- const cur = this.at(i);
896
- if (cur !== void 0) yield cur;
897
- }
898
- }
899
- };
900
-
901
- // src/data-structures/base/iterable-entry-base.ts
902
- var IterableEntryBase = class {
903
- /**
904
- * Time Complexity: O(n)
905
- * Space Complexity: O(1)
906
- *
907
- * The function is an implementation of the Symbol.iterator method that returns an iterable iterator.
908
- * @param {any[]} args - The `args` parameter in the code snippet represents a rest parameter. It
909
- * allows the function to accept any number of arguments as an array. In this case, the `args`
910
- * parameter is used to pass any additional arguments to the `_getIterator` method.
911
- */
912
- *[Symbol.iterator](...args) {
913
- yield* this._getIterator(...args);
914
- }
915
- /**
916
- * Time Complexity: O(n)
917
- * Space Complexity: O(n)
918
- *
919
- * The function returns an iterator that yields key-value pairs from the object, where the value can
920
- * be undefined.
921
- */
922
- *entries() {
923
- for (const item of this) {
924
- yield item;
925
- }
926
- }
927
- /**
928
- * Time Complexity: O(n)
929
- * Space Complexity: O(n)
930
- *
931
- * The function returns an iterator that yields the keys of a data structure.
932
- */
933
- *keys() {
934
- for (const item of this) {
935
- yield item[0];
936
- }
937
- }
938
- /**
939
- * Time Complexity: O(n)
940
- * Space Complexity: O(n)
941
- *
942
- * The function returns an iterator that yields the values of a collection.
943
- */
944
- *values() {
945
- for (const item of this) {
946
- yield item[1];
947
- }
948
- }
949
- /**
950
- * Time Complexity: O(n)
951
- * Space Complexity: O(1)
952
- *
953
- * The `every` function checks if every element in a collection satisfies a given condition.
954
- * @param predicate - The `predicate` parameter is a callback function that takes three arguments:
955
- * `value`, `key`, and `index`. It should return a boolean value indicating whether the condition is
956
- * met for the current element in the iteration.
957
- * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value
958
- * to be used as `this` when executing the `predicate` function. If `thisArg` is provided, it will be
959
- * passed as the first argument to the `predicate` function. If `thisArg` is not provided
960
- * @returns The `every` method is returning a boolean value. It returns `true` if every element in
961
- * the collection satisfies the provided predicate function, and `false` otherwise.
962
- */
963
- every(predicate, thisArg) {
964
- let index = 0;
965
- for (const item of this) {
966
- if (!predicate.call(thisArg, item[0], item[1], index++, this)) {
967
- return false;
968
- }
969
- }
970
- return true;
971
- }
972
- /**
973
- * Time Complexity: O(n)
974
- * Space Complexity: O(1)
975
- *
976
- * The "some" function iterates over a collection and returns true if at least one element satisfies
977
- * a given predicate.
978
- * @param predicate - The `predicate` parameter is a callback function that takes three arguments:
979
- * `value`, `key`, and `index`. It should return a boolean value indicating whether the condition is
980
- * met for the current element in the iteration.
981
- * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value
982
- * to be used as the `this` value when executing the `predicate` function. If `thisArg` is provided,
983
- * it will be passed as the first argument to the `predicate` function. If `thisArg` is
984
- * @returns a boolean value. It returns true if the predicate function returns true for any pair in
985
- * the collection, and false otherwise.
986
- */
987
- some(predicate, thisArg) {
988
- let index = 0;
989
- for (const item of this) {
990
- if (predicate.call(thisArg, item[0], item[1], index++, this)) {
991
- return true;
992
- }
993
- }
994
- return false;
995
- }
996
- /**
997
- * Time Complexity: O(n)
998
- * Space Complexity: O(1)
999
- *
1000
- * The `forEach` function iterates over each key-value pair in a collection and executes a callback
1001
- * function for each pair.
1002
- * @param callbackfn - The callback function that will be called for each element in the collection.
1003
- * It takes four parameters: the value of the current element, the key of the current element, the
1004
- * index of the current element, and the collection itself.
1005
- * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that allows you to
1006
- * specify the value of `this` within the callback function. If `thisArg` is provided, it will be
1007
- * used as the `this` value when calling the callback function. If `thisArg` is not provided, `
1008
- */
1009
- forEach(callbackfn, thisArg) {
1010
- let index = 0;
1011
- for (const item of this) {
1012
- const [key, value] = item;
1013
- callbackfn.call(thisArg, key, value, index++, this);
1014
- }
1015
- }
1016
- /**
1017
- * Time Complexity: O(n)
1018
- * Space Complexity: O(1)
1019
- *
1020
- * The `find` function iterates over the entries of a collection and returns the first value for
1021
- * which the callback function returns true.
1022
- * @param callbackfn - The callback function that will be called for each entry in the collection. It
1023
- * takes three arguments: the value of the entry, the key of the entry, and the index of the entry in
1024
- * the collection. It should return a boolean value indicating whether the current entry matches the
1025
- * desired condition.
1026
- * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value
1027
- * to be used as `this` when executing the `callbackfn` function. If `thisArg` is provided, it will
1028
- * be passed as the `this` value to the `callbackfn` function. If `thisArg
1029
- * @returns The method `find` returns the value of the first element in the iterable that satisfies
1030
- * the provided callback function. If no element satisfies the callback function, `undefined` is
1031
- * returned.
1032
- */
1033
- find(callbackfn, thisArg) {
1034
- let index = 0;
1035
- for (const item of this) {
1036
- const [key, value] = item;
1037
- if (callbackfn.call(thisArg, key, value, index++, this)) return item;
1038
- }
1039
- return;
1040
- }
1041
- /**
1042
- * Time Complexity: O(n)
1043
- * Space Complexity: O(1)
1044
- *
1045
- * The function checks if a given key exists in a collection.
1046
- * @param {K} key - The parameter "key" is of type K, which means it can be any type. It represents
1047
- * the key that we want to check for existence in the data structure.
1048
- * @returns a boolean value. It returns true if the key is found in the collection, and false
1049
- * otherwise.
1050
- */
1051
- has(key) {
1052
- for (const item of this) {
1053
- const [itemKey] = item;
1054
- if (itemKey === key) return true;
1055
- }
1056
- return false;
1057
- }
1058
- /**
1059
- * Time Complexity: O(n)
1060
- * Space Complexity: O(1)
1061
- *
1062
- * The function checks if a given value exists in a collection.
1063
- * @param {V} value - The parameter "value" is the value that we want to check if it exists in the
1064
- * collection.
1065
- * @returns a boolean value, either true or false.
1066
- */
1067
- hasValue(value) {
1068
- for (const [, elementValue] of this) {
1069
- if (elementValue === value) return true;
1070
- }
1071
- return false;
1072
- }
1073
- /**
1074
- * Time Complexity: O(n)
1075
- * Space Complexity: O(1)
1076
- *
1077
- * The `get` function retrieves the value associated with a given key from a collection.
1078
- * @param {K} key - K (the type of the key) - This parameter represents the key that is being
1079
- * searched for in the collection.
1080
- * @returns The `get` method returns the value associated with the specified key if it exists in the
1081
- * collection, otherwise it returns `undefined`.
1082
- */
1083
- get(key) {
1084
- for (const item of this) {
1085
- const [itemKey, value] = item;
1086
- if (itemKey === key) return value;
1087
- }
1088
- return;
1089
- }
1090
- /**
1091
- * Time Complexity: O(n)
1092
- * Space Complexity: O(1)
1093
- *
1094
- * The `reduce` function iterates over key-value pairs and applies a callback function to each pair,
1095
- * accumulating a single value.
1096
- * @param callbackfn - The callback function that will be called for each element in the collection.
1097
- * It takes four arguments: the current accumulator value, the current value of the element, the key
1098
- * of the element, and the index of the element in the collection. It should return the updated
1099
- * accumulator value.
1100
- * @param {U} initialValue - The `initialValue` parameter is the initial value of the accumulator. It
1101
- * is the value that will be used as the first argument to the `callbackfn` function when reducing
1102
- * the elements of the collection.
1103
- * @returns The `reduce` method is returning the final value of the accumulator after iterating over
1104
- * all the elements in the collection.
1105
- */
1106
- reduce(callbackfn, initialValue) {
1107
- let accumulator = initialValue;
1108
- let index = 0;
1109
- for (const item of this) {
1110
- const [key, value] = item;
1111
- accumulator = callbackfn(accumulator, value, key, index++, this);
1112
- }
1113
- return accumulator;
1114
- }
1115
- /**
1116
- * Time Complexity: O(n)
1117
- * Space Complexity: O(n)
1118
- *
1119
- * The print function logs the elements of an array to the console.
1120
- */
1121
- toVisual() {
1122
- return [...this];
1123
- }
1124
- /**
1125
- * Time Complexity: O(n)
1126
- * Space Complexity: O(n)
1127
- *
1128
- * The print function logs the elements of an array to the console.
1129
- */
1130
- print() {
1131
- console.log(this.toVisual());
1132
- }
1133
- };
1134
-
1135
- // src/common/index.ts
1136
- var Range = class {
1137
- constructor(low, high, includeLow = true, includeHigh = true) {
1138
- this.low = low;
1139
- this.high = high;
1140
- this.includeLow = includeLow;
1141
- this.includeHigh = includeHigh;
1142
- if (!(isComparable(low) && isComparable(high))) throw new RangeError("low or high is not comparable");
1143
- if (low > high) throw new RangeError("low must be less than or equal to high");
1144
- }
1145
- // Determine whether a key is within the range
1146
- isInRange(key, comparator) {
1147
- const lowCheck = this.includeLow ? comparator(key, this.low) >= 0 : comparator(key, this.low) > 0;
1148
- const highCheck = this.includeHigh ? comparator(key, this.high) <= 0 : comparator(key, this.high) < 0;
1149
- return lowCheck && highCheck;
1150
- }
1151
- };
1152
-
1153
- // src/data-structures/binary-tree/binary-tree.ts
1154
- var BinaryTreeNode = class {
1155
- key;
1156
- value;
1157
- parent = void 0;
1158
- /**
1159
- * The constructor function initializes an object with a key and an optional value in TypeScript.
1160
- * @param {K} key - The `key` parameter in the constructor function is used to store the key value
1161
- * for the key-value pair.
1162
- * @param {V} [value] - The `value` parameter in the constructor is optional, meaning it does not
1163
- * have to be provided when creating an instance of the class. If a `value` is not provided, it will
1164
- * default to `undefined`.
1165
- */
1166
- constructor(key, value) {
1167
- this.key = key;
1168
- this.value = value;
1169
- }
1170
- _left = void 0;
1171
- get left() {
1172
- return this._left;
1173
- }
1174
- set left(v) {
1175
- if (v) {
1176
- v.parent = this;
1177
- }
1178
- this._left = v;
1179
- }
1180
- _right = void 0;
1181
- get right() {
1182
- return this._right;
1183
- }
1184
- set right(v) {
1185
- if (v) {
1186
- v.parent = this;
1187
- }
1188
- this._right = v;
1189
- }
1190
- _height = 0;
1191
- get height() {
1192
- return this._height;
1193
- }
1194
- set height(value) {
1195
- this._height = value;
1196
- }
1197
- _color = "BLACK";
1198
- get color() {
1199
- return this._color;
1200
- }
1201
- set color(value) {
1202
- this._color = value;
1203
- }
1204
- _count = 1;
1205
- get count() {
1206
- return this._count;
1207
- }
1208
- set count(value) {
1209
- this._count = value;
1210
- }
1211
- get familyPosition() {
1212
- if (!this.parent) {
1213
- return this.left || this.right ? "ROOT" : "ISOLATED";
1214
- }
1215
- if (this.parent.left === this) {
1216
- return this.left || this.right ? "ROOT_LEFT" : "LEFT";
1217
- } else if (this.parent.right === this) {
1218
- return this.left || this.right ? "ROOT_RIGHT" : "RIGHT";
1219
- }
1220
- return "MAL_NODE";
1221
- }
1222
- };
1223
- var BinaryTree = class _BinaryTree extends IterableEntryBase {
1224
- iterationType = "ITERATIVE";
1225
- /**
1226
- * This TypeScript constructor function initializes a binary tree with optional options and adds
1227
- * elements based on the provided input.
1228
- * @param keysNodesEntriesOrRaws - The `keysNodesEntriesOrRaws` parameter in the constructor is an
1229
- * iterable that can contain either objects of type `K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined ` or `R`. It
1230
- * is used to initialize the binary tree with keys, nodes, entries, or raw data.
1231
- * @param [options] - The `options` parameter in the constructor is an optional object that can
1232
- * contain the following properties:
1233
- */
1234
- constructor(keysNodesEntriesOrRaws = [], options) {
1235
- super();
1236
- if (options) {
1237
- const { iterationType, toEntryFn, isMapMode, isDuplicate } = options;
1238
- if (iterationType) this.iterationType = iterationType;
1239
- if (isMapMode !== void 0) this._isMapMode = isMapMode;
1240
- if (isDuplicate !== void 0) this._isDuplicate = isDuplicate;
1241
- if (typeof toEntryFn === "function") this._toEntryFn = toEntryFn;
1242
- else if (toEntryFn) throw TypeError("toEntryFn must be a function type");
1243
- }
1244
- if (keysNodesEntriesOrRaws) this.addMany(keysNodesEntriesOrRaws);
1245
- }
1246
- _isMapMode = true;
1247
- get isMapMode() {
1248
- return this._isMapMode;
1249
- }
1250
- _isDuplicate = false;
1251
- get isDuplicate() {
1252
- return this._isDuplicate;
1253
- }
1254
- _store = /* @__PURE__ */ new Map();
1255
- get store() {
1256
- return this._store;
1257
- }
1258
- _root;
1259
- get root() {
1260
- return this._root;
1261
- }
1262
- _size = 0;
1263
- get size() {
1264
- return this._size;
1265
- }
1266
- _NIL = new BinaryTreeNode(NaN);
1267
- get NIL() {
1268
- return this._NIL;
1269
- }
1270
- _toEntryFn;
1271
- get toEntryFn() {
1272
- return this._toEntryFn;
1273
- }
1274
- /**
1275
- * Time Complexity: O(1)
1276
- * Space Complexity: O(1)
1277
- *
1278
- * The function creates a new binary tree node with a specified key and optional value.
1279
- * @param {K} key - The `key` parameter is the key of the node being created in the binary tree.
1280
- * @param {V} [value] - The `value` parameter in the `createNode` function is optional, meaning it is
1281
- * not required to be provided when calling the function. If a `value` is provided, it should be of
1282
- * type `V`, which is the type of the value associated with the node.
1283
- * @returns A new BinaryTreeNode instance with the provided key and value is being returned, casted
1284
- * as BinaryTreeNode<K, V>.
1285
- */
1286
- createNode(key, value) {
1287
- return new BinaryTreeNode(key, this._isMapMode ? void 0 : value);
1288
- }
1289
- /**
1290
- * Time Complexity: O(1)
1291
- * Space Complexity: O(1)
1292
- *
1293
- * The function creates a binary tree with the specified options.
1294
- * @param [options] - The `options` parameter in the `createTree` function is an optional parameter
1295
- * that allows you to provide partial configuration options for creating a binary tree. It is of type
1296
- * `Partial<BinaryTreeOptions<K, V, R>>`, which means you can pass in an object containing a subset
1297
- * of properties
1298
- * @returns A new instance of a binary tree with the specified options is being returned.
1299
- */
1300
- createTree(options) {
1301
- return new _BinaryTree([], {
1302
- iterationType: this.iterationType,
1303
- isMapMode: this._isMapMode,
1304
- toEntryFn: this._toEntryFn,
1305
- ...options
1306
- });
1307
- }
1308
- /**
1309
- * Time Complexity: O(n)
1310
- * Space Complexity: O(log n)
1311
- *
1312
- * The function `ensureNode` in TypeScript checks if a given input is a node, entry, key, or raw
1313
- * value and returns the corresponding node or null.
1314
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The `keyNodeOrEntry`
1315
- * parameter in the `ensureNode` function can be of type `K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined ` or `R`. It
1316
- * is used to determine whether the input is a key, node, entry, or raw data. The
1317
- * @param {IterationType} iterationType - The `iterationType` parameter in the `ensureNode` function
1318
- * is used to specify the type of iteration to be performed. It has a default value of
1319
- * `this.iterationType` if not explicitly provided.
1320
- * @returns The `ensureNode` function returns either a node, `null`, or `undefined` based on the
1321
- * conditions specified in the code snippet.
1322
- */
1323
- ensureNode(keyNodeOrEntry, iterationType = this.iterationType) {
1324
- if (keyNodeOrEntry === null) return null;
1325
- if (keyNodeOrEntry === void 0) return;
1326
- if (keyNodeOrEntry === this._NIL) return;
1327
- if (this.isNode(keyNodeOrEntry)) return keyNodeOrEntry;
1328
- if (this.isEntry(keyNodeOrEntry)) {
1329
- const key = keyNodeOrEntry[0];
1330
- if (key === null) return null;
1331
- if (key === void 0) return;
1332
- return this.getNode(key, this._root, iterationType);
1333
- }
1334
- return this.getNode(keyNodeOrEntry, this._root, iterationType);
1335
- }
1336
- /**
1337
- * Time Complexity: O(1)
1338
- * Space Complexity: O(1)
1339
- *
1340
- * The function isNode checks if the input is an instance of BinaryTreeNode.
1341
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The parameter
1342
- * `keyNodeOrEntry` can be either a key, a node, an entry, or raw data. The function is
1343
- * checking if the input is an instance of a `BinaryTreeNode` and returning a boolean value
1344
- * accordingly.
1345
- * @returns The function `isNode` is checking if the input `keyNodeOrEntry` is an instance of
1346
- * `BinaryTreeNode`. If it is, the function returns `true`, indicating that the input is a node. If
1347
- * it is not an instance of `BinaryTreeNode`, the function returns `false`, indicating that the input
1348
- * is not a node.
1349
- */
1350
- isNode(keyNodeOrEntry) {
1351
- return keyNodeOrEntry instanceof BinaryTreeNode;
1352
- }
1353
- /**
1354
- * Time Complexity: O(1)
1355
- * Space Complexity: O(1)
1356
- *
1357
- * The function `isRaw` checks if the input parameter is of type `R` by verifying if it is an object.
1358
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined | R} keyNodeEntryOrRaw - K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined
1359
- * @returns The function `isRaw` is checking if the `keyNodeEntryOrRaw` parameter is of type `R` by
1360
- * checking if it is an object. If the parameter is an object, the function will return `true`,
1361
- * indicating that it is of type `R`.
1362
- */
1363
- isRaw(keyNodeEntryOrRaw) {
1364
- return this._toEntryFn !== void 0 && typeof keyNodeEntryOrRaw === "object";
1365
- }
1366
- /**
1367
- * Time Complexity: O(1)
1368
- * Space Complexity: O(1)
1369
- *
1370
- * The function `isRealNode` checks if a given input is a valid node in a binary tree.
1371
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The `keyNodeOrEntry`
1372
- * parameter in the `isRealNode` function can be of type `K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined ` or `R`.
1373
- * The function checks if the input parameter is a `BinaryTreeNode<K, V>` type by verifying if it is not equal
1374
- * @returns The function `isRealNode` is checking if the input `keyNodeOrEntry` is a valid
1375
- * node by comparing it to `this._NIL`, `null`, and `undefined`. If the input is not one of these
1376
- * values, it then calls the `isNode` method to further determine if the input is a node. The
1377
- * function will return a boolean value indicating whether the
1378
- */
1379
- isRealNode(keyNodeOrEntry) {
1380
- if (keyNodeOrEntry === this._NIL || keyNodeOrEntry === null || keyNodeOrEntry === void 0) return false;
1381
- return this.isNode(keyNodeOrEntry);
1382
- }
1383
- /**
1384
- * Time Complexity: O(1)
1385
- * Space Complexity: O(1)
1386
- *
1387
- * The function checks if a given input is a valid node or null.
1388
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The parameter
1389
- * `keyNodeOrEntry` in the `isRealNodeOrNull` function can be of type `BTNRep<K,
1390
- * V, BinaryTreeNode<K, V>>` or `R`. It is a union type that can either be a key, a node, an entry, or
1391
- * @returns The function `isRealNodeOrNull` is returning a boolean value. It checks if the input
1392
- * `keyNodeOrEntry` is either `null` or a real node, and returns `true` if it is a node or
1393
- * `null`, and `false` otherwise.
1394
- */
1395
- isRealNodeOrNull(keyNodeOrEntry) {
1396
- return keyNodeOrEntry === null || this.isRealNode(keyNodeOrEntry);
1397
- }
1398
- /**
1399
- * Time Complexity: O(1)
1400
- * Space Complexity: O(1)
1401
- *
1402
- * The function isNIL checks if a given key, node, entry, or raw value is equal to the _NIL value.
1403
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - BTNRep<K, V,
1404
- * BinaryTreeNode<K, V>>
1405
- * @returns The function is checking if the `keyNodeOrEntry` parameter is equal to the `_NIL`
1406
- * property of the current object and returning a boolean value based on that comparison.
1407
- */
1408
- isNIL(keyNodeOrEntry) {
1409
- return keyNodeOrEntry === this._NIL;
1410
- }
1411
- /**
1412
- * Time Complexity: O(1)
1413
- * Space Complexity: O(1)
1414
- *
1415
- * The function `isRange` checks if the input parameter is an instance of the `Range` class.
1416
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined | NodePredicate<BinaryTreeNode<K, V>> | Range<K>} keyNodeEntryOrPredicate
1417
- * - The `keyNodeEntryOrPredicate` parameter in the `isRange` function can be
1418
- * of type `K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined `, `NodePredicate<BinaryTreeNode<K, V>>`, or
1419
- * `Range<K>`. The function checks if the `keyNodeEntry
1420
- * @returns The `isRange` function is checking if the `keyNodeEntryOrPredicate` parameter is an
1421
- * instance of the `Range` class. If it is an instance of `Range`, the function will return `true`,
1422
- * indicating that the parameter is a `Range<K>`. If it is not an instance of `Range`, the function
1423
- * will return `false`.
1424
- */
1425
- isRange(keyNodeEntryOrPredicate) {
1426
- return keyNodeEntryOrPredicate instanceof Range;
1427
- }
1428
- /**
1429
- * Time Complexity: O(1)
1430
- * Space Complexity: O(1)
1431
- *
1432
- * The function determines whether a given key, node, entry, or raw data is a leaf node in a binary
1433
- * tree.
1434
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The parameter
1435
- * `keyNodeOrEntry` can be of type `K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined ` or `R`. It represents a
1436
- * key, node, entry, or raw data in a binary tree structure. The function `isLeaf` checks whether the
1437
- * provided
1438
- * @returns The function `isLeaf` returns a boolean value indicating whether the input
1439
- * `keyNodeOrEntry` is a leaf node in a binary tree.
1440
- */
1441
- isLeaf(keyNodeOrEntry) {
1442
- keyNodeOrEntry = this.ensureNode(keyNodeOrEntry);
1443
- if (keyNodeOrEntry === void 0) return false;
1444
- if (keyNodeOrEntry === null) return true;
1445
- return !this.isRealNode(keyNodeOrEntry.left) && !this.isRealNode(keyNodeOrEntry.right);
1446
- }
1447
- /**
1448
- * Time Complexity: O(1)
1449
- * Space Complexity: O(1)
1450
- *
1451
- * The function `isEntry` checks if the input is a BTNEntry object by verifying if it is an array
1452
- * with a length of 2.
1453
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The `keyNodeOrEntry`
1454
- * parameter in the `isEntry` function can be of type `K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined ` or type `R`.
1455
- * The function checks if the provided `keyNodeOrEntry` is of type `BTN
1456
- * @returns The `isEntry` function is checking if the `keyNodeOrEntry` parameter is an array
1457
- * with a length of 2. If it is, then it returns `true`, indicating that the parameter is of type
1458
- * `BTNEntry<K, V>`. If the condition is not met, it returns `false`.
1459
- */
1460
- isEntry(keyNodeOrEntry) {
1461
- return Array.isArray(keyNodeOrEntry) && keyNodeOrEntry.length === 2;
1462
- }
1463
- /**
1464
- * Time Complexity O(1)
1465
- * Space Complexity O(1)
1466
- *
1467
- * The function `isValidKey` checks if a given key is comparable.
1468
- * @param {any} key - The `key` parameter is of type `any`, which means it can be any data type in
1469
- * TypeScript.
1470
- * @returns The function `isValidKey` is checking if the `key` parameter is `null` or if it is comparable.
1471
- * If the `key` is `null`, the function returns `true`. Otherwise, it returns the result of the
1472
- * `isComparable` function, which is not provided in the code snippet.
1473
- */
1474
- isValidKey(key) {
1475
- if (key === null) return true;
1476
- return isComparable(key);
1477
- }
1478
- /**
1479
- * Time Complexity O(n)
1480
- * Space Complexity O(1)
1481
- *
1482
- * The `add` function in TypeScript adds a new node to a binary tree while handling duplicate keys
1483
- * and finding the correct insertion position.
1484
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The `add` method you provided
1485
- * seems to be for adding a new node to a binary tree structure. The `keyNodeOrEntry`
1486
- * parameter in the method can accept different types of values:
1487
- * @param {V} [value] - The `value` parameter in the `add` method represents the value associated
1488
- * with the key that you want to add to the binary tree. When adding a key-value pair to the binary
1489
- * tree, you provide the key and its corresponding value. The `add` method then creates a new node
1490
- * with this
1491
- * @returns The `add` method returns a boolean value. It returns `true` if the insertion of the new
1492
- * node was successful, and `false` if the insertion position could not be found or if a duplicate
1493
- * key was found and the node was replaced instead of inserted.
1494
- */
1495
- add(keyNodeOrEntry, value) {
1496
- const [newNode, newValue] = this._keyValueNodeOrEntryToNodeAndValue(keyNodeOrEntry, value);
1497
- if (newNode === void 0) return false;
1498
- if (!this._root) {
1499
- this._setRoot(newNode);
1500
- if (this._isMapMode) this._setValue(newNode?.key, newValue);
1501
- this._size = 1;
1502
- return true;
1503
- }
1504
- const queue = new Queue([this._root]);
1505
- let potentialParent;
1506
- while (queue.length > 0) {
1507
- const cur = queue.shift();
1508
- if (!cur) continue;
1509
- if (!this._isDuplicate) {
1510
- if (newNode !== null && cur.key === newNode.key) {
1511
- this._replaceNode(cur, newNode);
1512
- if (this._isMapMode) this._setValue(cur.key, newValue);
1513
- return true;
1514
- }
1515
- }
1516
- if (potentialParent === void 0 && (cur.left === void 0 || cur.right === void 0)) {
1517
- potentialParent = cur;
1518
- }
1519
- if (cur.left !== null) {
1520
- if (cur.left) queue.push(cur.left);
1521
- }
1522
- if (cur.right !== null) {
1523
- if (cur.right) queue.push(cur.right);
1524
- }
1525
- }
1526
- if (potentialParent) {
1527
- if (potentialParent.left === void 0) {
1528
- potentialParent.left = newNode;
1529
- } else if (potentialParent.right === void 0) {
1530
- potentialParent.right = newNode;
1531
- }
1532
- if (this._isMapMode) this._setValue(newNode?.key, newValue);
1533
- this._size++;
1534
- return true;
1535
- }
1536
- return false;
1537
- }
1538
- /**
1539
- * Time Complexity: O(k * n)
1540
- * Space Complexity: O(k)
1541
- *
1542
- * The `addMany` function takes in multiple keys or nodes or entries or raw values along with
1543
- * optional values, and adds them to a data structure while returning an array indicating whether
1544
- * each insertion was successful.
1545
- * @param keysNodesEntriesOrRaws - `keysNodesEntriesOrRaws` is an iterable that can contain a
1546
- * mix of keys, nodes, entries, or raw values. Each element in this iterable can be of type
1547
- * `K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined ` or `R`.
1548
- * @param [values] - The `values` parameter in the `addMany` function is an optional parameter that
1549
- * accepts an iterable of values. These values correspond to the keys or nodes being added in the
1550
- * `keysNodesEntriesOrRaws` parameter. If provided, the function will iterate over the values and
1551
- * assign them
1552
- * @returns The `addMany` method returns an array of boolean values indicating whether each key,
1553
- * node, entry, or raw value was successfully added to the data structure. Each boolean value
1554
- * corresponds to the success of adding the corresponding key or value in the input iterable.
1555
- */
1556
- addMany(keysNodesEntriesOrRaws, values) {
1557
- const inserted = [];
1558
- let valuesIterator;
1559
- if (values) {
1560
- valuesIterator = values[Symbol.iterator]();
1561
- }
1562
- for (let keyNodeEntryOrRaw of keysNodesEntriesOrRaws) {
1563
- let value = void 0;
1564
- if (valuesIterator) {
1565
- const valueResult = valuesIterator.next();
1566
- if (!valueResult.done) {
1567
- value = valueResult.value;
1568
- }
1569
- }
1570
- if (this.isRaw(keyNodeEntryOrRaw)) keyNodeEntryOrRaw = this._toEntryFn(keyNodeEntryOrRaw);
1571
- inserted.push(this.add(keyNodeEntryOrRaw, value));
1572
- }
1573
- return inserted;
1574
- }
1575
- /**
1576
- * Time Complexity: O(k * n)
1577
- * Space Complexity: O(1)
1578
- *
1579
- * The `merge` function in TypeScript merges another binary tree into the current tree by adding all
1580
- * elements from the other tree.
1581
- * @param anotherTree - BinaryTree<K, V, R, MK, MV, MR>
1582
- */
1583
- merge(anotherTree) {
1584
- this.addMany(anotherTree, []);
1585
- }
1586
- /**
1587
- * Time Complexity: O(k * n)
1588
- * Space Complexity: O(1)
1589
- *
1590
- * The `refill` function clears the existing data structure and then adds new key-value pairs based
1591
- * on the provided input.
1592
- * @param keysNodesEntriesOrRaws - The `keysNodesEntriesOrRaws` parameter in the `refill`
1593
- * method can accept an iterable containing a mix of `K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined ` objects or `R`
1594
- * objects.
1595
- * @param [values] - The `values` parameter in the `refill` method is an optional parameter that
1596
- * accepts an iterable of values of type `V` or `undefined`.
1597
- */
1598
- refill(keysNodesEntriesOrRaws, values) {
1599
- this.clear();
1600
- this.addMany(keysNodesEntriesOrRaws, values);
1601
- }
1602
- /**
1603
- * Time Complexity: O(n)
1604
- * Space Complexity: O(1)
1605
- *
1606
- * The function `delete` in TypeScript implements the deletion of a node in a binary tree and returns
1607
- * the deleted node along with information for tree balancing.
1608
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry
1609
- * - The `delete` method you provided is used to delete a node from a binary tree based on the key,
1610
- * node, entry or raw data. The method returns an array of
1611
- * `BinaryTreeDeleteResult` objects containing information about the deleted node and whether
1612
- * balancing is needed.
1613
- * @returns The `delete` method returns an array of `BinaryTreeDeleteResult` objects. Each object in
1614
- * the array contains information about the node that was deleted (`deleted`) and the node that may
1615
- * need to be balanced (`needBalanced`).
1616
- */
1617
- delete(keyNodeOrEntry) {
1618
- const deletedResult = [];
1619
- if (!this._root) return deletedResult;
1620
- const curr = this.getNode(keyNodeOrEntry);
1621
- if (!curr) return deletedResult;
1622
- const parent = curr?.parent;
1623
- let needBalanced;
1624
- let orgCurrent = curr;
1625
- if (!curr.left && !curr.right && !parent) {
1626
- this._setRoot(void 0);
1627
- } else if (curr.left) {
1628
- const leftSubTreeRightMost = this.getRightMost((node) => node, curr.left);
1629
- if (leftSubTreeRightMost) {
1630
- const parentOfLeftSubTreeMax = leftSubTreeRightMost.parent;
1631
- orgCurrent = this._swapProperties(curr, leftSubTreeRightMost);
1632
- if (parentOfLeftSubTreeMax) {
1633
- if (parentOfLeftSubTreeMax.right === leftSubTreeRightMost)
1634
- parentOfLeftSubTreeMax.right = leftSubTreeRightMost.left;
1635
- else parentOfLeftSubTreeMax.left = leftSubTreeRightMost.left;
1636
- needBalanced = parentOfLeftSubTreeMax;
1637
- }
1638
- }
1639
- } else if (parent) {
1640
- const { familyPosition: fp } = curr;
1641
- if (fp === "LEFT" || fp === "ROOT_LEFT") {
1642
- parent.left = curr.right;
1643
- } else if (fp === "RIGHT" || fp === "ROOT_RIGHT") {
1644
- parent.right = curr.right;
1645
- }
1646
- needBalanced = parent;
1647
- } else {
1648
- this._setRoot(curr.right);
1649
- curr.right = void 0;
1650
- }
1651
- this._size = this._size - 1;
1652
- deletedResult.push({ deleted: orgCurrent, needBalanced });
1653
- if (this._isMapMode && orgCurrent) this._store.delete(orgCurrent.key);
1654
- return deletedResult;
1655
- }
1656
- /**
1657
- * Time Complexity: O(n)
1658
- * Space Complexity: O(k + log n)
1659
- *
1660
- * The `search` function in TypeScript performs a depth-first or breadth-first search on a tree
1661
- * structure based on a given predicate or key, with options to return multiple results or just one.
1662
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined | NodePredicate<BinaryTreeNode<K, V>>} keyNodeEntryOrPredicate - The
1663
- * `keyNodeEntryOrPredicate` parameter in the `search` function can accept three types of values:
1664
- * @param [onlyOne=false] - The `onlyOne` parameter in the `search` function is a boolean flag that
1665
- * determines whether the search should stop after finding the first matching node. If `onlyOne` is
1666
- * set to `true`, the search will return as soon as a matching node is found. If `onlyOne` is
1667
- * @param {C} callback - The `callback` parameter in the `search` function is a callback function
1668
- * that will be called on each node that matches the search criteria. It is of type `C`, which
1669
- * extends `NodeCallback<BinaryTreeNode<K, V> | null>`. The default value for `callback` is `this._DEFAULT_NODE_CALLBACK` if
1670
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the `search` function is
1671
- * used to specify the node from which the search operation should begin. It represents the starting
1672
- * point in the binary tree where the search will be performed. If no specific `startNode` is
1673
- * provided, the search operation will start from the root
1674
- * @param {IterationType} iterationType - The `iterationType` parameter in the `search` function
1675
- * specifies the type of iteration to be used when searching for nodes in a binary tree. It can have
1676
- * two possible values:
1677
- * @returns The `search` function returns an array of values that match the provided criteria based
1678
- * on the search algorithm implemented within the function.
1679
- */
1680
- search(keyNodeEntryOrPredicate, onlyOne = false, callback = this._DEFAULT_NODE_CALLBACK, startNode = this._root, iterationType = this.iterationType) {
1681
- if (keyNodeEntryOrPredicate === void 0) return [];
1682
- if (keyNodeEntryOrPredicate === null) return [];
1683
- startNode = this.ensureNode(startNode);
1684
- if (!startNode) return [];
1685
- const predicate = this._ensurePredicate(keyNodeEntryOrPredicate);
1686
- const ans = [];
1687
- if (iterationType === "RECURSIVE") {
1688
- const dfs = (cur) => {
1689
- if (predicate(cur)) {
1690
- ans.push(callback(cur));
1691
- if (onlyOne) return;
1692
- }
1693
- if (!this.isRealNode(cur.left) && !this.isRealNode(cur.right)) return;
1694
- if (this.isRealNode(cur.left)) dfs(cur.left);
1695
- if (this.isRealNode(cur.right)) dfs(cur.right);
1696
- };
1697
- dfs(startNode);
1698
- } else {
1699
- const stack = [startNode];
1700
- while (stack.length > 0) {
1701
- const cur = stack.pop();
1702
- if (this.isRealNode(cur)) {
1703
- if (predicate(cur)) {
1704
- ans.push(callback(cur));
1705
- if (onlyOne) return ans;
1706
- }
1707
- if (this.isRealNode(cur.left)) stack.push(cur.left);
1708
- if (this.isRealNode(cur.right)) stack.push(cur.right);
1709
- }
1710
- }
1711
- }
1712
- return ans;
1713
- }
1714
- /**
1715
- * Time Complexity: O(n)
1716
- * Space Complexity: O(k + log n)
1717
- *
1718
- * The function `getNodes` retrieves nodes from a binary tree based on a key, node, entry, raw data,
1719
- * or predicate, with options for recursive or iterative traversal.
1720
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined | NodePredicate<BinaryTreeNode<K, V>>} keyNodeEntryOrPredicate
1721
- * - The `getNodes` function you provided takes several parameters:
1722
- * @param [onlyOne=false] - The `onlyOne` parameter in the `getNodes` function is a boolean flag that
1723
- * determines whether to return only the first node that matches the criteria specified by the
1724
- * `keyNodeEntryOrPredicate` parameter. If `onlyOne` is set to `true`, the function will
1725
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the
1726
- * `getNodes` function is used to specify the starting point for traversing the binary tree. It
1727
- * represents the root node of the binary tree or the node from which the traversal should begin. If
1728
- * not provided, the default value is set to `this._root
1729
- * @param {IterationType} iterationType - The `iterationType` parameter in the `getNodes` function
1730
- * determines the type of iteration to be performed when traversing the nodes of a binary tree. It
1731
- * can have two possible values:
1732
- * @returns The `getNodes` function returns an array of nodes that satisfy the provided condition
1733
- * based on the input parameters and the iteration type specified.
1734
- */
1735
- getNodes(keyNodeEntryOrPredicate, onlyOne = false, startNode = this._root, iterationType = this.iterationType) {
1736
- return this.search(keyNodeEntryOrPredicate, onlyOne, (node) => node, startNode, iterationType);
1737
- }
1738
- /**
1739
- * Time Complexity: O(n)
1740
- * Space Complexity: O(log n)
1741
- *
1742
- * The `getNode` function retrieves a node based on the provided key, node, entry, raw data, or
1743
- * predicate.
1744
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined | NodePredicate<BinaryTreeNode<K, V>>} keyNodeEntryOrPredicate
1745
- * - The `keyNodeEntryOrPredicate` parameter in the `getNode` function can accept a key,
1746
- * node, entry, raw data, or a predicate function.
1747
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the
1748
- * `getNode` function is used to specify the starting point for searching for a node in a binary
1749
- * tree. If no specific starting point is provided, the default value is set to `this._root`, which
1750
- * is typically the root node of the binary tree.
1751
- * @param {IterationType} iterationType - The `iterationType` parameter in the `getNode` method is
1752
- * used to specify the type of iteration to be performed when searching for a node. It has a default
1753
- * value of `this.iterationType`, which means it will use the iteration type defined in the current
1754
- * context if no specific value is provided
1755
- * @returns The `getNode` function is returning the first node that matches the specified criteria,
1756
- * or `null` if no matching node is found.
1757
- */
1758
- getNode(keyNodeEntryOrPredicate, startNode = this._root, iterationType = this.iterationType) {
1759
- return this.search(keyNodeEntryOrPredicate, true, (node) => node, startNode, iterationType)[0];
1760
- }
1761
- /**
1762
- * Time Complexity: O(n)
1763
- * Space Complexity: O(log n)
1764
- *
1765
- * This function overrides the `get` method to retrieve the value associated with a specified key,
1766
- * node, entry, raw data, or predicate in a data structure.
1767
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined | NodePredicate<BinaryTreeNode<K, V>>} keyNodeEntryOrPredicate
1768
- * - The `keyNodeEntryOrPredicate` parameter in the `get` method can accept one of the
1769
- * following types:
1770
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the `get`
1771
- * method is used to specify the starting point for searching for a key or node in the binary tree.
1772
- * If no specific starting point is provided, the default starting point is the root of the binary
1773
- * tree (`this._root`).
1774
- * @param {IterationType} iterationType - The `iterationType` parameter in the `get` method is used
1775
- * to specify the type of iteration to be performed when searching for a key in the binary tree. It
1776
- * is an optional parameter with a default value of `this.iterationType`, which means it will use the
1777
- * iteration type defined in the
1778
- * @returns The `get` method is returning the value associated with the specified key, node, entry,
1779
- * raw data, or predicate in the binary tree map. If the specified key or node is found in the tree,
1780
- * the method returns the corresponding value. If the key or node is not found, it returns
1781
- * `undefined`.
1782
- */
1783
- get(keyNodeEntryOrPredicate, startNode = this._root, iterationType = this.iterationType) {
1784
- if (this._isMapMode) {
1785
- const key = this._extractKey(keyNodeEntryOrPredicate);
1786
- if (key === null || key === void 0) return;
1787
- return this._store.get(key);
1788
- }
1789
- return this.getNode(keyNodeEntryOrPredicate, startNode, iterationType)?.value;
1790
- }
1791
- /**
1792
- * Time Complexity: O(n)
1793
- * Space Complexity: O(log n)
1794
- *
1795
- * The `has` function in TypeScript checks if a specified key, node, entry, raw data, or predicate
1796
- * exists in the data structure.
1797
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined | NodePredicate<BinaryTreeNode<K, V>>} keyNodeEntryOrPredicate
1798
- * - The `keyNodeEntryOrPredicate` parameter in the `override has` method can accept one of
1799
- * the following types:
1800
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the
1801
- * `override` method is used to specify the starting point for the search operation within the data
1802
- * structure. It defaults to `this._root` if not provided explicitly.
1803
- * @param {IterationType} iterationType - The `iterationType` parameter in the `override has` method
1804
- * is used to specify the type of iteration to be performed. It has a default value of
1805
- * `this.iterationType`, which means it will use the iteration type defined in the current context if
1806
- * no value is provided when calling the method.
1807
- * @returns The `override has` method is returning a boolean value. It checks if there are any nodes
1808
- * that match the provided key, node, entry, raw data, or predicate in the tree structure. If there
1809
- * are matching nodes, it returns `true`, indicating that the tree contains the specified element.
1810
- * Otherwise, it returns `false`.
1811
- */
1812
- has(keyNodeEntryOrPredicate, startNode = this._root, iterationType = this.iterationType) {
1813
- return this.search(keyNodeEntryOrPredicate, true, (node) => node, startNode, iterationType).length > 0;
1814
- }
1815
- /**
1816
- * Time Complexity: O(1)
1817
- * Space Complexity: O(1)
1818
- *
1819
- * The clear function removes nodes and values in map mode.
1820
- */
1821
- clear() {
1822
- this._clearNodes();
1823
- if (this._isMapMode) this._clearValues();
1824
- }
1825
- /**
1826
- * Time Complexity: O(1)
1827
- * Space Complexity: O(1)
1828
- *
1829
- * The `isEmpty` function in TypeScript checks if a data structure has no elements and returns a
1830
- * boolean value.
1831
- * @returns The `isEmpty()` method is returning a boolean value, specifically `true` if the `_size`
1832
- * property is equal to 0, indicating that the data structure is empty, and `false` otherwise.
1833
- */
1834
- isEmpty() {
1835
- return this._size === 0;
1836
- }
1837
- /**
1838
- * Time Complexity: O(n)
1839
- * Space Complexity: O(log n)
1840
- *
1841
- * The function checks if a binary tree is perfectly balanced by comparing its minimum height with
1842
- * its height.
1843
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter is the starting
1844
- * point for checking if the binary tree is perfectly balanced. It represents the root node of the
1845
- * binary tree or a specific node from which the balance check should begin.
1846
- * @returns The method `isPerfectlyBalanced` is returning a boolean value, which indicates whether
1847
- * the tree starting from the `startNode` node is perfectly balanced or not. The return value is
1848
- * determined by comparing the minimum height of the tree with the height of the tree. If the minimum
1849
- * height plus 1 is greater than or equal to the height of the tree, then it is considered perfectly
1850
- * balanced and
1851
- */
1852
- isPerfectlyBalanced(startNode = this._root) {
1853
- return this.getMinHeight(startNode) + 1 >= this.getHeight(startNode);
1854
- }
1855
- /**
1856
- * Time Complexity: O(n)
1857
- * Space Complexity: O(log n)
1858
- *
1859
- * The function `isBST` in TypeScript checks if a binary search tree is valid using either recursive
1860
- * or iterative methods.
1861
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the `isBST`
1862
- * function represents the starting point for checking whether a binary search tree (BST) is valid.
1863
- * It can be a node in the BST or a reference to the root of the BST. If no specific node is
1864
- * provided, the function will default to
1865
- * @param {IterationType} iterationType - The `iterationType` parameter in the `isBST` function
1866
- * determines whether the function should use a recursive approach or an iterative approach to check
1867
- * if the binary search tree (BST) is valid.
1868
- * @returns The `isBST` method is returning a boolean value, which indicates whether the binary
1869
- * search tree (BST) represented by the given root node is a valid BST or not. The method checks if
1870
- * the tree satisfies the BST property, where for every node, all nodes in its left subtree have keys
1871
- * less than the node's key, and all nodes in its right subtree have keys greater than the node's
1872
- */
1873
- isBST(startNode = this._root, iterationType = this.iterationType) {
1874
- startNode = this.ensureNode(startNode);
1875
- if (!startNode) return true;
1876
- if (iterationType === "RECURSIVE") {
1877
- const dfs = (cur, min, max) => {
1878
- if (!this.isRealNode(cur)) return true;
1879
- const numKey = Number(cur.key);
1880
- if (numKey <= min || numKey >= max) return false;
1881
- return dfs(cur.left, min, numKey) && dfs(cur.right, numKey, max);
1882
- };
1883
- const isStandardBST = dfs(startNode, Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER);
1884
- const isInverseBST = dfs(startNode, Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER);
1885
- return isStandardBST || isInverseBST;
1886
- } else {
1887
- const checkBST = (checkMax = false) => {
1888
- const stack = [];
1889
- let prev = checkMax ? Number.MAX_SAFE_INTEGER : Number.MIN_SAFE_INTEGER;
1890
- let curr = startNode;
1891
- while (this.isRealNode(curr) || stack.length > 0) {
1892
- while (this.isRealNode(curr)) {
1893
- stack.push(curr);
1894
- curr = curr.left;
1895
- }
1896
- curr = stack.pop();
1897
- const numKey = Number(curr.key);
1898
- if (!this.isRealNode(curr) || !checkMax && prev >= numKey || checkMax && prev <= numKey) return false;
1899
- prev = numKey;
1900
- curr = curr.right;
1901
- }
1902
- return true;
1903
- };
1904
- const isStandardBST = checkBST(false), isInverseBST = checkBST(true);
1905
- return isStandardBST || isInverseBST;
1906
- }
1907
- }
1908
- /**
1909
- * Time Complexity: O(n)
1910
- * Space Complexity: O(log n)
1911
- *
1912
- * The `getDepth` function calculates the depth between two nodes in a binary tree.
1913
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } dist - The `dist` parameter in the `getDepth`
1914
- * function represents the node or entry in a binary tree map, or a reference to a node in the tree.
1915
- * It is the target node for which you want to calculate the depth from the `startNode` node.
1916
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the
1917
- * `getDepth` function represents the starting point from which you want to calculate the depth of a
1918
- * given node or entry in a binary tree. If no specific starting point is provided, the default value
1919
- * for `startNode` is set to the root of the binary
1920
- * @returns The `getDepth` method returns the depth of a given node `dist` relative to the
1921
- * `startNode` node in a binary tree. If the `dist` node is not found in the path to the `startNode`
1922
- * node, it returns the depth of the `dist` node from the root of the tree.
1923
- */
1924
- getDepth(dist, startNode = this._root) {
1925
- let distEnsured = this.ensureNode(dist);
1926
- const beginRootEnsured = this.ensureNode(startNode);
1927
- let depth = 0;
1928
- while (distEnsured?.parent) {
1929
- if (distEnsured === beginRootEnsured) {
1930
- return depth;
1931
- }
1932
- depth++;
1933
- distEnsured = distEnsured.parent;
1934
- }
1935
- return depth;
1936
- }
1937
- /**
1938
- * Time Complexity: O(n)
1939
- * Space Complexity: O(log n)
1940
- *
1941
- * The `getHeight` function calculates the maximum height of a binary tree using either a recursive
1942
- * or iterative approach in TypeScript.
1943
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter is the starting
1944
- * point from which the height of the binary tree will be calculated. It can be a node in the binary
1945
- * tree or a reference to the root of the tree. If not provided, it defaults to the root of the
1946
- * binary tree data structure.
1947
- * @param {IterationType} iterationType - The `iterationType` parameter is used to determine the type
1948
- * of iteration to be performed while calculating the height of the binary tree. It can have two
1949
- * possible values:
1950
- * @returns The `getHeight` method returns the height of the binary tree starting from the specified
1951
- * root node. The height is calculated based on the maximum depth of the tree, considering either a
1952
- * recursive approach or an iterative approach depending on the `iterationType` parameter.
1953
- */
1954
- getHeight(startNode = this._root, iterationType = this.iterationType) {
1955
- startNode = this.ensureNode(startNode);
1956
- if (!this.isRealNode(startNode)) return -1;
1957
- if (iterationType === "RECURSIVE") {
1958
- const _getMaxHeight = (cur) => {
1959
- if (!this.isRealNode(cur)) return -1;
1960
- const leftHeight = _getMaxHeight(cur.left);
1961
- const rightHeight = _getMaxHeight(cur.right);
1962
- return Math.max(leftHeight, rightHeight) + 1;
1963
- };
1964
- return _getMaxHeight(startNode);
1965
- } else {
1966
- const stack = [{ node: startNode, depth: 0 }];
1967
- let maxHeight = 0;
1968
- while (stack.length > 0) {
1969
- const { node, depth } = stack.pop();
1970
- if (this.isRealNode(node.left)) stack.push({ node: node.left, depth: depth + 1 });
1971
- if (this.isRealNode(node.right)) stack.push({ node: node.right, depth: depth + 1 });
1972
- maxHeight = Math.max(maxHeight, depth);
1973
- }
1974
- return maxHeight;
1975
- }
1976
- }
1977
- /**
1978
- * Time Complexity: O(n)
1979
- * Space Complexity: O(log n)
1980
- *
1981
- * The `getMinHeight` function calculates the minimum height of a binary tree using either a
1982
- * recursive or iterative approach in TypeScript.
1983
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the
1984
- * `getMinHeight` function represents the starting node from which the minimum height of the binary
1985
- * tree will be calculated. It is either a node in the binary tree or a reference to the root of the
1986
- * tree. If not provided, the default value is the root
1987
- * @param {IterationType} iterationType - The `iterationType` parameter in the `getMinHeight` method
1988
- * specifies the type of iteration to use when calculating the minimum height of a binary tree. It
1989
- * can have two possible values:
1990
- * @returns The `getMinHeight` method returns the minimum height of the binary tree starting from the
1991
- * specified root node. The height is calculated based on the shortest path from the root node to a
1992
- * leaf node in the tree. The method uses either a recursive approach or an iterative approach (using
1993
- * a stack) based on the `iterationType` parameter.
1994
- */
1995
- getMinHeight(startNode = this._root, iterationType = this.iterationType) {
1996
- startNode = this.ensureNode(startNode);
1997
- if (!startNode) return -1;
1998
- if (iterationType === "RECURSIVE") {
1999
- const _getMinHeight = (cur) => {
2000
- if (!this.isRealNode(cur)) return 0;
2001
- if (!this.isRealNode(cur.left) && !this.isRealNode(cur.right)) return 0;
2002
- const leftMinHeight = _getMinHeight(cur.left);
2003
- const rightMinHeight = _getMinHeight(cur.right);
2004
- return Math.min(leftMinHeight, rightMinHeight) + 1;
2005
- };
2006
- return _getMinHeight(startNode);
2007
- } else {
2008
- const stack = [];
2009
- let node = startNode, last = null;
2010
- const depths = /* @__PURE__ */ new Map();
2011
- while (stack.length > 0 || node) {
2012
- if (this.isRealNode(node)) {
2013
- stack.push(node);
2014
- node = node.left;
2015
- } else {
2016
- node = stack[stack.length - 1];
2017
- if (!this.isRealNode(node.right) || last === node.right) {
2018
- node = stack.pop();
2019
- if (this.isRealNode(node)) {
2020
- const leftMinHeight = this.isRealNode(node.left) ? depths.get(node.left) : -1;
2021
- const rightMinHeight = this.isRealNode(node.right) ? depths.get(node.right) : -1;
2022
- depths.set(node, 1 + Math.min(leftMinHeight, rightMinHeight));
2023
- last = node;
2024
- node = null;
2025
- }
2026
- } else node = node.right;
2027
- }
2028
- }
2029
- return depths.get(startNode);
2030
- }
2031
- }
2032
- /**
2033
- * Time Complexity: O(log n)
2034
- * Space Complexity: O(log n)
2035
- *
2036
- * The function `getPathToRoot` in TypeScript retrieves the path from a given node to the root of a
2037
- * tree structure, applying a specified callback function along the way.
2038
- * @param {C} callback - The `callback` parameter is a function that is used to process each node in
2039
- * the path to the root. It is expected to be a function that takes a node as an argument and returns
2040
- * a value based on that node. The return type of the callback function is determined by the generic
2041
- * type `C
2042
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } beginNode - The `beginNode` parameter in the
2043
- * `getPathToRoot` function can be either a key, a node, an entry, or any other value of type `R`.
2044
- * @param [isReverse=true] - The `isReverse` parameter in the `getPathToRoot` function determines
2045
- * whether the resulting path from the given `beginNode` to the root should be in reverse order or
2046
- * not. If `isReverse` is set to `true`, the path will be reversed before being returned. If `is
2047
- * @returns The function `getPathToRoot` returns an array of the return values of the callback
2048
- * function `callback` applied to each node in the path from the `beginNode` to the root node. The
2049
- * array is either in reverse order or in the original order based on the value of the `isReverse`
2050
- * parameter.
2051
- */
2052
- getPathToRoot(beginNode, callback = this._DEFAULT_NODE_CALLBACK, isReverse = false) {
2053
- const result = [];
2054
- let beginNodeEnsured = this.ensureNode(beginNode);
2055
- if (!beginNodeEnsured) return result;
2056
- while (beginNodeEnsured.parent) {
2057
- result.push(callback(beginNodeEnsured));
2058
- beginNodeEnsured = beginNodeEnsured.parent;
2059
- }
2060
- result.push(callback(beginNodeEnsured));
2061
- return isReverse ? result.reverse() : result;
2062
- }
2063
- /**
2064
- * Time Complexity: O(log n)
2065
- * Space Complexity: O(log n)
2066
- *
2067
- * The function `getLeftMost` retrieves the leftmost node in a binary tree using either recursive or
2068
- * tail-recursive iteration.
2069
- * @param {C} callback - The `callback` parameter is a function that will be called with the leftmost
2070
- * node of a binary tree or with `undefined` if the tree is empty. It is provided with a default
2071
- * value of `_DEFAULT_NODE_CALLBACK` if not specified.
2072
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the
2073
- * `getLeftMost` function represents the starting point for finding the leftmost node in a binary
2074
- * tree. It can be either a key, a node, or an entry in the binary tree structure. If no specific
2075
- * starting point is provided, the function will default
2076
- * @param {IterationType} iterationType - The `iterationType` parameter in the `getLeftMost` function
2077
- * specifies the type of iteration to be used when traversing the binary tree nodes. It can have two
2078
- * possible values:
2079
- * @returns The `getLeftMost` function returns the result of the callback function `C` applied to the
2080
- * leftmost node in the binary tree starting from the `startNode` node. If the `startNode` node is
2081
- * `NIL`, it returns the result of the callback function applied to `undefined`. If the `startNode`
2082
- * node is not a real node, it returns the result of the callback
2083
- */
2084
- getLeftMost(callback = this._DEFAULT_NODE_CALLBACK, startNode = this._root, iterationType = this.iterationType) {
2085
- if (this.isNIL(startNode)) return callback(void 0);
2086
- startNode = this.ensureNode(startNode);
2087
- if (!this.isRealNode(startNode)) return callback(startNode);
2088
- if (iterationType === "RECURSIVE") {
2089
- const dfs = (cur) => {
2090
- if (!this.isRealNode(cur.left)) return cur;
2091
- return dfs(cur.left);
2092
- };
2093
- return callback(dfs(startNode));
2094
- } else {
2095
- const dfs = trampoline((cur) => {
2096
- if (!this.isRealNode(cur.left)) return cur;
2097
- return dfs.cont(cur.left);
2098
- });
2099
- return callback(dfs(startNode));
2100
- }
2101
- }
2102
- /**
2103
- * Time Complexity: O(log n)
2104
- * Space Complexity: O(log n)
2105
- *
2106
- * The function `getRightMost` retrieves the rightmost node in a binary tree using either recursive
2107
- * or iterative traversal methods.
2108
- * @param {C} callback - The `callback` parameter is a function that will be called with the result
2109
- * of finding the rightmost node in a binary tree. It is of type `NodeCallback<OptNodeOrNull<BinaryTreeNode<K, V>>>`,
2110
- * which means it is a callback function that can accept either an optional binary tree node or null
2111
- * as
2112
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the
2113
- * `getRightMost` function represents the starting point for finding the rightmost node in a binary
2114
- * tree. It can be either a key, a node, or an entry in the binary tree structure. If no specific
2115
- * starting point is provided, the function will default
2116
- * @param {IterationType} iterationType - The `iterationType` parameter in the `getRightMost`
2117
- * function specifies the type of iteration to be used when traversing the binary tree nodes. It can
2118
- * have two possible values:
2119
- * @returns The `getRightMost` function returns the result of the callback function `C`, which is
2120
- * passed as a parameter to the function. The callback function is called with the rightmost node in
2121
- * the binary tree structure, determined based on the specified iteration type ('RECURSIVE' or
2122
- * other).
2123
- */
2124
- getRightMost(callback = this._DEFAULT_NODE_CALLBACK, startNode = this._root, iterationType = this.iterationType) {
2125
- if (this.isNIL(startNode)) return callback(void 0);
2126
- startNode = this.ensureNode(startNode);
2127
- if (!startNode) return callback(startNode);
2128
- if (iterationType === "RECURSIVE") {
2129
- const dfs = (cur) => {
2130
- if (!this.isRealNode(cur.right)) return cur;
2131
- return dfs(cur.right);
2132
- };
2133
- return callback(dfs(startNode));
2134
- } else {
2135
- const dfs = trampoline((cur) => {
2136
- if (!this.isRealNode(cur.right)) return cur;
2137
- return dfs.cont(cur.right);
2138
- });
2139
- return callback(dfs(startNode));
2140
- }
2141
- }
2142
- /**
2143
- * Time Complexity: O(log n)
2144
- * Space Complexity: O(log n)
2145
- *
2146
- * The function `getPredecessor` in TypeScript returns the predecessor node of a given node in a
2147
- * binary tree.
2148
- * @param {BinaryTreeNode<K, V>} node - The `getPredecessor` function you provided seems to be attempting to find the
2149
- * predecessor of a given node in a binary tree. However, there seems to be a logical issue in the
2150
- * while loop condition that might cause an infinite loop.
2151
- * @returns The `getPredecessor` function returns the predecessor node of the input `BinaryTreeNode<K, V>` parameter.
2152
- * If the left child of the input node exists, it traverses to the rightmost node of the left subtree
2153
- * to find the predecessor. If the left child does not exist, it returns the input node itself.
2154
- */
2155
- getPredecessor(node) {
2156
- if (this.isRealNode(node.left)) {
2157
- let predecessor = node.left;
2158
- while (!this.isRealNode(predecessor) || this.isRealNode(predecessor.right) && predecessor.right !== node) {
2159
- if (this.isRealNode(predecessor)) {
2160
- predecessor = predecessor.right;
2161
- }
2162
- }
2163
- return predecessor;
2164
- } else {
2165
- return node;
2166
- }
2167
- }
2168
- /**
2169
- * Time Complexity: O(log n)
2170
- * Space Complexity: O(log n)
2171
- *
2172
- * The function `getSuccessor` in TypeScript returns the next node in an in-order traversal of a
2173
- * binary tree.
2174
- * @param {K | BinaryTreeNode<K, V> | null} [x] - The `getSuccessor` function takes a parameter `x`, which can be of
2175
- * type `K`, `BinaryTreeNode<K, V>`, or `null`.
2176
- * @returns The `getSuccessor` function returns the successor node of the input node `x`. If `x` has
2177
- * a right child, the function returns the leftmost node in the right subtree of `x`. If `x` does not
2178
- * have a right child, the function traverses up the parent nodes until it finds a node that is not
2179
- * the right child of its parent, and returns that node
2180
- */
2181
- getSuccessor(x) {
2182
- x = this.ensureNode(x);
2183
- if (!this.isRealNode(x)) return void 0;
2184
- if (this.isRealNode(x.right)) {
2185
- return this.getLeftMost((node) => node, x.right);
2186
- }
2187
- let y = x.parent;
2188
- while (this.isRealNode(y) && x === y.right) {
2189
- x = y;
2190
- y = y.parent;
2191
- }
2192
- return y;
2193
- }
2194
- /**
2195
- * Time complexity: O(n)
2196
- * Space complexity: O(n)
2197
- *
2198
- * The function performs a depth-first search on a binary tree structure based on the specified
2199
- * parameters.
2200
- * @param {C} callback - The `callback` parameter is a function that will be called for each node
2201
- * visited during the depth-first search. It should accept a `BinaryTreeNode` as an argument and
2202
- * return an optional node or null. The default value for this parameter is `_DEFAULT_NODE_CALLBACK`.
2203
- * @param {DFSOrderPattern} [pattern=IN] - The `pattern` parameter in the `dfs` function specifies
2204
- * the order in which the nodes are visited during a depth-first search traversal. The possible
2205
- * values for the `pattern` parameter are:
2206
- * @param {boolean} [onlyOne=false] - The `onlyOne` parameter in the `dfs` function is a boolean flag
2207
- * that determines whether the depth-first search should stop after finding the first matching node
2208
- * or continue searching for all matching nodes. If `onlyOne` is set to `true`, the search will stop
2209
- * after finding the first matching node
2210
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined}
2211
- * startNode - The `startNode` parameter in the `dfs` function can be one of the following types:
2212
- * @param {IterationType} iterationType - The `iterationType` parameter in the `dfs` function
2213
- * specifies the type of iteration to be performed during the Depth-First Search traversal. It is
2214
- * used to determine the order in which nodes are visited during the traversal. The possible values
2215
- * for `iterationType` are typically defined as an enum or a
2216
- * @param [includeNull=false] - The `includeNull` parameter in the `dfs` function determines whether
2217
- * null nodes should be included in the depth-first search traversal. If `includeNull` is set to
2218
- * `true`, null nodes will be included in the traversal process. If it is set to `false`, null nodes
2219
- * will be skipped
2220
- * @returns The `dfs` method is returning an array of the return type of the callback function `C`.
2221
- */
2222
- dfs(callback = this._DEFAULT_NODE_CALLBACK, pattern = "IN", onlyOne = false, startNode = this._root, iterationType = this.iterationType, includeNull = false) {
2223
- startNode = this.ensureNode(startNode);
2224
- if (!startNode) return [];
2225
- return this._dfs(callback, pattern, onlyOne, startNode, iterationType, includeNull);
2226
- }
2227
- /**
2228
- * Time complexity: O(n)
2229
- * Space complexity: O(n)
2230
- *
2231
- * The `bfs` function performs a breadth-first search traversal on a binary tree or binary search
2232
- * tree, executing a specified callback function on each node visited.
2233
- * @param {C} callback - The `callback` parameter in the `bfs` function is a function that will be
2234
- * called on each node visited during the breadth-first search traversal. It is a generic type `C`
2235
- * that extends the `NodeCallback` type, which takes a parameter of type `BinaryTreeNode<K, V>` or `null`.
2236
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the `bfs`
2237
- * function represents the starting point for the breadth-first search traversal in a binary tree. It
2238
- * can be specified as a key, node, or entry in the binary tree structure. If not provided, the
2239
- * default value is the root node of the binary
2240
- * @param {IterationType} iterationType - The `iterationType` parameter in the `bfs` function
2241
- * determines the type of iteration to be performed on the binary tree nodes. It can have two
2242
- * possible values:
2243
- * @param [includeNull=false] - The `includeNull` parameter in the `bfs` function determines whether
2244
- * to include `null` values in the breadth-first search traversal of a binary tree. If `includeNull`
2245
- * is set to `true`, the traversal will include `null` values for nodes that do not have children
2246
- * (left
2247
- * @returns The `bfs` function returns an array of values that are the result of applying the
2248
- * provided callback function to each node in the binary tree in a breadth-first search manner.
2249
- */
2250
- bfs(callback = this._DEFAULT_NODE_CALLBACK, startNode = this._root, iterationType = this.iterationType, includeNull = false) {
2251
- startNode = this.ensureNode(startNode);
2252
- if (!startNode) return [];
2253
- const ans = [];
2254
- if (iterationType === "RECURSIVE") {
2255
- const queue = new Queue([
2256
- startNode
2257
- ]);
2258
- const dfs = (level) => {
2259
- if (queue.length === 0) return;
2260
- const current = queue.shift();
2261
- ans.push(callback(current));
2262
- if (includeNull) {
2263
- if (current && this.isRealNodeOrNull(current.left)) queue.push(current.left);
2264
- if (current && this.isRealNodeOrNull(current.right)) queue.push(current.right);
2265
- } else {
2266
- if (this.isRealNode(current.left)) queue.push(current.left);
2267
- if (this.isRealNode(current.right)) queue.push(current.right);
2268
- }
2269
- dfs(level + 1);
2270
- };
2271
- dfs(0);
2272
- } else {
2273
- const queue = new Queue([startNode]);
2274
- while (queue.length > 0) {
2275
- const levelSize = queue.length;
2276
- for (let i = 0; i < levelSize; i++) {
2277
- const current = queue.shift();
2278
- ans.push(callback(current));
2279
- if (includeNull) {
2280
- if (current && this.isRealNodeOrNull(current.left)) queue.push(current.left);
2281
- if (current && this.isRealNodeOrNull(current.right)) queue.push(current.right);
2282
- } else {
2283
- if (this.isRealNode(current.left)) queue.push(current.left);
2284
- if (this.isRealNode(current.right)) queue.push(current.right);
2285
- }
2286
- }
2287
- }
2288
- }
2289
- return ans;
2290
- }
2291
- /**
2292
- * Time complexity: O(n)
2293
- * Space complexity: O(n)
2294
- *
2295
- * The `leaves` function in TypeScript returns an array of values from leaf nodes in a binary tree
2296
- * structure based on a specified callback and iteration type.
2297
- * @param {C} callback - The `callback` parameter is a function that will be called on each leaf node
2298
- * in the binary tree. It is optional and defaults to a default callback function if not provided.
2299
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the `leaves`
2300
- * method is used to specify the starting point for finding and processing the leaves of a binary
2301
- * tree. It can be provided as either a key, a node, or an entry in the binary tree structure. If not
2302
- * explicitly provided, the default value
2303
- * @param {IterationType} iterationType - The `iterationType` parameter in the `leaves` method
2304
- * specifies the type of iteration to be performed when collecting the leaves of a binary tree. It
2305
- * can have two possible values:
2306
- * @returns The `leaves` method returns an array of values that are the result of applying the
2307
- * provided callback function to each leaf node in the binary tree.
2308
- */
2309
- leaves(callback = this._DEFAULT_NODE_CALLBACK, startNode = this._root, iterationType = this.iterationType) {
2310
- startNode = this.ensureNode(startNode);
2311
- const leaves = [];
2312
- if (!this.isRealNode(startNode)) return [];
2313
- if (iterationType === "RECURSIVE") {
2314
- const dfs = (cur) => {
2315
- if (this.isLeaf(cur)) {
2316
- leaves.push(callback(cur));
2317
- }
2318
- if (!this.isRealNode(cur.left) && !this.isRealNode(cur.right)) return;
2319
- if (this.isRealNode(cur.left)) dfs(cur.left);
2320
- if (this.isRealNode(cur.right)) dfs(cur.right);
2321
- };
2322
- dfs(startNode);
2323
- } else {
2324
- const queue = new Queue([startNode]);
2325
- while (queue.length > 0) {
2326
- const cur = queue.shift();
2327
- if (this.isRealNode(cur)) {
2328
- if (this.isLeaf(cur)) {
2329
- leaves.push(callback(cur));
2330
- }
2331
- if (this.isRealNode(cur.left)) queue.push(cur.left);
2332
- if (this.isRealNode(cur.right)) queue.push(cur.right);
2333
- }
2334
- }
2335
- }
2336
- return leaves;
2337
- }
2338
- /**
2339
- * Time complexity: O(n)
2340
- * Space complexity: O(n)
2341
- *
2342
- * The `listLevels` function in TypeScript generates a list of nodes at each level of a binary tree,
2343
- * using either recursive or iterative traversal based on the specified iteration type.
2344
- * @param {C} callback - The `callback` parameter is a function that will be applied to each node in
2345
- * the binary tree during the traversal. It is used to process each node and determine what
2346
- * information to include in the output for each level of the tree.
2347
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the
2348
- * `listLevels` function represents the starting point for traversing the binary tree. It can be
2349
- * either a key, a node, or an entry in the binary tree. If not provided, the default value is the
2350
- * root of the binary tree.
2351
- * @param {IterationType} iterationType - The `iterationType` parameter in the `listLevels` function
2352
- * determines the type of iteration to be performed on the binary tree nodes. It can have two
2353
- * possible values:
2354
- * @param [includeNull=false] - The `includeNull` parameter in the `listLevels` method determines
2355
- * whether or not to include null nodes in the traversal of the binary tree. If `includeNull` is set
2356
- * to `true`, the traversal will include null nodes in the levels of the tree. If set to `false`,
2357
- * null
2358
- * @returns The `listLevels` method returns an array of arrays, where each inner array represents a
2359
- * level in a binary tree. Each inner array contains the return value of the provided callback
2360
- * function applied to the nodes at that level.
2361
- */
2362
- listLevels(callback = this._DEFAULT_NODE_CALLBACK, startNode = this._root, iterationType = this.iterationType, includeNull = false) {
2363
- startNode = this.ensureNode(startNode);
2364
- const levelsNodes = [];
2365
- if (!startNode) return levelsNodes;
2366
- if (iterationType === "RECURSIVE") {
2367
- const _recursive = (node, level) => {
2368
- if (!levelsNodes[level]) levelsNodes[level] = [];
2369
- levelsNodes[level].push(callback(node));
2370
- if (includeNull) {
2371
- if (node && this.isRealNodeOrNull(node.left)) _recursive(node.left, level + 1);
2372
- if (node && this.isRealNodeOrNull(node.right)) _recursive(node.right, level + 1);
2373
- } else {
2374
- if (node && node.left) _recursive(node.left, level + 1);
2375
- if (node && node.right) _recursive(node.right, level + 1);
2376
- }
2377
- };
2378
- _recursive(startNode, 0);
2379
- } else {
2380
- const stack = [[startNode, 0]];
2381
- while (stack.length > 0) {
2382
- const head = stack.pop();
2383
- const [node, level] = head;
2384
- if (!levelsNodes[level]) levelsNodes[level] = [];
2385
- levelsNodes[level].push(callback(node));
2386
- if (includeNull) {
2387
- if (node && this.isRealNodeOrNull(node.right)) stack.push([node.right, level + 1]);
2388
- if (node && this.isRealNodeOrNull(node.left)) stack.push([node.left, level + 1]);
2389
- } else {
2390
- if (node && node.right) stack.push([node.right, level + 1]);
2391
- if (node && node.left) stack.push([node.left, level + 1]);
2392
- }
2393
- }
2394
- }
2395
- return levelsNodes;
2396
- }
2397
- /**
2398
- * Time complexity: O(n)
2399
- * Space complexity: O(n)
2400
- *
2401
- * The `morris` function in TypeScript performs a Depth-First Search traversal on a binary tree using
2402
- * Morris Traversal algorithm with different order patterns.
2403
- * @param {C} callback - The `callback` parameter in the `morris` function is a function that will be
2404
- * called on each node in the binary tree during the traversal. It is of type `C`, which extends the
2405
- * `NodeCallback<BinaryTreeNode<K, V> | null>` type. The default value for `callback` is `this._DEFAULT
2406
- * @param {DFSOrderPattern} [pattern=IN] - The `pattern` parameter in the `morris` function specifies
2407
- * the type of Depth-First Search (DFS) order pattern to traverse the binary tree. The possible
2408
- * values for the `pattern` parameter are:
2409
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the `morris`
2410
- * function is the starting point for the Morris traversal algorithm. It represents the root node of
2411
- * the binary tree or the node from which the traversal should begin. It can be provided as either a
2412
- * key, a node, an entry, or a reference
2413
- * @returns The `morris` function is returning an array of values that are the result of applying the
2414
- * provided callback function to each node in the binary tree in the specified order pattern (IN,
2415
- * PRE, or POST).
2416
- */
2417
- morris(callback = this._DEFAULT_NODE_CALLBACK, pattern = "IN", startNode = this._root) {
2418
- startNode = this.ensureNode(startNode);
2419
- if (!startNode) return [];
2420
- const ans = [];
2421
- let cur = startNode;
2422
- const _reverseEdge = (node) => {
2423
- let pre = null;
2424
- let next = null;
2425
- while (node) {
2426
- next = node.right;
2427
- node.right = pre;
2428
- pre = node;
2429
- node = next;
2430
- }
2431
- return pre;
2432
- };
2433
- const _printEdge = (node) => {
2434
- const tail = _reverseEdge(node);
2435
- let cur2 = tail;
2436
- while (cur2) {
2437
- ans.push(callback(cur2));
2438
- cur2 = cur2.right;
2439
- }
2440
- _reverseEdge(tail);
2441
- };
2442
- switch (pattern) {
2443
- case "IN":
2444
- while (cur) {
2445
- if (cur.left) {
2446
- const predecessor = this.getPredecessor(cur);
2447
- if (!predecessor.right) {
2448
- predecessor.right = cur;
2449
- cur = cur.left;
2450
- continue;
2451
- } else {
2452
- predecessor.right = null;
2453
- }
2454
- }
2455
- ans.push(callback(cur));
2456
- cur = cur.right;
2457
- }
2458
- break;
2459
- case "PRE":
2460
- while (cur) {
2461
- if (cur.left) {
2462
- const predecessor = this.getPredecessor(cur);
2463
- if (!predecessor.right) {
2464
- predecessor.right = cur;
2465
- ans.push(callback(cur));
2466
- cur = cur.left;
2467
- continue;
2468
- } else {
2469
- predecessor.right = null;
2470
- }
2471
- } else {
2472
- ans.push(callback(cur));
2473
- }
2474
- cur = cur.right;
2475
- }
2476
- break;
2477
- case "POST":
2478
- while (cur) {
2479
- if (cur.left) {
2480
- const predecessor = this.getPredecessor(cur);
2481
- if (predecessor.right === null) {
2482
- predecessor.right = cur;
2483
- cur = cur.left;
2484
- continue;
2485
- } else {
2486
- predecessor.right = null;
2487
- _printEdge(cur.left);
2488
- }
2489
- }
2490
- cur = cur.right;
2491
- }
2492
- _printEdge(startNode);
2493
- break;
2494
- }
2495
- return ans;
2496
- }
2497
- /**
2498
- * Time complexity: O(n)
2499
- * Space complexity: O(n)
2500
- *
2501
- * The `clone` function creates a deep copy of a tree structure by traversing it using breadth-first
2502
- * search.
2503
- * @returns The `clone()` method is returning a cloned copy of the tree with the same structure and
2504
- * values as the original tree. The method creates a new tree, iterates over the nodes of the
2505
- * original tree using breadth-first search (bfs), and adds the nodes to the new tree. If a node in
2506
- * the original tree is null, a null node is added to the cloned tree. If a node
2507
- */
2508
- clone() {
2509
- const cloned = this.createTree();
2510
- this._clone(cloned);
2511
- return cloned;
2512
- }
2513
- /**
2514
- * Time Complexity: O(n)
2515
- * Space Complexity: O(n)
2516
- *
2517
- * The `filter` function iterates over key-value pairs in a tree data structure and creates a new
2518
- * tree with elements that satisfy a given predicate.
2519
- * @param predicate - The `predicate` parameter in the `filter` method is a function that will be
2520
- * called with four arguments: the `value` of the current entry, the `key` of the current entry, the
2521
- * `index` of the current entry in the iteration, and the reference to the tree itself (`
2522
- * @param {any} [thisArg] - The `thisArg` parameter in the `filter` method allows you to specify the
2523
- * value of `this` that should be used when executing the `predicate` function. This is useful when
2524
- * the `predicate` function relies on the context of a specific object or value. By providing a
2525
- * `thisArg
2526
- * @returns The `filter` method is returning a new tree that contains entries that pass the provided
2527
- * predicate function.
2528
- */
2529
- filter(predicate, thisArg) {
2530
- const newTree = this.createTree();
2531
- let index = 0;
2532
- for (const [key, value] of this) {
2533
- if (predicate.call(thisArg, key, value, index++, this)) {
2534
- newTree.add([key, value]);
2535
- }
2536
- }
2537
- return newTree;
2538
- }
2539
- /**
2540
- * Time Complexity: O(n)
2541
- * Space Complexity: O(n)
2542
- *
2543
- * The `map` function in TypeScript creates a new BinaryTree by applying a callback function to each
2544
- * entry in the original BinaryTree.
2545
- * @param callback - A function that will be called for each entry in the current binary tree. It
2546
- * takes the key, value (which can be undefined), and an array containing the mapped key and value as
2547
- * arguments.
2548
- * @param [options] - The `options` parameter in the `map` method is of type `BinaryTreeOptions<MK,
2549
- * MV, MR>`. It is an optional parameter that allows you to specify additional options for the binary
2550
- * tree being created during the mapping process. These options could include things like custom
2551
- * comparators, initial
2552
- * @param {any} [thisArg] - The `thisArg` parameter in the `map` method is used to specify the value
2553
- * of `this` when executing the `callback` function. It allows you to set the context (value of
2554
- * `this`) within the callback function. If `thisArg` is provided, it will be passed
2555
- * @returns The `map` function is returning a new `BinaryTree` instance filled with entries that are
2556
- * the result of applying the provided `callback` function to each entry in the original tree.
2557
- */
2558
- map(callback, options, thisArg) {
2559
- const newTree = new _BinaryTree([], options);
2560
- let index = 0;
2561
- for (const [key, value] of this) {
2562
- newTree.add(callback.call(thisArg, key, value, index++, this));
2563
- }
2564
- return newTree;
2565
- }
2566
- /**
2567
- * Time Complexity: O(n)
2568
- * Space Complexity: O(n)
2569
- *
2570
- * The function `toVisual` in TypeScript overrides the visual representation of a binary tree with
2571
- * customizable options for displaying undefined, null, and sentinel nodes.
2572
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the
2573
- * `toVisual` method is used to specify the starting point for visualizing the binary tree structure.
2574
- * It can be a node, key, entry, or the root of the tree. If no specific starting point is provided,
2575
- * the default is set to the root
2576
- * @param {BinaryTreePrintOptions} [options] - The `options` parameter in the `toVisual` method is an
2577
- * object that contains the following properties:
2578
- * @returns The `override toVisual` method returns a string that represents the visual display of the
2579
- * binary tree based on the provided options for showing undefined, null, and Red-Black NIL nodes.
2580
- * The method constructs the visual representation by calling the `_displayAux` method and appending
2581
- * the lines to the output string. The final output string contains the visual representation of the
2582
- * binary tree with the specified options.
2583
- */
2584
- toVisual(startNode = this._root, options) {
2585
- const opts = { isShowUndefined: false, isShowNull: true, isShowRedBlackNIL: false, ...options };
2586
- startNode = this.ensureNode(startNode);
2587
- let output = "";
2588
- if (!startNode) return output;
2589
- if (opts.isShowUndefined) output += `U for undefined
2590
- `;
2591
- if (opts.isShowNull) output += `N for null
2592
- `;
2593
- if (opts.isShowRedBlackNIL) output += `S for Sentinel Node(NIL)
2594
- `;
2595
- const display = (root) => {
2596
- const [lines] = this._displayAux(root, opts);
2597
- let paragraph = "";
2598
- for (const line of lines) {
2599
- paragraph += line + "\n";
2600
- }
2601
- output += paragraph;
2602
- };
2603
- display(startNode);
2604
- return output;
2605
- }
2606
- /**
2607
- * Time Complexity: O(n)
2608
- * Space Complexity: O(n)
2609
- *
2610
- * The function `print` in TypeScript overrides the default print behavior to log a visual
2611
- * representation of the binary tree to the console.
2612
- * @param {BinaryTreePrintOptions} [options] - The `options` parameter is used to specify the
2613
- * printing options for the binary tree. It is an optional parameter that allows you to customize how
2614
- * the binary tree is printed, such as choosing between different traversal orders or formatting
2615
- * options.
2616
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the
2617
- * `override print` method is used to specify the starting point for printing the binary tree. It can
2618
- * be either a key, a node, an entry, or the root of the tree. If no specific starting point is
2619
- * provided, the default value is set to
2620
- */
2621
- print(options, startNode = this._root) {
2622
- console.log(this.toVisual(startNode, options));
2623
- }
2624
- _clone(cloned) {
2625
- this.bfs(
2626
- (node) => {
2627
- if (node === null) cloned.add(null);
2628
- else {
2629
- if (this._isMapMode) cloned.add([node.key, this._store.get(node.key)]);
2630
- else cloned.add([node.key, node.value]);
2631
- }
2632
- },
2633
- this._root,
2634
- this.iterationType,
2635
- true
2636
- );
2637
- if (this._isMapMode) cloned._store = this._store;
2638
- }
2639
- /**
2640
- * Time Complexity: O(1)
2641
- * Space Complexity: O(1)
2642
- *
2643
- * The function `keyValueNodeEntryRawToNodeAndValue` converts various input types into a node object
2644
- * or returns null.
2645
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The
2646
- * `keyValueNodeEntryRawToNodeAndValue` function takes in a parameter `keyNodeOrEntry`, which
2647
- * can be of type `K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined ` or `R`. This parameter represents either a key, a
2648
- * node, an entry
2649
- * @param {V} [value] - The `value` parameter in the `keyValueNodeEntryRawToNodeAndValue` function is
2650
- * an optional parameter of type `V`. It represents the value associated with the key in the node
2651
- * being created. If a `value` is provided, it will be used when creating the node. If
2652
- * @returns The `keyValueNodeEntryRawToNodeAndValue` function returns an optional node
2653
- * (`BinaryTreeNode<K, V> | null | undefined`) based on the input parameters provided. The function checks the type of the
2654
- * input parameter (`keyNodeOrEntry`) and processes it accordingly to return a node or null
2655
- * value.
2656
- */
2657
- _keyValueNodeOrEntryToNodeAndValue(keyNodeOrEntry, value) {
2658
- if (keyNodeOrEntry === void 0) return [void 0, void 0];
2659
- if (keyNodeOrEntry === null) return [null, void 0];
2660
- if (this.isNode(keyNodeOrEntry)) return [keyNodeOrEntry, value];
2661
- if (this.isEntry(keyNodeOrEntry)) {
2662
- const [key, entryValue] = keyNodeOrEntry;
2663
- if (key === void 0) return [void 0, void 0];
2664
- else if (key === null) return [null, void 0];
2665
- const finalValue = value ?? entryValue;
2666
- return [this.createNode(key, finalValue), finalValue];
2667
- }
2668
- return [this.createNode(keyNodeOrEntry, value), value];
2669
- }
2670
- /**
2671
- * Time complexity: O(n)
2672
- * Space complexity: O(n)
2673
- *
2674
- * The `_dfs` function performs a depth-first search traversal on a binary tree, with customizable
2675
- * options for traversal order and node processing.
2676
- * @param {C} callback - The `callback` parameter in the `_dfs` method is a function that will be
2677
- * called on each node visited during the depth-first search traversal. It is a generic type `C` that
2678
- * extends `NodeCallback<BinaryTreeNode<K, V> | null>`. The default value for `callback`
2679
- * @param {DFSOrderPattern} [pattern=IN] - The `pattern` parameter in the `_dfs` method specifies the
2680
- * order in which the nodes are visited during a depth-first search traversal. It can have one of the
2681
- * following values:
2682
- * @param {boolean} [onlyOne=false] - The `onlyOne` parameter in the `_dfs` method is a boolean flag
2683
- * that determines whether the traversal should stop after processing a single node. If `onlyOne` is
2684
- * set to `true`, the traversal will return as soon as a single node is processed. If it is set to
2685
- * `false
2686
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined}
2687
- * startNode - The `startNode` parameter in the `_dfs` method is used to specify the starting node
2688
- * for the depth-first search traversal. It can be provided in different forms:
2689
- * @param {IterationType} iterationType - The `iterationType` parameter in the `_dfs` method
2690
- * specifies whether the traversal should be done recursively or iteratively. It can have two
2691
- * possible values:
2692
- * @param [includeNull=false] - The `includeNull` parameter in the `_dfs` method determines whether
2693
- * null nodes should be included in the traversal process. If `includeNull` is set to `true`, the
2694
- * method will consider null nodes as valid nodes to visit or process. If `includeNull` is set to
2695
- * `false`,
2696
- * @param shouldVisitLeft - The `shouldVisitLeft` parameter in the `_dfs` method is a function that
2697
- * determines whether the left child of a node should be visited during the Depth-First Search
2698
- * traversal. By default, it checks if the node is not null or undefined before visiting the left
2699
- * child. You can customize this behavior
2700
- * @param shouldVisitRight - The `shouldVisitRight` parameter in the `_dfs` method is a function that
2701
- * determines whether to visit the right child node of the current node during a depth-first search
2702
- * traversal. The default implementation of this function checks if the node is not null or undefined
2703
- * before deciding to visit it.
2704
- * @param shouldVisitRoot - The `shouldVisitRoot` parameter in the `_dfs` method is a function that
2705
- * determines whether a given node should be visited during the depth-first search traversal. The
2706
- * function takes a node as an argument and returns a boolean value indicating whether the node
2707
- * should be visited.
2708
- * @param shouldProcessRoot - The `shouldProcessRoot` parameter in the `_dfs` method is a function
2709
- * that determines whether the root node should be processed during the Depth-First Search traversal.
2710
- * It takes a node (BinaryTreeNode<K, V> | null | undefined) as input and returns a boolean value. If
2711
- * the function
2712
- * @returns The `_dfs` method returns an array of the return type of the provided callback function
2713
- * `C`.
2714
- */
2715
- _dfs(callback = this._DEFAULT_NODE_CALLBACK, pattern = "IN", onlyOne = false, startNode = this._root, iterationType = this.iterationType, includeNull = false, shouldVisitLeft = (node) => !!node, shouldVisitRight = (node) => !!node, shouldVisitRoot = (node) => {
2716
- if (includeNull) return this.isRealNodeOrNull(node);
2717
- return this.isRealNode(node);
2718
- }, shouldProcessRoot = (node) => this.isRealNodeOrNull(node)) {
2719
- startNode = this.ensureNode(startNode);
2720
- if (!startNode) return [];
2721
- const ans = [];
2722
- if (iterationType === "RECURSIVE") {
2723
- const dfs = (node) => {
2724
- if (!shouldVisitRoot(node)) return;
2725
- const visitLeft = () => {
2726
- if (shouldVisitLeft(node) && node?.left !== void 0) dfs(node?.left);
2727
- };
2728
- const visitRight = () => {
2729
- if (shouldVisitRight(node) && node?.right !== void 0) dfs(node?.right);
2730
- };
2731
- switch (pattern) {
2732
- case "IN":
2733
- visitLeft();
2734
- if (shouldProcessRoot(node)) {
2735
- ans.push(callback(node));
2736
- if (onlyOne) return;
2737
- }
2738
- visitRight();
2739
- break;
2740
- case "PRE":
2741
- if (shouldProcessRoot(node)) {
2742
- ans.push(callback(node));
2743
- if (onlyOne) return;
2744
- }
2745
- visitLeft();
2746
- visitRight();
2747
- break;
2748
- case "POST":
2749
- visitLeft();
2750
- visitRight();
2751
- if (shouldProcessRoot(node)) {
2752
- ans.push(callback(node));
2753
- if (onlyOne) return;
2754
- }
2755
- break;
2756
- }
2757
- };
2758
- dfs(startNode);
2759
- } else {
2760
- const stack = [{ opt: 0 /* VISIT */, node: startNode }];
2761
- const pushLeft = (cur) => {
2762
- if (shouldVisitLeft(cur.node)) stack.push({ opt: 0 /* VISIT */, node: cur.node?.left });
2763
- };
2764
- const pushRight = (cur) => {
2765
- if (shouldVisitRight(cur.node)) stack.push({ opt: 0 /* VISIT */, node: cur.node?.right });
2766
- };
2767
- const pushRoot = (cur) => {
2768
- if (shouldVisitRoot(cur.node)) stack.push({ opt: 1 /* PROCESS */, node: cur.node });
2769
- };
2770
- while (stack.length > 0) {
2771
- const cur = stack.pop();
2772
- if (cur === void 0) continue;
2773
- if (!shouldVisitRoot(cur.node)) continue;
2774
- if (cur.opt === 1 /* PROCESS */) {
2775
- if (shouldProcessRoot(cur.node) && cur.node !== void 0) {
2776
- ans.push(callback(cur.node));
2777
- if (onlyOne) return ans;
2778
- }
2779
- } else {
2780
- switch (pattern) {
2781
- case "IN":
2782
- pushRight(cur);
2783
- pushRoot(cur);
2784
- pushLeft(cur);
2785
- break;
2786
- case "PRE":
2787
- pushRight(cur);
2788
- pushLeft(cur);
2789
- pushRoot(cur);
2790
- break;
2791
- case "POST":
2792
- pushRoot(cur);
2793
- pushRight(cur);
2794
- pushLeft(cur);
2795
- break;
2796
- }
2797
- }
2798
- }
2799
- }
2800
- return ans;
2801
- }
2802
- /**
2803
- * Time Complexity: O(1)
2804
- * Space Complexity: O(1)
2805
- *
2806
- * The function `_getIterator` returns an iterable iterator for a binary tree data structure, either
2807
- * using an iterative approach or a recursive approach based on the specified iteration type.
2808
- * @param node - The `node` parameter in the `_getIterator` method represents the current node being
2809
- * processed during iteration. It is initially set to the root node of the data structure (or the
2810
- * node passed as an argument), and then it is traversed through the data structure based on the
2811
- * iteration type specified (`ITER
2812
- * @returns The `_getIterator` method returns an IterableIterator containing key-value pairs of nodes
2813
- * in a binary tree structure. The method uses an iterative approach to traverse the tree based on
2814
- * the `iterationType` property. If the `iterationType` is set to 'ITERATIVE', the method uses a
2815
- * stack to perform an in-order traversal of the tree. If the `iterationType` is not 'ITERATIVE
2816
- */
2817
- *_getIterator(node = this._root) {
2818
- if (!node) return;
2819
- if (this.iterationType === "ITERATIVE") {
2820
- const stack = [];
2821
- let current = node;
2822
- while (current || stack.length > 0) {
2823
- while (this.isRealNode(current)) {
2824
- stack.push(current);
2825
- current = current.left;
2826
- }
2827
- current = stack.pop();
2828
- if (this.isRealNode(current)) {
2829
- if (this._isMapMode) yield [current.key, this._store.get(current.key)];
2830
- else yield [current.key, current.value];
2831
- current = current.right;
2832
- }
2833
- }
2834
- } else {
2835
- if (node.left && this.isRealNode(node)) {
2836
- yield* this[Symbol.iterator](node.left);
2837
- }
2838
- if (this._isMapMode) yield [node.key, this._store.get(node.key)];
2839
- else yield [node.key, node.value];
2840
- if (node.right && this.isRealNode(node)) {
2841
- yield* this[Symbol.iterator](node.right);
2842
- }
2843
- }
2844
- }
2845
- /**
2846
- * Time Complexity: O(n)
2847
- * Space Complexity: O(n)
2848
- *
2849
- * The function `_displayAux` in TypeScript is responsible for generating the display layout of nodes
2850
- * in a binary tree based on specified options.
2851
- * @param node - The `node` parameter in the `_displayAux` function represents a node in a binary
2852
- * tree. It can be either a valid node containing a key or a special type of node like null,
2853
- * undefined, or a Red-Black tree NIL node. The function checks the type of the node and its
2854
- * @param {BinaryTreePrintOptions} options - The `options` parameter in the `_displayAux` function
2855
- * contains the following properties:
2856
- * @returns The `_displayAux` function returns a `NodeDisplayLayout`, which is an array containing
2857
- * information about how to display a node in a binary tree. The `NodeDisplayLayout` consists of four
2858
- * elements:
2859
- */
2860
- _displayAux(node, options) {
2861
- const { isShowNull, isShowUndefined, isShowRedBlackNIL } = options;
2862
- const emptyDisplayLayout = [["\u2500"], 1, 0, 0];
2863
- if (node === null && !isShowNull) {
2864
- return emptyDisplayLayout;
2865
- } else if (node === void 0 && !isShowUndefined) {
2866
- return emptyDisplayLayout;
2867
- } else if (this.isNIL(node) && !isShowRedBlackNIL) {
2868
- return emptyDisplayLayout;
2869
- } else if (node !== null && node !== void 0) {
2870
- const key = node.key, line = this.isNIL(node) ? "S" : String(key), width = line.length;
2871
- return _buildNodeDisplay(
2872
- line,
2873
- width,
2874
- this._displayAux(node.left, options),
2875
- this._displayAux(node.right, options)
2876
- );
2877
- } else {
2878
- const line = node === void 0 ? "U" : "N", width = line.length;
2879
- return _buildNodeDisplay(line, width, [[""], 1, 0, 0], [[""], 1, 0, 0]);
2880
- }
2881
- function _buildNodeDisplay(line, width, left, right) {
2882
- const [leftLines, leftWidth, leftHeight, leftMiddle] = left;
2883
- const [rightLines, rightWidth, rightHeight, rightMiddle] = right;
2884
- const firstLine = " ".repeat(Math.max(0, leftMiddle + 1)) + "_".repeat(Math.max(0, leftWidth - leftMiddle - 1)) + line + "_".repeat(Math.max(0, rightMiddle)) + " ".repeat(Math.max(0, rightWidth - rightMiddle));
2885
- const secondLine = (leftHeight > 0 ? " ".repeat(leftMiddle) + "/" + " ".repeat(leftWidth - leftMiddle - 1) : " ".repeat(leftWidth)) + " ".repeat(width) + (rightHeight > 0 ? " ".repeat(rightMiddle) + "\\" + " ".repeat(rightWidth - rightMiddle - 1) : " ".repeat(rightWidth));
2886
- const mergedLines = [firstLine, secondLine];
2887
- for (let i = 0; i < Math.max(leftHeight, rightHeight); i++) {
2888
- const leftLine = i < leftHeight ? leftLines[i] : " ".repeat(leftWidth);
2889
- const rightLine = i < rightHeight ? rightLines[i] : " ".repeat(rightWidth);
2890
- mergedLines.push(leftLine + " ".repeat(width) + rightLine);
2891
- }
2892
- return [
2893
- mergedLines,
2894
- leftWidth + width + rightWidth,
2895
- Math.max(leftHeight, rightHeight) + 2,
2896
- leftWidth + Math.floor(width / 2)
2897
- ];
2898
- }
2899
- }
2900
- _DEFAULT_NODE_CALLBACK = (node) => node ? node.key : void 0;
2901
- /**
2902
- * Time Complexity: O(1)
2903
- * Space Complexity: O(1)
2904
- *
2905
- * The _swapProperties function swaps key and value properties between two nodes in a binary tree.
2906
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } srcNode - The `srcNode` parameter in the
2907
- * `_swapProperties` method can be either a BTNRep object containing key and value
2908
- * properties, or it can be of type R.
2909
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } destNode - The `destNode` parameter in the
2910
- * `_swapProperties` method represents the node or entry where the properties will be swapped with
2911
- * the `srcNode`. It can be of type `K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined ` or `R`. The method ensures that
2912
- * both `srcNode
2913
- * @returns The `_swapProperties` method returns either the `destNode` with its key and value swapped
2914
- * with the `srcNode`, or `undefined` if either `srcNode` or `destNode` is falsy.
2915
- */
2916
- _swapProperties(srcNode, destNode) {
2917
- srcNode = this.ensureNode(srcNode);
2918
- destNode = this.ensureNode(destNode);
2919
- if (srcNode && destNode) {
2920
- const { key, value } = destNode;
2921
- const tempNode = this.createNode(key, value);
2922
- if (tempNode) {
2923
- destNode.key = srcNode.key;
2924
- if (!this._isMapMode) destNode.value = srcNode.value;
2925
- srcNode.key = tempNode.key;
2926
- if (!this._isMapMode) srcNode.value = tempNode.value;
2927
- }
2928
- return destNode;
2929
- }
2930
- return void 0;
2931
- }
2932
- /**
2933
- * Time Complexity: O(1)
2934
- * Space Complexity: O(1)
2935
- *
2936
- * The _replaceNode function replaces an old node with a new node in a binary tree structure.
2937
- * @param {BinaryTreeNode<K, V>} oldNode - The `oldNode` parameter represents the node that you want to replace in a
2938
- * tree data structure.
2939
- * @param {BinaryTreeNode<K, V>} newNode - The `newNode` parameter in the `_replaceNode` function represents the node
2940
- * that will replace the `oldNode` in a tree data structure. This function is responsible for
2941
- * updating the parent, left child, right child, and root (if necessary) references when replacing a
2942
- * node in the tree.
2943
- * @returns The method `_replaceNode` is returning the `newNode` that was passed as a parameter after
2944
- * replacing the `oldNode` with it in the binary tree structure.
2945
- */
2946
- _replaceNode(oldNode, newNode) {
2947
- if (oldNode.parent) {
2948
- if (oldNode.parent.left === oldNode) {
2949
- oldNode.parent.left = newNode;
2950
- } else if (oldNode.parent.right === oldNode) {
2951
- oldNode.parent.right = newNode;
2952
- }
2953
- }
2954
- newNode.left = oldNode.left;
2955
- newNode.right = oldNode.right;
2956
- newNode.parent = oldNode.parent;
2957
- if (this._root === oldNode) {
2958
- this._setRoot(newNode);
2959
- }
2960
- return newNode;
2961
- }
2962
- /**
2963
- * Time Complexity: O(1)
2964
- * Space Complexity: O(1)
2965
- *
2966
- * The function _setRoot sets the root node of a data structure while updating the parent reference
2967
- * of the previous root node.
2968
- * @param v - The parameter `v` in the `_setRoot` method is of type `BinaryTreeNode<K, V> | null | undefined`, which means
2969
- * it can either be an optional `BinaryTreeNode<K, V>` type or `null`.
2970
- */
2971
- _setRoot(v) {
2972
- if (v) {
2973
- v.parent = void 0;
2974
- }
2975
- this._root = v;
2976
- }
2977
- /**
2978
- * Time Complexity: O(1)
2979
- * Space Complexity: O(1)
2980
- *
2981
- * The function `_ensurePredicate` in TypeScript ensures that the input is converted into a valid
2982
- * predicate function for a binary tree node.
2983
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined | NodePredicate<BinaryTreeNode<K, V>>} keyNodeEntryOrPredicate - The
2984
- * `_ensurePredicate` method in the provided code snippet is responsible for ensuring that the input
2985
- * parameter `keyNodeEntryOrPredicate` is transformed into a valid predicate function that can be
2986
- * used for filtering nodes in a binary tree.
2987
- * @returns A NodePredicate<BinaryTreeNode<K, V>> function is being returned.
2988
- */
2989
- _ensurePredicate(keyNodeEntryOrPredicate) {
2990
- if (keyNodeEntryOrPredicate === null || keyNodeEntryOrPredicate === void 0)
2991
- return (node) => node ? false : false;
2992
- if (this._isPredicate(keyNodeEntryOrPredicate)) return keyNodeEntryOrPredicate;
2993
- if (this.isRealNode(keyNodeEntryOrPredicate))
2994
- return (node) => node === keyNodeEntryOrPredicate;
2995
- if (this.isEntry(keyNodeEntryOrPredicate)) {
2996
- const [key] = keyNodeEntryOrPredicate;
2997
- return (node) => {
2998
- if (!node) return false;
2999
- return node.key === key;
3000
- };
3001
- }
3002
- return (node) => {
3003
- if (!node) return false;
3004
- return node.key === keyNodeEntryOrPredicate;
3005
- };
3006
- }
3007
- /**
3008
- * Time Complexity: O(1)
3009
- * Space Complexity: O(1)
3010
- *
3011
- * The function `_isPredicate` checks if a given parameter is a function.
3012
- * @param {any} p - The parameter `p` is a variable of type `any`, which means it can hold any type
3013
- * of value. In this context, the function `_isPredicate` is checking if `p` is a function that
3014
- * satisfies the type `NodePredicate<BinaryTreeNode<K, V>>`.
3015
- * @returns The function is checking if the input `p` is a function and returning a boolean value
3016
- * based on that check. If `p` is a function, it will return `true`, indicating that `p` is a
3017
- * predicate function for a binary tree node. If `p` is not a function, it will return `false`.
3018
- */
3019
- _isPredicate(p) {
3020
- return typeof p === "function";
3021
- }
3022
- /**
3023
- * Time Complexity: O(1)
3024
- * Space Complexity: O(1)
3025
- *
3026
- * The function `_extractKey` in TypeScript returns the key from a given input, which can be a node,
3027
- * entry, raw data, or null/undefined.
3028
- * @param {K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The `_extractKey` method you provided is a
3029
- * TypeScript method that takes in a parameter `keyNodeOrEntry` of type `K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined `,
3030
- * where `BTNRep` is a generic type with keys `K`, `V`, and `BinaryTreeNode<K, V>`, and `
3031
- * @returns The `_extractKey` method returns the key value extracted from the `keyNodeOrEntry`
3032
- * parameter. The return value can be a key value of type `K`, `null`, or `undefined`, depending on
3033
- * the conditions checked in the method.
3034
- */
3035
- _extractKey(keyNodeOrEntry) {
3036
- if (keyNodeOrEntry === null) return null;
3037
- if (keyNodeOrEntry === void 0) return;
3038
- if (keyNodeOrEntry === this._NIL) return;
3039
- if (this.isNode(keyNodeOrEntry)) return keyNodeOrEntry.key;
3040
- if (this.isEntry(keyNodeOrEntry)) return keyNodeOrEntry[0];
3041
- return keyNodeOrEntry;
3042
- }
3043
- /**
3044
- * Time Complexity: O(1)
3045
- * Space Complexity: O(1)
3046
- *
3047
- * The function `_setValue` sets a value in a store based on a key, handling cases where the key or
3048
- * value is null or undefined.
3049
- * @param {K | null | undefined} key - The `key` parameter can be of type `K`, `null`, or
3050
- * `undefined`.
3051
- * @param {V | undefined} value - The `value` parameter in the `_setValue` method can be of type `V`
3052
- * or `undefined`.
3053
- * @returns The method `_setValue` returns `false` if either the `key` is `null` or `undefined`, or
3054
- * if the `value` is `undefined`. Otherwise, it returns the result of calling the `set` method on the
3055
- * `_store` object with the `key` and `value` arguments.
3056
- */
3057
- _setValue(key, value) {
3058
- if (key === null || key === void 0) return false;
3059
- if (value === void 0) return false;
3060
- return this._store.set(key, value);
3061
- }
3062
- /**
3063
- * Time Complexity: O(1)
3064
- * Space Complexity: O(1)
3065
- *
3066
- * The _clearNodes function sets the root node to undefined and resets the size to 0.
3067
- */
3068
- _clearNodes() {
3069
- this._setRoot(void 0);
3070
- this._size = 0;
3071
- }
3072
- /**
3073
- * Time Complexity: O(1)
3074
- * Space Complexity: O(1)
3075
- *
3076
- * The _clearValues function clears all values stored in the _store object.
3077
- */
3078
- _clearValues() {
3079
- this._store.clear();
3080
- }
3081
- };
3082
-
3083
- // src/data-structures/binary-tree/bst.ts
3084
- var BSTNode = class extends BinaryTreeNode {
3085
- parent = void 0;
3086
- /**
3087
- * This TypeScript constructor function initializes an instance with a key and an optional value.
3088
- * @param {K} key - The `key` parameter is typically used to uniquely identify an object or element
3089
- * within a data structure. It serves as a reference or identifier for accessing or manipulating the
3090
- * associated value.
3091
- * @param {V} [value] - The `value` parameter in the constructor is optional, meaning it does not
3092
- * have to be provided when creating an instance of the class. If a value is not provided, it will
3093
- * default to `undefined`.
3094
- */
3095
- constructor(key, value) {
3096
- super(key, value);
3097
- }
3098
- _left = void 0;
3099
- get left() {
3100
- return this._left;
3101
- }
3102
- set left(v) {
3103
- if (v) {
3104
- v.parent = this;
3105
- }
3106
- this._left = v;
3107
- }
3108
- _right = void 0;
3109
- get right() {
3110
- return this._right;
3111
- }
3112
- set right(v) {
3113
- if (v) {
3114
- v.parent = this;
3115
- }
3116
- this._right = v;
3117
- }
3118
- };
3119
- var BST = class _BST extends BinaryTree {
3120
- /**
3121
- * This TypeScript constructor initializes a binary search tree with optional options and adds
3122
- * elements if provided.
3123
- * @param keysNodesEntriesOrRaws - The `keysNodesEntriesOrRaws` parameter in the constructor is an
3124
- * iterable that can contain elements of type `K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined ` or `R`. It is used to
3125
- * initialize the binary search tree with keys, nodes, entries, or raw data.
3126
- * @param [options] - The `options` parameter is an optional object that can contain the following
3127
- * properties:
3128
- */
3129
- constructor(keysNodesEntriesOrRaws = [], options) {
3130
- super([], options);
3131
- if (options) {
3132
- const { specifyComparable, isReverse } = options;
3133
- if (typeof specifyComparable === "function") this._specifyComparable = specifyComparable;
3134
- if (isReverse !== void 0) this._isReverse = isReverse;
3135
- }
3136
- if (keysNodesEntriesOrRaws) this.addMany(keysNodesEntriesOrRaws);
3137
- }
3138
- _root = void 0;
3139
- get root() {
3140
- return this._root;
3141
- }
3142
- _isReverse = false;
3143
- get isReverse() {
3144
- return this._isReverse;
3145
- }
3146
- _comparator = (a, b) => {
3147
- if (isComparable(a) && isComparable(b)) {
3148
- if (a > b) return 1;
3149
- if (a < b) return -1;
3150
- return 0;
3151
- }
3152
- if (this._specifyComparable) {
3153
- if (this._specifyComparable(a) > this._specifyComparable(b)) return 1;
3154
- if (this._specifyComparable(a) < this._specifyComparable(b)) return -1;
3155
- return 0;
3156
- }
3157
- if (typeof a === "object" || typeof b === "object") {
3158
- throw TypeError(
3159
- `When comparing object types, a custom specifyComparable must be defined in the constructor's options parameter.`
3160
- );
3161
- }
3162
- return 0;
3163
- };
3164
- get comparator() {
3165
- return this._comparator;
3166
- }
3167
- _specifyComparable;
3168
- get specifyComparable() {
3169
- return this._specifyComparable;
3170
- }
3171
- /**
3172
- * Time Complexity: O(1)
3173
- * Space Complexity: O(1)
3174
- *
3175
- * The function creates a new BSTNode with the given key and value and returns it.
3176
- * @param {K} key - The key parameter is of type K, which represents the type of the key for the node
3177
- * being created.
3178
- * @param {V} [value] - The "value" parameter is an optional parameter of type V. It represents the
3179
- * value associated with the key in the node being created.
3180
- * @returns The method is returning a new instance of the BSTNode class, casted as the BSTNode<K, V> type.
3181
- */
3182
- createNode(key, value) {
3183
- return new BSTNode(key, this._isMapMode ? void 0 : value);
3184
- }
3185
- /**
3186
- * Time Complexity: O(1)
3187
- * Space Complexity: O(1)
3188
- *
3189
- * The function creates a new binary search tree with the specified options.
3190
- * @param [options] - The `options` parameter is an optional object that allows you to customize the
3191
- * behavior of the `createTree` method. It accepts a partial `BSTOptions` object, which has the
3192
- * following properties:
3193
- * @returns a new instance of the BST class with the provided options.
3194
- */
3195
- createTree(options) {
3196
- return new _BST([], {
3197
- iterationType: this.iterationType,
3198
- isMapMode: this._isMapMode,
3199
- specifyComparable: this._specifyComparable,
3200
- toEntryFn: this._toEntryFn,
3201
- isReverse: this._isReverse,
3202
- ...options
3203
- });
3204
- }
3205
- /**
3206
- * Time Complexity: O(log n)
3207
- * Space Complexity: O(log n)
3208
- *
3209
- * The function ensures the existence of a node in a data structure and returns it, or undefined if
3210
- * it doesn't exist.
3211
- * @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The parameter
3212
- * `keyNodeOrEntry` can accept a value of type `R`, which represents the key, node,
3213
- * entry, or raw element that needs to be ensured in the tree.
3214
- * @param {IterationType} [iterationType=ITERATIVE] - The `iterationType` parameter is an optional
3215
- * parameter that specifies the type of iteration to be used when ensuring a node. It has a default
3216
- * value of `'ITERATIVE'`.
3217
- * @returns The method is returning either the node that was ensured or `undefined` if the node could
3218
- * not be ensured.
3219
- */
3220
- ensureNode(keyNodeOrEntry, iterationType = this.iterationType) {
3221
- return super.ensureNode(keyNodeOrEntry, iterationType) ?? void 0;
3222
- }
3223
- /**
3224
- * Time Complexity: O(1)
3225
- * Space Complexity: O(1)
3226
- *
3227
- * The function checks if the input is an instance of the BSTNode class.
3228
- * @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The parameter
3229
- * `keyNodeOrEntry` can be of type `R` or `K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined `.
3230
- * @returns a boolean value indicating whether the input parameter `keyNodeOrEntry` is
3231
- * an instance of the `BSTNode` class.
3232
- */
3233
- isNode(keyNodeOrEntry) {
3234
- return keyNodeOrEntry instanceof BSTNode;
3235
- }
3236
- /**
3237
- * Time Complexity: O(1)
3238
- * Space Complexity: O(1)
3239
- *
3240
- * The function "override isValidKey" checks if a key is comparable based on a given comparator.
3241
- * @param {any} key - The `key` parameter is a value that will be checked to determine if it is of
3242
- * type `K`.
3243
- * @returns The `override isValidKey(key: any): key is K` function is returning a boolean value based on
3244
- * the result of the `isComparable` function with the condition `this._compare !==
3245
- * this._DEFAULT_COMPARATOR`.
3246
- */
3247
- isValidKey(key) {
3248
- return isComparable(key, this._specifyComparable !== void 0);
3249
- }
3250
- /**
3251
- * Time Complexity: O(log n)
3252
- * Space Complexity: O(log n)
3253
- *
3254
- * The `add` function in TypeScript adds a new node to a binary search tree based on the key value.
3255
- * @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The parameter
3256
- * `keyNodeOrEntry` can accept a value of type `R` or `K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined `.
3257
- * @param {V} [value] - The `value` parameter is an optional value that can be associated with the
3258
- * key in the binary search tree. If provided, it will be stored in the node along with the key.
3259
- * @returns a boolean value.
3260
- */
3261
- add(keyNodeOrEntry, value) {
3262
- const [newNode, newValue] = this._keyValueNodeOrEntryToNodeAndValue(keyNodeOrEntry, value);
3263
- if (newNode === void 0) return false;
3264
- if (this._root === void 0) {
3265
- this._setRoot(newNode);
3266
- if (this._isMapMode) this._setValue(newNode?.key, newValue);
3267
- this._size++;
3268
- return true;
3269
- }
3270
- let current = this._root;
3271
- while (current !== void 0) {
3272
- if (this._compare(current.key, newNode.key) === 0) {
3273
- this._replaceNode(current, newNode);
3274
- if (this._isMapMode) this._setValue(current.key, newValue);
3275
- return true;
3276
- } else if (this._compare(current.key, newNode.key) > 0) {
3277
- if (current.left === void 0) {
3278
- current.left = newNode;
3279
- if (this._isMapMode) this._setValue(newNode?.key, newValue);
3280
- this._size++;
3281
- return true;
3282
- }
3283
- if (current.left !== null) current = current.left;
3284
- } else {
3285
- if (current.right === void 0) {
3286
- current.right = newNode;
3287
- if (this._isMapMode) this._setValue(newNode?.key, newValue);
3288
- this._size++;
3289
- return true;
3290
- }
3291
- if (current.right !== null) current = current.right;
3292
- }
3293
- }
3294
- return false;
3295
- }
3296
- /**
3297
- * Time Complexity: O(k log n)
3298
- * Space Complexity: O(k + log n)
3299
- *
3300
- * The `addMany` function in TypeScript adds multiple keys or nodes to a data structure and returns
3301
- * an array indicating whether each key or node was successfully inserted.
3302
- * @param keysNodesEntriesOrRaws - An iterable containing keys, nodes, entries, or raw
3303
- * elements to be added to the data structure.
3304
- * @param [values] - An optional iterable of values to be associated with the keys or nodes being
3305
- * added. If provided, the values will be assigned to the corresponding keys or nodes in the same
3306
- * order. If not provided, undefined will be assigned as the value for each key or node.
3307
- * @param [isBalanceAdd=true] - A boolean flag indicating whether the tree should be balanced after
3308
- * adding the elements. If set to true, the tree will be balanced using a binary search tree
3309
- * algorithm. If set to false, the elements will be added without balancing the tree. The default
3310
- * value is true.
3311
- * @param {IterationType} iterationType - The `iterationType` parameter is an optional parameter that
3312
- * specifies the type of iteration to use when adding multiple keys or nodes to the binary search
3313
- * tree. It can have two possible values:
3314
- * @returns The function `addMany` returns an array of booleans indicating whether each element was
3315
- * successfully inserted into the data structure.
3316
- */
3317
- addMany(keysNodesEntriesOrRaws, values, isBalanceAdd = true, iterationType = this.iterationType) {
3318
- const inserted = [];
3319
- let valuesIterator;
3320
- if (values) {
3321
- valuesIterator = values[Symbol.iterator]();
3322
- }
3323
- if (!isBalanceAdd) {
3324
- for (let kve of keysNodesEntriesOrRaws) {
3325
- const value = valuesIterator?.next().value;
3326
- if (this.isRaw(kve)) kve = this._toEntryFn(kve);
3327
- inserted.push(this.add(kve, value));
3328
- }
3329
- return inserted;
3330
- }
3331
- const realBTNExemplars = [];
3332
- let i = 0;
3333
- for (const kve of keysNodesEntriesOrRaws) {
3334
- realBTNExemplars.push({ key: kve, value: valuesIterator?.next().value, orgIndex: i });
3335
- i++;
3336
- }
3337
- let sorted = [];
3338
- sorted = realBTNExemplars.sort(({ key: a }, { key: b }) => {
3339
- let keyA, keyB;
3340
- if (this.isRaw(a)) keyA = this._toEntryFn(a)[0];
3341
- else if (this.isEntry(a)) keyA = a[0];
3342
- else if (this.isRealNode(a)) keyA = a.key;
3343
- else {
3344
- keyA = a;
3345
- }
3346
- if (this.isRaw(b)) keyB = this._toEntryFn(b)[0];
3347
- else if (this.isEntry(b)) keyB = b[0];
3348
- else if (this.isRealNode(b)) keyB = b.key;
3349
- else {
3350
- keyB = b;
3351
- }
3352
- if (keyA !== void 0 && keyA !== null && keyB !== void 0 && keyB !== null) {
3353
- return this._compare(keyA, keyB);
3354
- }
3355
- return 0;
3356
- });
3357
- const _dfs = (arr) => {
3358
- if (arr.length === 0) return;
3359
- const mid = Math.floor((arr.length - 1) / 2);
3360
- const { key, value } = arr[mid];
3361
- const { orgIndex } = arr[mid];
3362
- if (this.isRaw(key)) {
3363
- const entry = this._toEntryFn(key);
3364
- inserted[orgIndex] = this.add(entry);
3365
- } else {
3366
- inserted[orgIndex] = this.add(key, value);
3367
- }
3368
- _dfs(arr.slice(0, mid));
3369
- _dfs(arr.slice(mid + 1));
3370
- };
3371
- const _iterate = () => {
3372
- const n = sorted.length;
3373
- const stack = [[0, n - 1]];
3374
- while (stack.length > 0) {
3375
- const popped = stack.pop();
3376
- if (popped) {
3377
- const [l, r] = popped;
3378
- if (l <= r) {
3379
- const m = l + Math.floor((r - l) / 2);
3380
- const { key, value } = sorted[m];
3381
- const { orgIndex } = sorted[m];
3382
- if (this.isRaw(key)) {
3383
- const entry = this._toEntryFn(key);
3384
- inserted[orgIndex] = this.add(entry);
3385
- } else {
3386
- inserted[orgIndex] = this.add(key, value);
3387
- }
3388
- stack.push([m + 1, r]);
3389
- stack.push([l, m - 1]);
3390
- }
3391
- }
3392
- }
3393
- };
3394
- if (iterationType === "RECURSIVE") {
3395
- _dfs(sorted);
3396
- } else {
3397
- _iterate();
3398
- }
3399
- return inserted;
3400
- }
3401
- /**
3402
- * Time Complexity: O(log n)
3403
- * Space Complexity: O(k + log n)
3404
- *
3405
- * The function `search` in TypeScript overrides the search behavior in a binary tree structure based
3406
- * on specified criteria.
3407
- * @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined | NodePredicate<BSTNode<K, V>>} keyNodeEntryOrPredicate - The
3408
- * `keyNodeEntryOrPredicate` parameter in the `override search` method can accept one of the
3409
- * following types:
3410
- * @param [onlyOne=false] - The `onlyOne` parameter is a boolean flag that determines whether the
3411
- * search should stop after finding the first matching node. If `onlyOne` is set to `true`, the
3412
- * search will return as soon as a matching node is found. If `onlyOne` is set to `false`, the
3413
- * @param {C} callback - The `callback` parameter in the `override search` function is a function
3414
- * that will be called on each node that matches the search criteria. It is of type `C`, which
3415
- * extends `NodeCallback<BSTNode<K, V> | null>`. The callback function should accept a node of type `BSTNode<K, V>` as its
3416
- * argument and
3417
- * @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the `override search`
3418
- * method represents the node from which the search operation will begin. It is the starting point
3419
- * for searching within the tree data structure. The method ensures that the `startNode` is a valid
3420
- * node before proceeding with the search operation. If the `
3421
- * @param {IterationType} iterationType - The `iterationType` parameter in the `override search`
3422
- * function determines the type of iteration to be used during the search operation. It can have two
3423
- * possible values:
3424
- * @returns The `override search` method returns an array of values that match the search criteria
3425
- * specified by the input parameters. The method performs a search operation on a binary tree
3426
- * structure based on the provided key, predicate, and other options. The search results are
3427
- * collected in an array and returned as the output of the method.
3428
- */
3429
- search(keyNodeEntryOrPredicate, onlyOne = false, callback = this._DEFAULT_NODE_CALLBACK, startNode = this._root, iterationType = this.iterationType) {
3430
- if (keyNodeEntryOrPredicate === void 0) return [];
3431
- if (keyNodeEntryOrPredicate === null) return [];
3432
- startNode = this.ensureNode(startNode);
3433
- if (!startNode) return [];
3434
- let predicate;
3435
- const isRange = this.isRange(keyNodeEntryOrPredicate);
3436
- if (isRange) {
3437
- predicate = (node) => {
3438
- if (!node) return false;
3439
- return keyNodeEntryOrPredicate.isInRange(node.key, this._comparator);
3440
- };
3441
- } else {
3442
- predicate = this._ensurePredicate(keyNodeEntryOrPredicate);
3443
- }
3444
- const shouldVisitLeft = (cur) => {
3445
- if (!cur) return false;
3446
- if (!this.isRealNode(cur.left)) return false;
3447
- if (isRange) {
3448
- const range = keyNodeEntryOrPredicate;
3449
- const leftS = this.isReverse ? range.high : range.low;
3450
- const leftI = this.isReverse ? range.includeHigh : range.includeLow;
3451
- return leftI && this._compare(cur.key, leftS) >= 0 || !leftI && this._compare(cur.key, leftS) > 0;
3452
- }
3453
- if (!isRange && !this._isPredicate(keyNodeEntryOrPredicate)) {
3454
- const benchmarkKey = this._extractKey(keyNodeEntryOrPredicate);
3455
- return benchmarkKey !== null && benchmarkKey !== void 0 && this._compare(cur.key, benchmarkKey) > 0;
3456
- }
3457
- return true;
3458
- };
3459
- const shouldVisitRight = (cur) => {
3460
- if (!cur) return false;
3461
- if (!this.isRealNode(cur.right)) return false;
3462
- if (isRange) {
3463
- const range = keyNodeEntryOrPredicate;
3464
- const rightS = this.isReverse ? range.low : range.high;
3465
- const rightI = this.isReverse ? range.includeLow : range.includeLow;
3466
- return rightI && this._compare(cur.key, rightS) <= 0 || !rightI && this._compare(cur.key, rightS) < 0;
3467
- }
3468
- if (!isRange && !this._isPredicate(keyNodeEntryOrPredicate)) {
3469
- const benchmarkKey = this._extractKey(keyNodeEntryOrPredicate);
3470
- return benchmarkKey !== null && benchmarkKey !== void 0 && this._compare(cur.key, benchmarkKey) < 0;
3471
- }
3472
- return true;
3473
- };
3474
- return super._dfs(
3475
- callback,
3476
- "IN",
3477
- onlyOne,
3478
- startNode,
3479
- iterationType,
3480
- false,
3481
- shouldVisitLeft,
3482
- shouldVisitRight,
3483
- () => true,
3484
- (cur) => {
3485
- if (cur) return predicate(cur);
3486
- return false;
3487
- }
3488
- );
3489
- }
3490
- /**
3491
- * Time Complexity: O(log n)
3492
- * Space Complexity: O(k + log n)
3493
- *
3494
- * The `rangeSearch` function searches for nodes within a specified range in a binary search tree.
3495
- * @param {Range<K> | [K, K]} range - The `range` parameter in the `rangeSearch` function can be
3496
- * either a `Range` object or an array of two elements representing the range boundaries.
3497
- * @param {C} callback - The `callback` parameter in the `rangeSearch` function is a callback
3498
- * function that is used to process each node that is found within the specified range during the
3499
- * search operation. It is of type `NodeCallback<BSTNode<K, V> | null>`, where `BSTNode<K, V>` is the type of nodes in the
3500
- * data structure.
3501
- * @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the `rangeSearch`
3502
- * function represents the node from which the search for nodes within the specified range will
3503
- * begin. It is the starting point for the range search operation.
3504
- * @param {IterationType} iterationType - The `iterationType` parameter in the `rangeSearch` function
3505
- * is used to specify the type of iteration to be performed during the search operation. It has a
3506
- * default value of `this.iterationType`, which suggests that it is likely a property of the class or
3507
- * object that the `rangeSearch`
3508
- * @returns The `rangeSearch` function is returning the result of calling the `search` method with
3509
- * the specified parameters.
3510
- */
3511
- rangeSearch(range, callback = this._DEFAULT_NODE_CALLBACK, startNode = this._root, iterationType = this.iterationType) {
3512
- const searchRange = range instanceof Range ? range : new Range(range[0], range[1]);
3513
- return this.search(searchRange, false, callback, startNode, iterationType);
3514
- }
3515
- /**
3516
- * Time Complexity: O(log n)
3517
- * Space Complexity: O(log n)
3518
- *
3519
- * This function retrieves a node based on a given keyNodeEntryOrPredicate within a binary search tree structure.
3520
- * @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined | NodePredicate<BSTNode<K, V>>} keyNodeEntryOrPredicate - The `keyNodeEntryOrPredicate`
3521
- * parameter can be of type `K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined `, `R`, or `NodePredicate<BSTNode<K, V>>`.
3522
- * @param {BSTNOptKeyOrNode<K, BSTNode<K, V>>} startNode - The `startNode` parameter in the `getNode` method
3523
- * is used to specify the starting point for searching nodes in the binary search tree. If no
3524
- * specific starting point is provided, the default value is set to `this._root`, which is the root
3525
- * node of the binary search tree.
3526
- * @param {IterationType} iterationType - The `iterationType` parameter in the `getNode` method is a
3527
- * parameter that specifies the type of iteration to be used. It has a default value of
3528
- * `this.iterationType`, which means it will use the iteration type defined in the class instance if
3529
- * no value is provided when calling the method.
3530
- * @returns The `getNode` method is returning an optional binary search tree node (`OptNode<BSTNode<K, V>>`).
3531
- * It is using the `getNodes` method to find the node based on the provided keyNodeEntryOrPredicate, beginning at
3532
- * the specified root node (`startNode`) and using the specified iteration type. The method then
3533
- * returns the first node found or `undefined` if no node is found.
3534
- */
3535
- getNode(keyNodeEntryOrPredicate, startNode = this._root, iterationType = this.iterationType) {
3536
- return this.getNodes(keyNodeEntryOrPredicate, true, startNode, iterationType)[0] ?? void 0;
3537
- }
3538
- /**
3539
- * Time complexity: O(n)
3540
- * Space complexity: O(n)
3541
- *
3542
- * The function `dfs` in TypeScript overrides the base class method with default parameters and
3543
- * returns the result of the super class `dfs` method.
3544
- * @param {C} callback - The `callback` parameter is a function that will be called for each node
3545
- * visited during the Depth-First Search traversal. It is a generic type `C` that extends the
3546
- * `NodeCallback` interface for `BSTNode<K, V>`. The default value for `callback` is `this._
3547
- * @param {DFSOrderPattern} [pattern=IN] - The `pattern` parameter in the `override dfs` method
3548
- * specifies the order in which the Depth-First Search (DFS) traversal should be performed on the
3549
- * Binary Search Tree (BST). The possible values for the `pattern` parameter are:
3550
- * @param {boolean} [onlyOne=false] - The `onlyOne` parameter in the `override dfs` method is a
3551
- * boolean flag that indicates whether you want to stop the depth-first search traversal after
3552
- * finding the first matching node or continue searching for all matching nodes. If `onlyOne` is set
3553
- * to `true`, the traversal will stop after finding
3554
- * @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined} startNode -
3555
- * The `startNode` parameter in the `override dfs` method can be one of the following types:
3556
- * @param {IterationType} iterationType - The `iterationType` parameter in the `override dfs` method
3557
- * specifies the type of iteration to be performed during the Depth-First Search (DFS) traversal of a
3558
- * Binary Search Tree (BST). It is used to determine the order in which nodes are visited during the
3559
- * traversal. The possible values for `
3560
- * @returns The `override` function is returning the result of calling the `dfs` method from the
3561
- * superclass, with the provided arguments `callback`, `pattern`, `onlyOne`, `startNode`, and
3562
- * `iterationType`. The return type is an array of the return type of the callback function `C`.
3563
- */
3564
- dfs(callback = this._DEFAULT_NODE_CALLBACK, pattern = "IN", onlyOne = false, startNode = this._root, iterationType = this.iterationType) {
3565
- return super.dfs(callback, pattern, onlyOne, startNode, iterationType);
3566
- }
3567
- /**
3568
- * Time complexity: O(n)
3569
- * Space complexity: O(n)
3570
- *
3571
- * The function overrides the breadth-first search method and returns an array of the return types of
3572
- * the callback function.
3573
- * @param {C} callback - The `callback` parameter is a function that will be called for each node
3574
- * visited during the breadth-first search. It should take a single argument, which is the current
3575
- * node being visited, and it can return a value of any type.
3576
- * @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter is the starting
3577
- * point for the breadth-first search. It can be either a root node, a key-value pair, or an entry
3578
- * object. If no value is provided, the default value is the root of the tree.
3579
- * @param {IterationType} iterationType - The `iterationType` parameter is used to specify the type
3580
- * of iteration to be performed during the breadth-first search (BFS) traversal. It can have one of
3581
- * the following values:
3582
- * @returns an array of the return type of the callback function.
3583
- */
3584
- bfs(callback = this._DEFAULT_NODE_CALLBACK, startNode = this._root, iterationType = this.iterationType) {
3585
- return super.bfs(callback, startNode, iterationType, false);
3586
- }
3587
- /**
3588
- * Time complexity: O(n)
3589
- * Space complexity: O(n)
3590
- *
3591
- * The function overrides the listLevels method from the superclass and returns an array of arrays
3592
- * containing the results of the callback function applied to each level of the tree.
3593
- * @param {C} callback - The `callback` parameter is a generic type `C` that extends
3594
- * `NodeCallback<BSTNode<K, V> | null>`. It represents a callback function that will be called for each node in the
3595
- * tree during the iteration process.
3596
- * @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter is the starting
3597
- * point for listing the levels of the binary tree. It can be either a root node of the tree, a
3598
- * key-value pair representing a node in the tree, or a key representing a node in the tree. If no
3599
- * value is provided, the root of
3600
- * @param {IterationType} iterationType - The `iterationType` parameter is used to specify the type
3601
- * of iteration to be performed on the tree. It can have one of the following values:
3602
- * @returns The method is returning a two-dimensional array of the return type of the callback
3603
- * function.
3604
- */
3605
- listLevels(callback = this._DEFAULT_NODE_CALLBACK, startNode = this._root, iterationType = this.iterationType) {
3606
- return super.listLevels(callback, startNode, iterationType, false);
3607
- }
3608
- /**
3609
- * Time complexity: O(n)
3610
- * Space complexity: O(n)
3611
- *
3612
- * The `lesserOrGreaterTraverse` function traverses a binary tree and applies a callback function to
3613
- * each node that meets a certain condition based on a target node and a comparison value.
3614
- * @param {C} callback - The `callback` parameter is a function that will be called for each node
3615
- * that meets the condition specified by the `lesserOrGreater` parameter. It takes a single argument,
3616
- * which is the current node being traversed, and returns a value of any type.
3617
- * @param {CP} lesserOrGreater - The `lesserOrGreater` parameter is used to determine whether to
3618
- * traverse nodes that are lesser, greater, or both than the `targetNode`. It accepts the values -1,
3619
- * 0, or 1, where:
3620
- * @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } targetNode - The `targetNode` parameter is the node in
3621
- * the binary tree that you want to start traversing from. It can be specified either by providing
3622
- * the key of the node, the node itself, or an entry containing the key and value of the node. If no
3623
- * `targetNode` is provided,
3624
- * @param {IterationType} iterationType - The `iterationType` parameter determines the type of
3625
- * traversal to be performed on the binary tree. It can have two possible values:
3626
- * @returns The function `lesserOrGreaterTraverse` returns an array of values of type
3627
- * `ReturnType<C>`, which is the return type of the callback function passed as an argument.
3628
- */
3629
- lesserOrGreaterTraverse(callback = this._DEFAULT_NODE_CALLBACK, lesserOrGreater = -1, targetNode = this._root, iterationType = this.iterationType) {
3630
- const targetNodeEnsured = this.ensureNode(targetNode);
3631
- const ans = [];
3632
- if (!this._root) return ans;
3633
- if (!targetNodeEnsured) return ans;
3634
- const targetKey = targetNodeEnsured.key;
3635
- if (iterationType === "RECURSIVE") {
3636
- const dfs = (cur) => {
3637
- const compared = this._compare(cur.key, targetKey);
3638
- if (Math.sign(compared) === lesserOrGreater) ans.push(callback(cur));
3639
- if (this.isRealNode(cur.left)) dfs(cur.left);
3640
- if (this.isRealNode(cur.right)) dfs(cur.right);
3641
- };
3642
- dfs(this._root);
3643
- return ans;
3644
- } else {
3645
- const queue = new Queue([this._root]);
3646
- while (queue.length > 0) {
3647
- const cur = queue.shift();
3648
- if (this.isRealNode(cur)) {
3649
- const compared = this._compare(cur.key, targetKey);
3650
- if (Math.sign(compared) === lesserOrGreater) ans.push(callback(cur));
3651
- if (this.isRealNode(cur.left)) queue.push(cur.left);
3652
- if (this.isRealNode(cur.right)) queue.push(cur.right);
3653
- }
3654
- }
3655
- return ans;
3656
- }
3657
- }
3658
- /**
3659
- * Time complexity: O(n)
3660
- * Space complexity: O(n)
3661
- *
3662
- * The `perfectlyBalance` function takes an optional `iterationType` parameter and returns `true` if
3663
- * the binary search tree is perfectly balanced, otherwise it returns `false`.
3664
- * @param {IterationType} iterationType - The `iterationType` parameter is an optional parameter that
3665
- * specifies the type of iteration to use when building a balanced binary search tree. It has a
3666
- * default value of `this.iterationType`, which means it will use the iteration type specified in the
3667
- * current instance of the class.
3668
- * @returns The function `perfectlyBalance` returns a boolean value.
3669
- */
3670
- perfectlyBalance(iterationType = this.iterationType) {
3671
- const sorted = this.dfs((node) => node, "IN"), n = sorted.length;
3672
- this._clearNodes();
3673
- if (sorted.length < 1) return false;
3674
- if (iterationType === "RECURSIVE") {
3675
- const buildBalanceBST = (l, r) => {
3676
- if (l > r) return;
3677
- const m = l + Math.floor((r - l) / 2);
3678
- const midNode = sorted[m];
3679
- if (this._isMapMode && midNode !== null) this.add(midNode.key);
3680
- else if (midNode !== null) this.add([midNode.key, midNode.value]);
3681
- buildBalanceBST(l, m - 1);
3682
- buildBalanceBST(m + 1, r);
3683
- };
3684
- buildBalanceBST(0, n - 1);
3685
- return true;
3686
- } else {
3687
- const stack = [[0, n - 1]];
3688
- while (stack.length > 0) {
3689
- const popped = stack.pop();
3690
- if (popped) {
3691
- const [l, r] = popped;
3692
- if (l <= r) {
3693
- const m = l + Math.floor((r - l) / 2);
3694
- const midNode = sorted[m];
3695
- if (this._isMapMode && midNode !== null) this.add(midNode.key);
3696
- else if (midNode !== null) this.add([midNode.key, midNode.value]);
3697
- stack.push([m + 1, r]);
3698
- stack.push([l, m - 1]);
3699
- }
3700
- }
3701
- }
3702
- return true;
3703
- }
3704
- }
3705
- /**
3706
- * Time Complexity: O(n)
3707
- * Space Complexity: O(log n)
3708
- *
3709
- * The function `isAVLBalanced` checks if a binary tree is AVL balanced using either a recursive or
3710
- * iterative approach.
3711
- * @param {IterationType} iterationType - The `iterationType` parameter is an optional parameter that
3712
- * specifies the type of iteration to use when checking if the AVL tree is balanced. It has a default
3713
- * value of `this.iterationType`, which means it will use the iteration type specified in the current
3714
- * instance of the AVL tree.
3715
- * @returns a boolean value.
3716
- */
3717
- isAVLBalanced(iterationType = this.iterationType) {
3718
- if (!this._root) return true;
3719
- let balanced = true;
3720
- if (iterationType === "RECURSIVE") {
3721
- const _height = (cur) => {
3722
- if (!cur) return 0;
3723
- const leftHeight = _height(cur.left), rightHeight = _height(cur.right);
3724
- if (Math.abs(leftHeight - rightHeight) > 1) balanced = false;
3725
- return Math.max(leftHeight, rightHeight) + 1;
3726
- };
3727
- _height(this._root);
3728
- } else {
3729
- const stack = [];
3730
- let node = this._root, last = void 0;
3731
- const depths = /* @__PURE__ */ new Map();
3732
- while (stack.length > 0 || node) {
3733
- if (node) {
3734
- stack.push(node);
3735
- if (node.left !== null) node = node.left;
3736
- } else {
3737
- node = stack[stack.length - 1];
3738
- if (!node.right || last === node.right) {
3739
- node = stack.pop();
3740
- if (node) {
3741
- const left = node.left ? depths.get(node.left) : -1;
3742
- const right = node.right ? depths.get(node.right) : -1;
3743
- if (Math.abs(left - right) > 1) return false;
3744
- depths.set(node, 1 + Math.max(left, right));
3745
- last = node;
3746
- node = void 0;
3747
- }
3748
- } else node = node.right;
3749
- }
3750
- }
3751
- }
3752
- return balanced;
3753
- }
3754
- /**
3755
- * Time complexity: O(n)
3756
- * Space complexity: O(n)
3757
- *
3758
- * The `map` function in TypeScript overrides the default map behavior for a binary search tree by
3759
- * applying a callback function to each entry and creating a new tree with the results.
3760
- * @param callback - A function that will be called for each entry in the BST. It takes four
3761
- * arguments: the key, the value (which can be undefined), the index of the entry, and a reference to
3762
- * the BST itself.
3763
- * @param [options] - The `options` parameter in the `override map` method is of type `BSTOptions<MK,
3764
- * MV, MR>`. It is an optional parameter that allows you to specify additional options for the Binary
3765
- * Search Tree (BST) being created in the `map` method. These options could include configuration
3766
- * @param {any} [thisArg] - The `thisArg` parameter in the `override map` method is used to specify
3767
- * the value of `this` that should be used when executing the `callback` function. It allows you to
3768
- * set the context or scope in which the callback function will be called. This can be useful when
3769
- * you want
3770
- * @returns The `map` method is returning a new Binary Search Tree (`BST`) instance with the entries
3771
- * transformed by the provided callback function.
3772
- */
3773
- map(callback, options, thisArg) {
3774
- const newTree = new _BST([], options);
3775
- let index = 0;
3776
- for (const [key, value] of this) {
3777
- newTree.add(callback.call(thisArg, key, value, index++, this));
3778
- }
3779
- return newTree;
3780
- }
3781
- /**
3782
- * Time complexity: O(n)
3783
- * Space complexity: O(n)
3784
- *
3785
- * The function `clone` overrides the default cloning behavior to create a deep copy of a tree
3786
- * structure.
3787
- * @returns The `cloned` object is being returned.
3788
- */
3789
- clone() {
3790
- const cloned = this.createTree();
3791
- this._clone(cloned);
3792
- return cloned;
3793
- }
3794
- /**
3795
- * Time Complexity: O(1)
3796
- * Space Complexity: O(1)
3797
- *
3798
- * The function overrides a method and converts a key, value pair or entry or raw element to a node.
3799
- * @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - A variable that can be of
3800
- * type R or K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined . It represents either a key, a node, an entry, or a raw
3801
- * element.
3802
- * @param {V} [value] - The `value` parameter is an optional value of type `V`. It represents the
3803
- * value associated with a key in a key-value pair.
3804
- * @returns either a BSTNode<K, V> object or undefined.
3805
- */
3806
- _keyValueNodeOrEntryToNodeAndValue(keyNodeOrEntry, value) {
3807
- const [node, entryValue] = super._keyValueNodeOrEntryToNodeAndValue(keyNodeOrEntry, value);
3808
- if (node === null) return [void 0, void 0];
3809
- return [node, value ?? entryValue];
3810
- }
3811
- /**
3812
- * Time Complexity: O(1)
3813
- * Space Complexity: O(1)
3814
- *
3815
- * The function sets the root of a tree-like structure and updates the parent property of the new
3816
- * root.
3817
- * @param {OptNode<BSTNode<K, V>>} v - v is a parameter of type BSTNode<K, V> or undefined.
3818
- */
3819
- _setRoot(v) {
3820
- if (v) {
3821
- v.parent = void 0;
3822
- }
3823
- this._root = v;
3824
- }
3825
- /**
3826
- * Time Complexity: O(1)
3827
- * Space Complexity: O(1)
3828
- *
3829
- * The _compare function compares two values using a specified comparator function and optionally
3830
- * reverses the result.
3831
- * @param {K} a - The parameter `a` is of type `K`, which is used as an input for comparison in the
3832
- * `_compare` method.
3833
- * @param {K} b - The parameter `b` in the `_compare` function is of type `K`.
3834
- * @returns The `_compare` method is returning the result of the ternary expression. If `_isReverse`
3835
- * is true, it returns the negation of the result of calling the `_comparator` function with
3836
- * arguments `a` and `b`. If `_isReverse` is false, it returns the result of calling the
3837
- * `_comparator` function with arguments `a` and `b`.
3838
- */
3839
- _compare(a, b) {
3840
- return this._isReverse ? -this._comparator(a, b) : this._comparator(a, b);
3841
- }
3842
- };
3843
-
3844
- // src/data-structures/binary-tree/red-black-tree.ts
3845
- var RedBlackTreeNode = class extends BSTNode {
3846
- parent = void 0;
3847
- /**
3848
- * The constructor initializes a node with a key, value, and color for a Red-Black Tree.
3849
- * @param {K} key - The `key` parameter is a key of type `K` that is used to identify the node in a
3850
- * Red-Black Tree data structure.
3851
- * @param {V} [value] - The `value` parameter in the constructor is an optional parameter of type
3852
- * `V`. It represents the value associated with the key in the data structure being constructed.
3853
- * @param {RBTNColor} [color=BLACK] - The `color` parameter in the constructor is used to specify the
3854
- * color of the node in a Red-Black Tree. It has a default value of 'BLACK' if not provided
3855
- * explicitly.
3856
- */
3857
- constructor(key, value, color = "BLACK") {
3858
- super(key, value);
3859
- this._color = color;
3860
- }
3861
- _left = void 0;
3862
- get left() {
3863
- return this._left;
3864
- }
3865
- set left(v) {
3866
- if (v) {
3867
- v.parent = this;
3868
- }
3869
- this._left = v;
3870
- }
3871
- _right = void 0;
3872
- get right() {
3873
- return this._right;
3874
- }
3875
- set right(v) {
3876
- if (v) {
3877
- v.parent = this;
3878
- }
3879
- this._right = v;
3880
- }
3881
- };
3882
- var RedBlackTree = class _RedBlackTree extends BST {
3883
- /**
3884
- * This TypeScript constructor initializes a Red-Black Tree with optional keys, nodes, entries, or
3885
- * raw data.
3886
- * @param keysNodesEntriesOrRaws - The `keysNodesEntriesOrRaws` parameter in the constructor is an
3887
- * iterable that can contain either `K | RedBlackTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined` objects or `R` objects. It
3888
- * is used to initialize the Red-Black Tree with keys, nodes, entries, or
3889
- * @param [options] - The `options` parameter in the constructor is of type `RedBlackTreeOptions<K,
3890
- * V, R>`. It is an optional parameter that allows you to specify additional options for the
3891
- * RedBlackTree class. These options could include configuration settings, behavior customization, or
3892
- * any other parameters that are specific to
3893
- */
3894
- constructor(keysNodesEntriesOrRaws = [], options) {
3895
- super([], options);
3896
- this._root = this.NIL;
3897
- if (keysNodesEntriesOrRaws) {
3898
- this.addMany(keysNodesEntriesOrRaws);
3899
- }
3900
- }
3901
- _root;
3902
- get root() {
3903
- return this._root;
3904
- }
3905
- /**
3906
- * Time Complexity: O(1)
3907
- * Space Complexity: O(1)
3908
- *
3909
- * The function creates a new Red-Black Tree node with the specified key, value, and color.
3910
- * @param {K} key - The key parameter represents the key value of the node being created. It is of
3911
- * type K, which is a generic type that can be replaced with any specific type when using the
3912
- * function.
3913
- * @param {V} [value] - The `value` parameter is an optional parameter that represents the value
3914
- * associated with the key in the node. It is not required and can be omitted if you only need to
3915
- * create a node with a key.
3916
- * @param {RBTNColor} [color=BLACK] - The "color" parameter is used to specify the color of the node
3917
- * in a Red-Black Tree. It can have two possible values: "RED" or "BLACK". By default, the color is
3918
- * set to "BLACK" if not specified.
3919
- * @returns A new instance of a RedBlackTreeNode with the specified key, value, and color is being
3920
- * returned.
3921
- */
3922
- createNode(key, value, color = "BLACK") {
3923
- return new RedBlackTreeNode(key, this._isMapMode ? void 0 : value, color);
3924
- }
3925
- /**
3926
- * Time Complexity: O(1)
3927
- * Space Complexity: O(1)
3928
- *
3929
- * The function creates a new Red-Black Tree with the specified options.
3930
- * @param [options] - The `options` parameter is an optional object that contains additional
3931
- * configuration options for creating the Red-Black Tree. It has the following properties:
3932
- * @returns a new instance of a RedBlackTree object.
3933
- */
3934
- createTree(options) {
3935
- return new _RedBlackTree([], {
3936
- iterationType: this.iterationType,
3937
- isMapMode: this._isMapMode,
3938
- specifyComparable: this._specifyComparable,
3939
- toEntryFn: this._toEntryFn,
3940
- ...options
3941
- });
3942
- }
3943
- /**
3944
- * Time Complexity: O(1)
3945
- * Space Complexity: O(1)
3946
- *
3947
- * The function checks if the input is an instance of the RedBlackTreeNode class.
3948
- * @param {K | RedBlackTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined} keyNodeOrEntry - The parameter
3949
- * `keyNodeOrEntry` can be of type `R` or `K | RedBlackTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined`.
3950
- * @returns a boolean value indicating whether the input parameter `keyNodeOrEntry` is
3951
- * an instance of the `RedBlackTreeNode` class.
3952
- */
3953
- isNode(keyNodeOrEntry) {
3954
- return keyNodeOrEntry instanceof RedBlackTreeNode;
3955
- }
3956
- /**
3957
- * Time Complexity: O(1)
3958
- * Space Complexity: O(1)
3959
- *
3960
- * The "clear" function sets the root node of a data structure to a sentinel value and resets the
3961
- * size counter to zero.
3962
- */
3963
- clear() {
3964
- super.clear();
3965
- this._root = this.NIL;
3966
- }
3967
- /**
3968
- * Time Complexity: O(log n)
3969
- * Space Complexity: O(log n)
3970
- *
3971
- * The function adds a new node to a binary search tree and returns true if the node was successfully
3972
- * added.
3973
- * @param {K | RedBlackTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined} keyNodeOrEntry - The parameter
3974
- * `keyNodeOrEntry` can accept a value of type `R` or `K | RedBlackTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined`.
3975
- * @param {V} [value] - The `value` parameter is an optional value that you want to associate with
3976
- * the key in the data structure. It represents the value that you want to add or update in the data
3977
- * structure.
3978
- * @returns The method is returning a boolean value. If a new node is successfully added to the tree,
3979
- * the method returns true. If the node already exists and its value is updated, the method also
3980
- * returns true. If the node cannot be added or updated, the method returns false.
3981
- */
3982
- add(keyNodeOrEntry, value) {
3983
- const [newNode, newValue] = this._keyValueNodeOrEntryToNodeAndValue(keyNodeOrEntry, value);
3984
- if (!this.isRealNode(newNode)) return false;
3985
- const insertStatus = this._insert(newNode);
3986
- if (insertStatus === "CREATED") {
3987
- if (this.isRealNode(this._root)) {
3988
- this._root.color = "BLACK";
3989
- } else {
3990
- return false;
3991
- }
3992
- if (this._isMapMode) this._setValue(newNode.key, newValue);
3993
- this._size++;
3994
- return true;
3995
- }
3996
- if (insertStatus === "UPDATED") {
3997
- if (this._isMapMode) this._setValue(newNode.key, newValue);
3998
- return true;
3999
- }
4000
- return false;
4001
- }
4002
- /**
4003
- * Time Complexity: O(log n)
4004
- * Space Complexity: O(log n)
4005
- *
4006
- * The function overrides the delete method in a binary tree data structure to remove a node based on
4007
- * a given predicate and maintain the binary search tree properties.
4008
- * @param {K | RedBlackTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined} keyNodeOrEntry - The `keyNodeOrEntry`
4009
- * parameter in the `override delete` method is used to specify the condition or key based on which a
4010
- * node should be deleted from the binary tree. It can be a key, a node, an entry, or a predicate
4011
- * function that determines which node(s) should be deleted.
4012
- * @returns The `override delete` method is returning an array of `BinaryTreeDeleteResult<RedBlackTreeNode<K, V>>`
4013
- * objects. Each object in the array contains information about the deleted node and whether
4014
- * balancing is needed.
4015
- */
4016
- delete(keyNodeOrEntry) {
4017
- if (keyNodeOrEntry === null) return [];
4018
- const results = [];
4019
- let nodeToDelete;
4020
- if (this._isPredicate(keyNodeOrEntry)) nodeToDelete = this.getNode(keyNodeOrEntry);
4021
- else nodeToDelete = this.isRealNode(keyNodeOrEntry) ? keyNodeOrEntry : this.getNode(keyNodeOrEntry);
4022
- if (!nodeToDelete) {
4023
- return results;
4024
- }
4025
- let originalColor = nodeToDelete.color;
4026
- let replacementNode;
4027
- if (!this.isRealNode(nodeToDelete.left)) {
4028
- if (nodeToDelete.right !== null) {
4029
- replacementNode = nodeToDelete.right;
4030
- this._transplant(nodeToDelete, nodeToDelete.right);
4031
- }
4032
- } else if (!this.isRealNode(nodeToDelete.right)) {
4033
- replacementNode = nodeToDelete.left;
4034
- this._transplant(nodeToDelete, nodeToDelete.left);
4035
- } else {
4036
- const successor = this.getLeftMost((node) => node, nodeToDelete.right);
4037
- if (successor) {
4038
- originalColor = successor.color;
4039
- if (successor.right !== null) replacementNode = successor.right;
4040
- if (successor.parent === nodeToDelete) {
4041
- if (this.isRealNode(replacementNode)) {
4042
- replacementNode.parent = successor;
4043
- }
4044
- } else {
4045
- if (successor.right !== null) {
4046
- this._transplant(successor, successor.right);
4047
- successor.right = nodeToDelete.right;
4048
- }
4049
- if (this.isRealNode(successor.right)) {
4050
- successor.right.parent = successor;
4051
- }
4052
- }
4053
- this._transplant(nodeToDelete, successor);
4054
- successor.left = nodeToDelete.left;
4055
- if (this.isRealNode(successor.left)) {
4056
- successor.left.parent = successor;
4057
- }
4058
- successor.color = nodeToDelete.color;
4059
- }
4060
- }
4061
- if (this._isMapMode) this._store.delete(nodeToDelete.key);
4062
- this._size--;
4063
- if (originalColor === "BLACK") {
4064
- this._deleteFixup(replacementNode);
4065
- }
4066
- results.push({ deleted: nodeToDelete, needBalanced: void 0 });
4067
- return results;
4068
- }
4069
- /**
4070
- * Time Complexity: O(n)
4071
- * Space Complexity: O(n)
4072
- *
4073
- * The `map` function in TypeScript overrides the default behavior to create a new Red-Black Tree by
4074
- * applying a callback to each entry in the original tree.
4075
- * @param callback - A function that will be called for each entry in the tree, with parameters
4076
- * representing the key, value, index, and the tree itself. It should return an entry for the new
4077
- * tree.
4078
- * @param [options] - The `options` parameter in the `map` method is of type `RedBlackTreeOptions<MK, MV,
4079
- * MR>`. This parameter allows you to specify additional options or configurations for the Red-Black
4080
- * Tree that will be created during the mapping process. These options could include things like
4081
- * custom comparators
4082
- * @param {any} [thisArg] - The `thisArg` parameter in the `override map` function is used to specify
4083
- * the value of `this` when executing the `callback` function. It allows you to set the context
4084
- * (value of `this`) for the callback function. This can be useful when you want to access properties
4085
- * or
4086
- * @returns A new Red-Black Tree is being returned, where each entry has been transformed using the
4087
- * provided callback function.
4088
- */
4089
- map(callback, options, thisArg) {
4090
- const newTree = new _RedBlackTree([], options);
4091
- let index = 0;
4092
- for (const [key, value] of this) {
4093
- newTree.add(callback.call(thisArg, key, value, index++, this));
4094
- }
4095
- return newTree;
4096
- }
4097
- /**
4098
- * Time Complexity: O(n)
4099
- * Space Complexity: O(n)
4100
- *
4101
- * The function `clone` overrides the default cloning behavior to create a deep copy of a tree
4102
- * structure.
4103
- * @returns The `cloned` object is being returned.
4104
- */
4105
- clone() {
4106
- const cloned = this.createTree();
4107
- this._clone(cloned);
4108
- return cloned;
4109
- }
4110
- /**
4111
- * Time Complexity: O(1)
4112
- * Space Complexity: O(1)
4113
- *
4114
- * The function sets the root of a tree-like structure and updates the parent property of the new
4115
- * root.
4116
- * @param {RedBlackTreeNode<K, V> | undefined} v - v is a parameter of type RedBlackTreeNode<K, V> or undefined.
4117
- */
4118
- _setRoot(v) {
4119
- if (v) {
4120
- v.parent = void 0;
4121
- }
4122
- this._root = v;
4123
- }
4124
- /**
4125
- * Time Complexity: O(1)
4126
- * Space Complexity: O(1)
4127
- *
4128
- * The function replaces an old node with a new node while preserving the color of the old node.
4129
- * @param {RedBlackTreeNode<K, V>} oldNode - The `oldNode` parameter represents the node that needs to be replaced in
4130
- * the data structure.
4131
- * @param {RedBlackTreeNode<K, V>} newNode - The `newNode` parameter is of type `RedBlackTreeNode<K, V>`, which represents a node in a
4132
- * data structure.
4133
- * @returns The method is returning the result of calling the `_replaceNode` method from the
4134
- * superclass, with the `oldNode` and `newNode` parameters.
4135
- */
4136
- _replaceNode(oldNode, newNode) {
4137
- newNode.color = oldNode.color;
4138
- return super._replaceNode(oldNode, newNode);
4139
- }
4140
- /**
4141
- * Time Complexity: O(log n)
4142
- * Space Complexity: O(log n)
4143
- *
4144
- * The `_insert` function inserts a node into a binary search tree and performs necessary fix-ups to
4145
- * maintain the red-black tree properties.
4146
- * @param {RedBlackTreeNode<K, V>} node - The `node` parameter represents the node that needs to be inserted into the
4147
- * binary search tree.
4148
- * @returns a string value indicating the result of the insertion operation. It can return either
4149
- * 'UPDATED' if the node with the same key already exists and was updated, or 'CREATED' if a new node
4150
- * was created and inserted into the tree.
4151
- */
4152
- _insert(node) {
4153
- let current = this.root;
4154
- let parent = void 0;
4155
- while (this.isRealNode(current)) {
4156
- parent = current;
4157
- const compared = this._compare(node.key, current.key);
4158
- if (compared < 0) {
4159
- current = current.left ?? this.NIL;
4160
- } else if (compared > 0) {
4161
- current = current.right ?? this.NIL;
4162
- } else {
4163
- this._replaceNode(current, node);
4164
- return "UPDATED";
4165
- }
4166
- }
4167
- node.parent = parent;
4168
- if (!parent) {
4169
- this._setRoot(node);
4170
- } else if (this._compare(node.key, parent.key) < 0) {
4171
- parent.left = node;
4172
- } else {
4173
- parent.right = node;
4174
- }
4175
- node.left = this.NIL;
4176
- node.right = this.NIL;
4177
- node.color = "RED";
4178
- this._insertFixup(node);
4179
- return "CREATED";
4180
- }
4181
- /**
4182
- * Time Complexity: O(1)
4183
- * Space Complexity: O(1)
4184
- *
4185
- * The function `_transplant` is used to replace a node `u` with another node `v` in a binary tree.
4186
- * @param {RedBlackTreeNode<K, V>} u - The parameter "u" represents a node in a binary tree.
4187
- * @param {RedBlackTreeNode<K, V> | undefined} v - The parameter `v` is of type `RedBlackTreeNode<K, V> | undefined`, which means it can
4188
- * either be a `RedBlackTreeNode<K, V>` object or `undefined`.
4189
- */
4190
- _transplant(u, v) {
4191
- if (!u.parent) {
4192
- this._setRoot(v);
4193
- } else if (u === u.parent.left) {
4194
- u.parent.left = v;
4195
- } else {
4196
- u.parent.right = v;
4197
- }
4198
- if (v) {
4199
- v.parent = u.parent;
4200
- }
4201
- }
4202
- /**
4203
- * Time Complexity: O(log n)
4204
- * Space Complexity: O(1)
4205
- *
4206
- * The `_insertFixup` function is used to fix the Red-Black Tree after inserting a new node.
4207
- * @param {RedBlackTreeNode<K, V> | undefined} z - The parameter `z` represents a node in the Red-Black Tree data
4208
- * structure. It can either be a valid node or `undefined`.
4209
- */
4210
- _insertFixup(z) {
4211
- while (z?.parent?.color === "RED") {
4212
- if (z.parent === z.parent.parent?.left) {
4213
- const y = z.parent.parent.right;
4214
- if (y?.color === "RED") {
4215
- z.parent.color = "BLACK";
4216
- y.color = "BLACK";
4217
- z.parent.parent.color = "RED";
4218
- z = z.parent.parent;
4219
- } else {
4220
- if (z === z.parent.right) {
4221
- z = z.parent;
4222
- this._leftRotate(z);
4223
- }
4224
- if (z && this.isRealNode(z.parent) && this.isRealNode(z.parent.parent)) {
4225
- z.parent.color = "BLACK";
4226
- z.parent.parent.color = "RED";
4227
- this._rightRotate(z.parent.parent);
4228
- }
4229
- }
4230
- } else {
4231
- const y = z?.parent?.parent?.left ?? void 0;
4232
- if (y?.color === "RED") {
4233
- z.parent.color = "BLACK";
4234
- y.color = "BLACK";
4235
- z.parent.parent.color = "RED";
4236
- z = z.parent.parent;
4237
- } else {
4238
- if (z === z.parent.left) {
4239
- z = z.parent;
4240
- this._rightRotate(z);
4241
- }
4242
- if (z && this.isRealNode(z.parent) && this.isRealNode(z.parent.parent)) {
4243
- z.parent.color = "BLACK";
4244
- z.parent.parent.color = "RED";
4245
- this._leftRotate(z.parent.parent);
4246
- }
4247
- }
4248
- }
4249
- }
4250
- if (this.isRealNode(this._root)) this._root.color = "BLACK";
4251
- }
4252
- /**
4253
- * Time Complexity: O(log n)
4254
- * Space Complexity: O(1)
4255
- *
4256
- * The `_deleteFixup` function is used to fix the red-black tree after a node deletion by adjusting
4257
- * the colors and performing rotations.
4258
- * @param {RedBlackTreeNode<K, V> | undefined} node - The `node` parameter represents a node in a binary tree. It can
4259
- * be either a valid node object or `undefined`.
4260
- * @returns The function does not return any value. It has a return type of `void`, which means it
4261
- * does not return anything.
4262
- */
4263
- _deleteFixup(node) {
4264
- if (!node || node === this.root || node.color === "BLACK") {
4265
- if (node) {
4266
- node.color = "BLACK";
4267
- }
4268
- return;
4269
- }
4270
- while (node && node !== this.root && node.color === "BLACK") {
4271
- const parent = node.parent;
4272
- if (!parent) {
4273
- break;
4274
- }
4275
- if (node === parent.left) {
4276
- let sibling = parent.right;
4277
- if (sibling?.color === "RED") {
4278
- sibling.color = "BLACK";
4279
- parent.color = "RED";
4280
- this._leftRotate(parent);
4281
- sibling = parent.right;
4282
- }
4283
- if ((sibling?.left?.color ?? "BLACK") === "BLACK") {
4284
- if (sibling) sibling.color = "RED";
4285
- node = parent;
4286
- } else {
4287
- if (sibling?.left) sibling.left.color = "BLACK";
4288
- if (sibling) sibling.color = parent.color;
4289
- parent.color = "BLACK";
4290
- this._rightRotate(parent);
4291
- node = this.root;
4292
- }
4293
- } else {
4294
- let sibling = parent.left;
4295
- if (sibling?.color === "RED") {
4296
- sibling.color = "BLACK";
4297
- if (parent) parent.color = "RED";
4298
- this._rightRotate(parent);
4299
- if (parent) sibling = parent.left;
4300
- }
4301
- if ((sibling?.right?.color ?? "BLACK") === "BLACK") {
4302
- if (sibling) sibling.color = "RED";
4303
- node = parent;
4304
- } else {
4305
- if (sibling?.right) sibling.right.color = "BLACK";
4306
- if (sibling) sibling.color = parent.color;
4307
- if (parent) parent.color = "BLACK";
4308
- this._leftRotate(parent);
4309
- node = this.root;
4310
- }
4311
- }
4312
- }
4313
- if (node) {
4314
- node.color = "BLACK";
4315
- }
4316
- }
4317
- /**
4318
- * Time Complexity: O(1)
4319
- * Space Complexity: O(1)
4320
- *
4321
- * The `_leftRotate` function performs a left rotation on a given node in a binary tree.
4322
- * @param {RedBlackTreeNode<K, V> | undefined} x - The parameter `x` is of type `RedBlackTreeNode<K, V> | undefined`. It represents a
4323
- * node in a binary tree or `undefined` if there is no node.
4324
- * @returns void, which means it does not return any value.
4325
- */
4326
- _leftRotate(x) {
4327
- if (!x || !x.right) {
4328
- return;
4329
- }
4330
- const y = x.right;
4331
- x.right = y.left;
4332
- if (this.isRealNode(y.left)) {
4333
- y.left.parent = x;
4334
- }
4335
- y.parent = x.parent;
4336
- if (!x.parent) {
4337
- this._setRoot(y);
4338
- } else if (x === x.parent.left) {
4339
- x.parent.left = y;
4340
- } else {
4341
- x.parent.right = y;
4342
- }
4343
- y.left = x;
4344
- x.parent = y;
4345
- }
4346
- /**
4347
- * Time Complexity: O(1)
4348
- * Space Complexity: O(1)
4349
- *
4350
- * The `_rightRotate` function performs a right rotation on a given node in a binary tree.
4351
- * @param {RedBlackTreeNode<K, V> | undefined} y - The parameter `y` is of type `RedBlackTreeNode<K, V> | undefined`. It represents a
4352
- * node in a binary tree or `undefined` if there is no node.
4353
- * @returns void, which means it does not return any value.
4354
- */
4355
- _rightRotate(y) {
4356
- if (!y || !y.left) {
4357
- return;
4358
- }
4359
- const x = y.left;
4360
- y.left = x.right;
4361
- if (this.isRealNode(x.right)) {
4362
- x.right.parent = y;
4363
- }
4364
- x.parent = y.parent;
4365
- if (!y.parent) {
4366
- this._setRoot(x);
4367
- } else if (y === y.parent.left) {
4368
- y.parent.left = x;
4369
- } else {
4370
- y.parent.right = x;
4371
- }
4372
- x.right = y;
4373
- y.parent = x;
4374
- }
4375
- };
4376
-
4377
- // src/data-structures/binary-tree/tree-multi-map.ts
4378
- var TreeMultiMapNode = class extends RedBlackTreeNode {
4379
- parent = void 0;
4380
- /**
4381
- * This TypeScript constructor initializes an object with a key of type K and an array of values of
4382
- * type V.
4383
- * @param {K} key - The `key` parameter is typically used to store a unique identifier or key for the
4384
- * data being stored in the data structure. It helps in quickly accessing or retrieving the
4385
- * associated value in the data structure.
4386
- * @param {V[]} value - The `value` parameter in the constructor represents an array of values of
4387
- * type `V`.
4388
- */
4389
- constructor(key, value) {
4390
- super(key, value);
4391
- }
4392
- _left = void 0;
4393
- get left() {
4394
- return this._left;
4395
- }
4396
- set left(v) {
4397
- if (v) {
4398
- v.parent = this;
4399
- }
4400
- this._left = v;
4401
- }
4402
- _right = void 0;
4403
- get right() {
4404
- return this._right;
4405
- }
4406
- set right(v) {
4407
- if (v) {
4408
- v.parent = this;
4409
- }
4410
- this._right = v;
4411
- }
4412
- };
4413
- var TreeMultiMap = class _TreeMultiMap extends RedBlackTree {
4414
- /**
4415
- * The constructor initializes an TreeMultiMap with the provided keys, nodes, entries, or raw data
4416
- * and options.
4417
- * @param keysNodesEntriesOrRaws - The `keysNodesEntriesOrRaws` parameter in the constructor is an
4418
- * iterable that can contain either key-value pairs represented as `BTNRep<K, V[],
4419
- * TreeMultiMapNode<K, V>>` or raw data represented as `R`. This parameter is used to initialize
4420
- * the RedBlackTreeMulti
4421
- * @param [options] - The `options` parameter in the constructor is of type
4422
- * `TreeMultiMapOptions<K, V[], R>`. It is an optional parameter that allows you to specify
4423
- * additional options for configuring the TreeMultiMap instance.
4424
- */
4425
- constructor(keysNodesEntriesOrRaws = [], options) {
4426
- super([], { ...options });
4427
- if (keysNodesEntriesOrRaws) {
4428
- this.addMany(keysNodesEntriesOrRaws);
4429
- }
4430
- }
4431
- /**
4432
- * Time Complexity: O(1)
4433
- * Space Complexity: O(1)
4434
- *
4435
- * The `createTree` function in TypeScript overrides the default implementation to create a new
4436
- * TreeMultiMap with specified options.
4437
- * @param [options] - The `options` parameter in the `createTree` method is of type
4438
- * `TreeMultiMapOptions<K, V[], R>`. This parameter allows you to pass additional configuration
4439
- * options when creating a new `TreeMultiMap` instance. It includes properties such as
4440
- * `iterationType`, `specifyComparable
4441
- * @returns A new instance of `TreeMultiMap` is being returned, with an empty array as the initial
4442
- * data and the provided options merged with the existing properties of the current object.
4443
- */
4444
- createTree(options) {
4445
- return new _TreeMultiMap([], {
4446
- iterationType: this.iterationType,
4447
- specifyComparable: this._specifyComparable,
4448
- toEntryFn: this._toEntryFn,
4449
- isReverse: this._isReverse,
4450
- isMapMode: this._isMapMode,
4451
- ...options
4452
- });
4453
- }
4454
- /**
4455
- * Time Complexity: O(1)
4456
- * Space Complexity: O(1)
4457
- *
4458
- * The function `createNode` overrides the creation of a new TreeMultiMapNode with a specified key
4459
- * and value array.
4460
- * @param {K} key - The `key` parameter represents the key of the node being created in the
4461
- * `TreeMultiMap`.
4462
- * @param {V[]} value - The `value` parameter in the `createNode` method represents an array of
4463
- * values associated with a specific key in the TreeMultiMap data structure.
4464
- * @returns A new instance of `TreeMultiMapNode<K, V>` is being returned with the specified key and
4465
- * value. If `_isMapMode` is true, an empty array is passed as the value, otherwise the provided
4466
- * value is used.
4467
- */
4468
- createNode(key, value = []) {
4469
- return new TreeMultiMapNode(key, this._isMapMode ? [] : value);
4470
- }
4471
- /**
4472
- * Time Complexity: O(log n)
4473
- * Space Complexity: O(log n)
4474
- *
4475
- * The function overrides the add method to handle different types of input for a TreeMultiMap data
4476
- * structure.
4477
- * @param [key] - The `key` parameter in the `override add` method represents the key of the entry to
4478
- * be added to the TreeMultiMap. It can be of type `K`, which is the key type of the TreeMultiMap, or
4479
- * it can be a TreeMultiMapNode containing the key and its
4480
- * @param {V[]} [values] - The `values` parameter in the `add` method represents an array of values
4481
- * that you want to add to the TreeMultiMap. It can contain one or more values of type `V`.
4482
- * @returns The `add` method is returning a boolean value, which indicates whether the operation was
4483
- * successful or not.
4484
- */
4485
- add(keyNodeOrEntry, value) {
4486
- if (this.isRealNode(keyNodeOrEntry)) return super.add(keyNodeOrEntry);
4487
- const _commonAdd = (key, values) => {
4488
- if (key === void 0 || key === null) return false;
4489
- const _addToValues = () => {
4490
- const existingValues = this.get(key);
4491
- if (existingValues !== void 0 && values !== void 0) {
4492
- for (const value2 of values) existingValues.push(value2);
4493
- return true;
4494
- }
4495
- return false;
4496
- };
4497
- const _addByNode = () => {
4498
- const existingNode = this.getNode(key);
4499
- if (this.isRealNode(existingNode)) {
4500
- const existingValues = this.get(existingNode);
4501
- if (existingValues === void 0) {
4502
- super.add(key, values);
4503
- return true;
4504
- }
4505
- if (values !== void 0) {
4506
- for (const value2 of values) existingValues.push(value2);
4507
- return true;
4508
- } else {
4509
- return false;
4510
- }
4511
- } else {
4512
- return super.add(key, values);
4513
- }
4514
- };
4515
- if (this._isMapMode) {
4516
- return _addByNode() || _addToValues();
4517
- }
4518
- return _addToValues() || _addByNode();
4519
- };
4520
- if (this.isEntry(keyNodeOrEntry)) {
4521
- const [key, values] = keyNodeOrEntry;
4522
- return _commonAdd(key, value !== void 0 ? [value] : values);
4523
- }
4524
- return _commonAdd(keyNodeOrEntry, value !== void 0 ? [value] : void 0);
4525
- }
4526
- /**
4527
- * Time Complexity: O(log n)
4528
- * Space Complexity: O(log n)
4529
- *
4530
- * The function `deleteValue` removes a specific value from a key in a TreeMultiMap data structure
4531
- * and deletes the entire node if no values are left for that key.
4532
- * @param {K | TreeMultiMapNode<K, V> | [K | null | undefined, V[] | undefined] | null | undefined} keyNodeOrEntry - The `keyNodeOrEntry`
4533
- * parameter in the `deleteValue` function can be either a `BTNRep` object containing a key and an
4534
- * array of values, or just a key itself.
4535
- * @param {V} value - The `value` parameter in the `deleteValue` function represents the specific
4536
- * value that you want to remove from the multi-map data structure associated with a particular key.
4537
- * The function checks if the value exists in the array of values associated with the key, and if
4538
- * found, removes it from the array.
4539
- * @returns The `deleteValue` function returns a boolean value - `true` if the specified `value` was
4540
- * successfully deleted from the values associated with the `keyNodeOrEntry`, and `false` otherwise.
4541
- */
4542
- deleteValue(keyNodeOrEntry, value) {
4543
- const values = this.get(keyNodeOrEntry);
4544
- if (Array.isArray(values)) {
4545
- const index = values.indexOf(value);
4546
- if (index === -1) return false;
4547
- values.splice(index, 1);
4548
- if (values.length === 0) this.delete(keyNodeOrEntry);
4549
- return true;
4550
- }
4551
- return false;
4552
- }
4553
- /**
4554
- * Time Complexity: O(n)
4555
- * Space Complexity: O(n)
4556
- *
4557
- * The function `clone` overrides the default cloning behavior to create a deep copy of a tree
4558
- * structure.
4559
- * @returns The `cloned` object is being returned.
4560
- */
4561
- clone() {
4562
- const cloned = this.createTree();
4563
- this._clone(cloned);
4564
- return cloned;
4565
- }
4566
- };
4567
- export {
4568
- TreeMultiMap,
4569
- TreeMultiMapNode
4570
- };
4571
- /**
4572
- * data-structure-typed
4573
- *
4574
- * @author Pablo Zeng
4575
- * @copyright Copyright (c) 2022 Pablo Zeng <zrwusa@gmail.com>
4576
- * @license MIT License
4577
- */
4578
- /**
4579
- * @license MIT
4580
- * @copyright Pablo Zeng <zrwusa@gmail.com>
4581
- * @class
4582
- */