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.
- package/CHANGELOG.md +1 -1
- package/package.json +1 -1
- package/src/data-structures/queue/queue.ts +1 -1
- package/test/unit/data-structures/queue/queue.test.ts +1 -1
- package/test/unit/utils/utils.test.ts +3 -2
- package/dist/individuals/binary-tree/avl-tree-counter.mjs +0 -4701
- package/dist/individuals/binary-tree/avl-tree-multi-map.mjs +0 -4514
- package/dist/individuals/binary-tree/avl-tree.mjs +0 -4321
- package/dist/individuals/binary-tree/binary-tree.mjs +0 -3097
- package/dist/individuals/binary-tree/bst.mjs +0 -3858
- package/dist/individuals/binary-tree/red-black-tree.mjs +0 -4391
- package/dist/individuals/binary-tree/tree-counter.mjs +0 -4806
- package/dist/individuals/binary-tree/tree-multi-map.mjs +0 -4582
- package/dist/individuals/graph/directed-graph.mjs +0 -2910
- package/dist/individuals/graph/undirected-graph.mjs +0 -2745
- package/dist/individuals/hash/hash-map.mjs +0 -1040
- package/dist/individuals/heap/heap.mjs +0 -909
- package/dist/individuals/heap/max-heap.mjs +0 -671
- package/dist/individuals/heap/min-heap.mjs +0 -659
- package/dist/individuals/linked-list/doubly-linked-list.mjs +0 -1495
- package/dist/individuals/linked-list/singly-linked-list.mjs +0 -1479
- package/dist/individuals/priority-queue/max-priority-queue.mjs +0 -768
- package/dist/individuals/priority-queue/min-priority-queue.mjs +0 -757
- package/dist/individuals/priority-queue/priority-queue.mjs +0 -670
- package/dist/individuals/queue/deque.mjs +0 -1262
- package/dist/individuals/queue/queue.mjs +0 -1865
- package/dist/individuals/stack/stack.mjs +0 -415
- package/dist/individuals/trie/trie.mjs +0 -687
|
@@ -1,4514 +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/avl-tree.ts
|
|
3845
|
-
var AVLTreeNode = class extends BSTNode {
|
|
3846
|
-
parent = void 0;
|
|
3847
|
-
/**
|
|
3848
|
-
* This TypeScript constructor function initializes an instance with a key and an optional value.
|
|
3849
|
-
* @param {K} key - The `key` parameter is typically used to uniquely identify an object or element
|
|
3850
|
-
* within a data structure. It serves as a reference or identifier for accessing or manipulating the
|
|
3851
|
-
* associated value or data.
|
|
3852
|
-
* @param {V} [value] - The `value` parameter in the constructor is optional, meaning it does not
|
|
3853
|
-
* have to be provided when creating an instance of the class. If a value is not provided, it will
|
|
3854
|
-
* default to `undefined`.
|
|
3855
|
-
*/
|
|
3856
|
-
constructor(key, value) {
|
|
3857
|
-
super(key, value);
|
|
3858
|
-
}
|
|
3859
|
-
_left = void 0;
|
|
3860
|
-
get left() {
|
|
3861
|
-
return this._left;
|
|
3862
|
-
}
|
|
3863
|
-
set left(v) {
|
|
3864
|
-
if (v) {
|
|
3865
|
-
v.parent = this;
|
|
3866
|
-
}
|
|
3867
|
-
this._left = v;
|
|
3868
|
-
}
|
|
3869
|
-
_right = void 0;
|
|
3870
|
-
get right() {
|
|
3871
|
-
return this._right;
|
|
3872
|
-
}
|
|
3873
|
-
set right(v) {
|
|
3874
|
-
if (v) {
|
|
3875
|
-
v.parent = this;
|
|
3876
|
-
}
|
|
3877
|
-
this._right = v;
|
|
3878
|
-
}
|
|
3879
|
-
};
|
|
3880
|
-
var AVLTree = class _AVLTree extends BST {
|
|
3881
|
-
/**
|
|
3882
|
-
* This TypeScript constructor initializes an AVLTree with keys, nodes, entries, or raw data provided
|
|
3883
|
-
* in an iterable format.
|
|
3884
|
-
* @param keysNodesEntriesOrRaws - The `keysNodesEntriesOrRaws` parameter in the constructor is an
|
|
3885
|
-
* iterable that can contain either `
|
|
3886
|
-
K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined ` objects or `R` objects. It is
|
|
3887
|
-
* used to initialize the AVLTree with key-value pairs or raw data entries. If provided
|
|
3888
|
-
* @param [options] - The `options` parameter in the constructor is of type `AVLTreeOptions<K, V,
|
|
3889
|
-
* R>`. It is an optional parameter that allows you to specify additional options for configuring the
|
|
3890
|
-
* AVL tree. These options could include things like custom comparators, initial capacity, or any
|
|
3891
|
-
* other configuration settings specific
|
|
3892
|
-
*/
|
|
3893
|
-
constructor(keysNodesEntriesOrRaws = [], options) {
|
|
3894
|
-
super([], options);
|
|
3895
|
-
if (keysNodesEntriesOrRaws) super.addMany(keysNodesEntriesOrRaws);
|
|
3896
|
-
}
|
|
3897
|
-
/**
|
|
3898
|
-
* Time Complexity: O(1)
|
|
3899
|
-
* Space Complexity: O(1)
|
|
3900
|
-
*
|
|
3901
|
-
* The function creates a new AVL tree node with the given key and value.
|
|
3902
|
-
* @param {K} key - The key parameter is of type K, which represents the key of the node being
|
|
3903
|
-
* created.
|
|
3904
|
-
* @param {V} [value] - The "value" parameter is an optional parameter of type V. It represents the
|
|
3905
|
-
* value associated with the key in the node being created.
|
|
3906
|
-
* @returns The method is returning a new instance of the AVLTreeNode class, casted as the generic
|
|
3907
|
-
* type AVLTreeNode<K, V>.
|
|
3908
|
-
*/
|
|
3909
|
-
createNode(key, value) {
|
|
3910
|
-
return new AVLTreeNode(key, this._isMapMode ? void 0 : value);
|
|
3911
|
-
}
|
|
3912
|
-
/**
|
|
3913
|
-
* Time Complexity: O(1)
|
|
3914
|
-
* Space Complexity: O(1)
|
|
3915
|
-
*
|
|
3916
|
-
* The function creates a new AVL tree with the specified options and returns it.
|
|
3917
|
-
* @param {AVLTreeOptions} [options] - The `options` parameter is an optional object that can be
|
|
3918
|
-
* passed to the `createTree` function. It is used to customize the behavior of the AVL tree that is
|
|
3919
|
-
* being created.
|
|
3920
|
-
* @returns a new AVLTree object.
|
|
3921
|
-
*/
|
|
3922
|
-
createTree(options) {
|
|
3923
|
-
return new _AVLTree([], {
|
|
3924
|
-
iterationType: this.iterationType,
|
|
3925
|
-
isMapMode: this._isMapMode,
|
|
3926
|
-
specifyComparable: this._specifyComparable,
|
|
3927
|
-
toEntryFn: this._toEntryFn,
|
|
3928
|
-
isReverse: this._isReverse,
|
|
3929
|
-
...options
|
|
3930
|
-
});
|
|
3931
|
-
}
|
|
3932
|
-
/**
|
|
3933
|
-
* Time Complexity: O(1)
|
|
3934
|
-
* Space Complexity: O(1)
|
|
3935
|
-
*
|
|
3936
|
-
* The function checks if the input is an instance of AVLTreeNode.
|
|
3937
|
-
* @param {K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The parameter
|
|
3938
|
-
* `keyNodeOrEntry` can be of type `R` or `
|
|
3939
|
-
K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined `.
|
|
3940
|
-
* @returns a boolean value indicating whether the input parameter `keyNodeOrEntry` is
|
|
3941
|
-
* an instance of the `AVLTreeNode` class.
|
|
3942
|
-
*/
|
|
3943
|
-
isNode(keyNodeOrEntry) {
|
|
3944
|
-
return keyNodeOrEntry instanceof AVLTreeNode;
|
|
3945
|
-
}
|
|
3946
|
-
/**
|
|
3947
|
-
* Time Complexity: O(log n)
|
|
3948
|
-
* Space Complexity: O(log n)
|
|
3949
|
-
*
|
|
3950
|
-
* The function overrides the add method of a class and inserts a key-value pair into a data
|
|
3951
|
-
* structure, then balances the path.
|
|
3952
|
-
* @param { K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The parameter
|
|
3953
|
-
* `keyNodeOrEntry` can accept values of type `R`, `
|
|
3954
|
-
K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined `
|
|
3955
|
-
* @param {V} [value] - The `value` parameter is an optional value that you want to associate with
|
|
3956
|
-
* the key or node being added to the data structure.
|
|
3957
|
-
* @returns The method is returning a boolean value.
|
|
3958
|
-
*/
|
|
3959
|
-
add(keyNodeOrEntry, value) {
|
|
3960
|
-
if (keyNodeOrEntry === null) return false;
|
|
3961
|
-
const inserted = super.add(keyNodeOrEntry, value);
|
|
3962
|
-
if (inserted) this._balancePath(keyNodeOrEntry);
|
|
3963
|
-
return inserted;
|
|
3964
|
-
}
|
|
3965
|
-
/**
|
|
3966
|
-
* Time Complexity: O(log n)
|
|
3967
|
-
* Space Complexity: O(log n)
|
|
3968
|
-
*
|
|
3969
|
-
* The function overrides the delete method in a TypeScript class, performs deletion, and then
|
|
3970
|
-
* balances the tree if necessary.
|
|
3971
|
-
* @param { K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The `keyNodeOrEntry`
|
|
3972
|
-
* parameter in the `override delete` method can be one of the following types:
|
|
3973
|
-
* @returns The `delete` method is being overridden in this code snippet. It first calls the `delete`
|
|
3974
|
-
* method from the superclass (presumably a parent class) with the provided `predicate`, which could
|
|
3975
|
-
* be a key, node, entry, or a custom predicate. The result of this deletion operation is stored in
|
|
3976
|
-
* `deletedResults`, which is an array of `BinaryTreeDeleteResult` objects.
|
|
3977
|
-
*/
|
|
3978
|
-
delete(keyNodeOrEntry) {
|
|
3979
|
-
const deletedResults = super.delete(keyNodeOrEntry);
|
|
3980
|
-
for (const { needBalanced } of deletedResults) {
|
|
3981
|
-
if (needBalanced) {
|
|
3982
|
-
this._balancePath(needBalanced);
|
|
3983
|
-
}
|
|
3984
|
-
}
|
|
3985
|
-
return deletedResults;
|
|
3986
|
-
}
|
|
3987
|
-
/**
|
|
3988
|
-
* Time Complexity: O(n)
|
|
3989
|
-
* Space Complexity: O(n)
|
|
3990
|
-
*
|
|
3991
|
-
* The `map` function in TypeScript overrides the default map behavior of an AVLTree data structure
|
|
3992
|
-
* by applying a callback function to each entry and creating a new AVLTree with the results.
|
|
3993
|
-
* @param callback - A function that will be called for each entry in the AVLTree. It takes four
|
|
3994
|
-
* arguments: the key, the value (which can be undefined), the index of the entry, and a reference to
|
|
3995
|
-
* the AVLTree itself.
|
|
3996
|
-
* @param [options] - The `options` parameter in the `override map` function is of type
|
|
3997
|
-
* `AVLTreeOptions<MK, MV, MR>`. It is an optional parameter that allows you to specify additional
|
|
3998
|
-
* options for the AVL tree being created during the mapping process. These options could include
|
|
3999
|
-
* custom comparators, initial
|
|
4000
|
-
* @param {any} [thisArg] - The `thisArg` parameter in the `override map` function is used to specify
|
|
4001
|
-
* the value of `this` when executing the `callback` function. It allows you to set the context
|
|
4002
|
-
* (value of `this`) within the callback function. This can be useful when you want to access
|
|
4003
|
-
* properties or
|
|
4004
|
-
* @returns The `map` method is returning a new AVLTree instance (`newTree`) with the entries
|
|
4005
|
-
* modified by the provided callback function.
|
|
4006
|
-
*/
|
|
4007
|
-
map(callback, options, thisArg) {
|
|
4008
|
-
const newTree = new _AVLTree([], options);
|
|
4009
|
-
let index = 0;
|
|
4010
|
-
for (const [key, value] of this) {
|
|
4011
|
-
newTree.add(callback.call(thisArg, key, value, index++, this));
|
|
4012
|
-
}
|
|
4013
|
-
return newTree;
|
|
4014
|
-
}
|
|
4015
|
-
/**
|
|
4016
|
-
* Time Complexity: O(n)
|
|
4017
|
-
* Space Complexity: O(n)
|
|
4018
|
-
*
|
|
4019
|
-
* The function `clone` overrides the default cloning behavior to create a deep copy of a tree
|
|
4020
|
-
* structure.
|
|
4021
|
-
* @returns A cloned tree object is being returned.
|
|
4022
|
-
*/
|
|
4023
|
-
clone() {
|
|
4024
|
-
const cloned = this.createTree();
|
|
4025
|
-
this._clone(cloned);
|
|
4026
|
-
return cloned;
|
|
4027
|
-
}
|
|
4028
|
-
/**
|
|
4029
|
-
* Time Complexity: O(1)
|
|
4030
|
-
* Space Complexity: O(1)
|
|
4031
|
-
*
|
|
4032
|
-
* The `_swapProperties` function swaps the key, value, and height properties between two nodes in a
|
|
4033
|
-
* binary search tree.
|
|
4034
|
-
* @param {BSTNOptKeyOrNode<K, AVLTreeNode<K, V>>} srcNode - The `srcNode` parameter represents either a node
|
|
4035
|
-
* object (`AVLTreeNode<K, V>`) or a key-value pair (`R`) that is being swapped with another node.
|
|
4036
|
-
* @param {BSTNOptKeyOrNode<K, AVLTreeNode<K, V>>} destNode - The `destNode` parameter is either an instance of
|
|
4037
|
-
* `R` or an instance of `BSTNOptKeyOrNode<K, AVLTreeNode<K, V>>`.
|
|
4038
|
-
* @returns The method is returning the `destNodeEnsured` object if both `srcNodeEnsured` and
|
|
4039
|
-
* `destNodeEnsured` are truthy. Otherwise, it returns `undefined`.
|
|
4040
|
-
*/
|
|
4041
|
-
_swapProperties(srcNode, destNode) {
|
|
4042
|
-
const srcNodeEnsured = this.ensureNode(srcNode);
|
|
4043
|
-
const destNodeEnsured = this.ensureNode(destNode);
|
|
4044
|
-
if (srcNodeEnsured && destNodeEnsured) {
|
|
4045
|
-
const { key, value, height } = destNodeEnsured;
|
|
4046
|
-
const tempNode = this.createNode(key, value);
|
|
4047
|
-
if (tempNode) {
|
|
4048
|
-
tempNode.height = height;
|
|
4049
|
-
destNodeEnsured.key = srcNodeEnsured.key;
|
|
4050
|
-
if (!this._isMapMode) destNodeEnsured.value = srcNodeEnsured.value;
|
|
4051
|
-
destNodeEnsured.height = srcNodeEnsured.height;
|
|
4052
|
-
srcNodeEnsured.key = tempNode.key;
|
|
4053
|
-
if (!this._isMapMode) srcNodeEnsured.value = tempNode.value;
|
|
4054
|
-
srcNodeEnsured.height = tempNode.height;
|
|
4055
|
-
}
|
|
4056
|
-
return destNodeEnsured;
|
|
4057
|
-
}
|
|
4058
|
-
return void 0;
|
|
4059
|
-
}
|
|
4060
|
-
/**
|
|
4061
|
-
* Time Complexity: O(1)
|
|
4062
|
-
* Space Complexity: O(1)
|
|
4063
|
-
*
|
|
4064
|
-
* The function calculates the balance factor of a node in a binary tree.
|
|
4065
|
-
* @param {AVLTreeNode<K, V>} node - The parameter "node" is of type "AVLTreeNode<K, V>", which likely represents a node in a
|
|
4066
|
-
* binary tree data structure.
|
|
4067
|
-
* @returns the balance factor of a given node. The balance factor is calculated by subtracting the
|
|
4068
|
-
* height of the left subtree from the height of the right subtree.
|
|
4069
|
-
*/
|
|
4070
|
-
_balanceFactor(node) {
|
|
4071
|
-
if (!node.right)
|
|
4072
|
-
return -node.height;
|
|
4073
|
-
else if (!node.left)
|
|
4074
|
-
return +node.height;
|
|
4075
|
-
else return node.right.height - node.left.height;
|
|
4076
|
-
}
|
|
4077
|
-
/**
|
|
4078
|
-
* Time Complexity: O(1)
|
|
4079
|
-
* Space Complexity: O(1)
|
|
4080
|
-
*
|
|
4081
|
-
* The function updates the height of a node in a binary tree based on the heights of its left and
|
|
4082
|
-
* right children.
|
|
4083
|
-
* @param {AVLTreeNode<K, V>} node - The parameter "node" represents a node in a binary tree data structure.
|
|
4084
|
-
*/
|
|
4085
|
-
_updateHeight(node) {
|
|
4086
|
-
if (!node.left && !node.right) node.height = 0;
|
|
4087
|
-
else if (!node.left) {
|
|
4088
|
-
const rightHeight = node.right ? node.right.height : 0;
|
|
4089
|
-
node.height = 1 + rightHeight;
|
|
4090
|
-
} else if (!node.right) node.height = 1 + node.left.height;
|
|
4091
|
-
else node.height = 1 + Math.max(node.right.height, node.left.height);
|
|
4092
|
-
}
|
|
4093
|
-
/**
|
|
4094
|
-
* Time Complexity: O(1)
|
|
4095
|
-
* Space Complexity: O(1)
|
|
4096
|
-
*
|
|
4097
|
-
* The `_balanceLL` function performs a left-left rotation to balance a binary search tree.
|
|
4098
|
-
* @param {AVLTreeNode<K, V>} A - A is a node in a binary tree.
|
|
4099
|
-
*/
|
|
4100
|
-
_balanceLL(A) {
|
|
4101
|
-
const parentOfA = A.parent;
|
|
4102
|
-
const B = A.left;
|
|
4103
|
-
if (B !== null) A.parent = B;
|
|
4104
|
-
if (B && B.right) {
|
|
4105
|
-
B.right.parent = A;
|
|
4106
|
-
}
|
|
4107
|
-
if (B) B.parent = parentOfA;
|
|
4108
|
-
if (A === this.root) {
|
|
4109
|
-
if (B) this._setRoot(B);
|
|
4110
|
-
} else {
|
|
4111
|
-
if (parentOfA?.left === A) {
|
|
4112
|
-
parentOfA.left = B;
|
|
4113
|
-
} else {
|
|
4114
|
-
if (parentOfA) parentOfA.right = B;
|
|
4115
|
-
}
|
|
4116
|
-
}
|
|
4117
|
-
if (B) {
|
|
4118
|
-
A.left = B.right;
|
|
4119
|
-
B.right = A;
|
|
4120
|
-
}
|
|
4121
|
-
this._updateHeight(A);
|
|
4122
|
-
if (B) this._updateHeight(B);
|
|
4123
|
-
}
|
|
4124
|
-
/**
|
|
4125
|
-
* Time Complexity: O(1)
|
|
4126
|
-
* Space Complexity: O(1)
|
|
4127
|
-
*
|
|
4128
|
-
* The `_balanceLR` function performs a left-right rotation to balance a binary tree.
|
|
4129
|
-
* @param {AVLTreeNode<K, V>} A - A is a node in a binary tree.
|
|
4130
|
-
*/
|
|
4131
|
-
_balanceLR(A) {
|
|
4132
|
-
const parentOfA = A.parent;
|
|
4133
|
-
const B = A.left;
|
|
4134
|
-
let C = void 0;
|
|
4135
|
-
if (B) {
|
|
4136
|
-
C = B.right;
|
|
4137
|
-
}
|
|
4138
|
-
if (A && C !== null) A.parent = C;
|
|
4139
|
-
if (B && C !== null) B.parent = C;
|
|
4140
|
-
if (C) {
|
|
4141
|
-
if (C.left) {
|
|
4142
|
-
if (B !== null) C.left.parent = B;
|
|
4143
|
-
}
|
|
4144
|
-
if (C.right) {
|
|
4145
|
-
C.right.parent = A;
|
|
4146
|
-
}
|
|
4147
|
-
C.parent = parentOfA;
|
|
4148
|
-
}
|
|
4149
|
-
if (A === this.root) {
|
|
4150
|
-
if (C) this._setRoot(C);
|
|
4151
|
-
} else {
|
|
4152
|
-
if (parentOfA) {
|
|
4153
|
-
if (parentOfA.left === A) {
|
|
4154
|
-
parentOfA.left = C;
|
|
4155
|
-
} else {
|
|
4156
|
-
parentOfA.right = C;
|
|
4157
|
-
}
|
|
4158
|
-
}
|
|
4159
|
-
}
|
|
4160
|
-
if (C) {
|
|
4161
|
-
A.left = C.right;
|
|
4162
|
-
if (B) B.right = C.left;
|
|
4163
|
-
C.left = B;
|
|
4164
|
-
C.right = A;
|
|
4165
|
-
}
|
|
4166
|
-
this._updateHeight(A);
|
|
4167
|
-
if (B) this._updateHeight(B);
|
|
4168
|
-
if (C) this._updateHeight(C);
|
|
4169
|
-
}
|
|
4170
|
-
/**
|
|
4171
|
-
* Time Complexity: O(1)
|
|
4172
|
-
* Space Complexity: O(1)
|
|
4173
|
-
*
|
|
4174
|
-
* The function `_balanceRR` performs a right-right rotation to balance a binary tree.
|
|
4175
|
-
* @param {AVLTreeNode<K, V>} A - A is a node in a binary tree.
|
|
4176
|
-
*/
|
|
4177
|
-
_balanceRR(A) {
|
|
4178
|
-
const parentOfA = A.parent;
|
|
4179
|
-
const B = A.right;
|
|
4180
|
-
if (B !== null) A.parent = B;
|
|
4181
|
-
if (B) {
|
|
4182
|
-
if (B.left) {
|
|
4183
|
-
B.left.parent = A;
|
|
4184
|
-
}
|
|
4185
|
-
B.parent = parentOfA;
|
|
4186
|
-
}
|
|
4187
|
-
if (A === this.root) {
|
|
4188
|
-
if (B) this._setRoot(B);
|
|
4189
|
-
} else {
|
|
4190
|
-
if (parentOfA) {
|
|
4191
|
-
if (parentOfA.left === A) {
|
|
4192
|
-
parentOfA.left = B;
|
|
4193
|
-
} else {
|
|
4194
|
-
parentOfA.right = B;
|
|
4195
|
-
}
|
|
4196
|
-
}
|
|
4197
|
-
}
|
|
4198
|
-
if (B) {
|
|
4199
|
-
A.right = B.left;
|
|
4200
|
-
B.left = A;
|
|
4201
|
-
}
|
|
4202
|
-
this._updateHeight(A);
|
|
4203
|
-
if (B) this._updateHeight(B);
|
|
4204
|
-
}
|
|
4205
|
-
/**
|
|
4206
|
-
* Time Complexity: O(1)
|
|
4207
|
-
* Space Complexity: O(1)
|
|
4208
|
-
*
|
|
4209
|
-
* The function `_balanceRL` performs a right-left rotation to balance a binary tree.
|
|
4210
|
-
* @param {AVLTreeNode<K, V>} A - A is a node in a binary tree.
|
|
4211
|
-
*/
|
|
4212
|
-
_balanceRL(A) {
|
|
4213
|
-
const parentOfA = A.parent;
|
|
4214
|
-
const B = A.right;
|
|
4215
|
-
let C = void 0;
|
|
4216
|
-
if (B) {
|
|
4217
|
-
C = B.left;
|
|
4218
|
-
}
|
|
4219
|
-
if (C !== null) A.parent = C;
|
|
4220
|
-
if (B && C !== null) B.parent = C;
|
|
4221
|
-
if (C) {
|
|
4222
|
-
if (C.left) {
|
|
4223
|
-
C.left.parent = A;
|
|
4224
|
-
}
|
|
4225
|
-
if (C.right) {
|
|
4226
|
-
if (B !== null) C.right.parent = B;
|
|
4227
|
-
}
|
|
4228
|
-
C.parent = parentOfA;
|
|
4229
|
-
}
|
|
4230
|
-
if (A === this.root) {
|
|
4231
|
-
if (C) this._setRoot(C);
|
|
4232
|
-
} else {
|
|
4233
|
-
if (parentOfA) {
|
|
4234
|
-
if (parentOfA.left === A) {
|
|
4235
|
-
parentOfA.left = C;
|
|
4236
|
-
} else {
|
|
4237
|
-
parentOfA.right = C;
|
|
4238
|
-
}
|
|
4239
|
-
}
|
|
4240
|
-
}
|
|
4241
|
-
if (C) A.right = C.left;
|
|
4242
|
-
if (B && C) B.left = C.right;
|
|
4243
|
-
if (C) C.left = A;
|
|
4244
|
-
if (C) C.right = B;
|
|
4245
|
-
this._updateHeight(A);
|
|
4246
|
-
if (B) this._updateHeight(B);
|
|
4247
|
-
if (C) this._updateHeight(C);
|
|
4248
|
-
}
|
|
4249
|
-
/**
|
|
4250
|
-
* Time Complexity: O(log n)
|
|
4251
|
-
* Space Complexity: O(1)
|
|
4252
|
-
*
|
|
4253
|
-
* The `_balancePath` function is used to update the heights of nodes and perform rotation operations
|
|
4254
|
-
* to restore balance in an AVL tree after inserting a node.
|
|
4255
|
-
* @param { K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } node - The `node` parameter can be of type `R` or
|
|
4256
|
-
* `
|
|
4257
|
-
K | AVLTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined `.
|
|
4258
|
-
*/
|
|
4259
|
-
_balancePath(node) {
|
|
4260
|
-
node = this.ensureNode(node);
|
|
4261
|
-
const path = this.getPathToRoot(node, (node2) => node2, false);
|
|
4262
|
-
for (let i = 0; i < path.length; i++) {
|
|
4263
|
-
const A = path[i];
|
|
4264
|
-
if (A) {
|
|
4265
|
-
this._updateHeight(A);
|
|
4266
|
-
switch (this._balanceFactor(A)) {
|
|
4267
|
-
case -2:
|
|
4268
|
-
if (A && A.left) {
|
|
4269
|
-
if (this._balanceFactor(A.left) <= 0) {
|
|
4270
|
-
this._balanceLL(A);
|
|
4271
|
-
} else {
|
|
4272
|
-
this._balanceLR(A);
|
|
4273
|
-
}
|
|
4274
|
-
}
|
|
4275
|
-
break;
|
|
4276
|
-
case 2:
|
|
4277
|
-
if (A && A.right) {
|
|
4278
|
-
if (this._balanceFactor(A.right) >= 0) {
|
|
4279
|
-
this._balanceRR(A);
|
|
4280
|
-
} else {
|
|
4281
|
-
this._balanceRL(A);
|
|
4282
|
-
}
|
|
4283
|
-
}
|
|
4284
|
-
}
|
|
4285
|
-
}
|
|
4286
|
-
}
|
|
4287
|
-
}
|
|
4288
|
-
/**
|
|
4289
|
-
* Time Complexity: O(1)
|
|
4290
|
-
* Space Complexity: O(1)
|
|
4291
|
-
*
|
|
4292
|
-
* The function replaces an old node with a new node and sets the height of the new node to be the
|
|
4293
|
-
* same as the old node.
|
|
4294
|
-
* @param {AVLTreeNode<K, V>} oldNode - The `oldNode` parameter represents the node that needs to be replaced in
|
|
4295
|
-
* the data structure.
|
|
4296
|
-
* @param {AVLTreeNode<K, V>} newNode - The `newNode` parameter is the new node that will replace the `oldNode` in
|
|
4297
|
-
* the data structure.
|
|
4298
|
-
* @returns The method is returning the result of calling the `_replaceNode` method from the
|
|
4299
|
-
* superclass, with the `oldNode` and `newNode` as arguments.
|
|
4300
|
-
*/
|
|
4301
|
-
_replaceNode(oldNode, newNode) {
|
|
4302
|
-
newNode.height = oldNode.height;
|
|
4303
|
-
return super._replaceNode(oldNode, newNode);
|
|
4304
|
-
}
|
|
4305
|
-
};
|
|
4306
|
-
|
|
4307
|
-
// src/data-structures/binary-tree/avl-tree-multi-map.ts
|
|
4308
|
-
var AVLTreeMultiMapNode = class extends AVLTreeNode {
|
|
4309
|
-
parent = void 0;
|
|
4310
|
-
/**
|
|
4311
|
-
* This TypeScript constructor initializes an object with a key of type K and an array of values of
|
|
4312
|
-
* type V.
|
|
4313
|
-
* @param {K} key - The `key` parameter is typically used to store a unique identifier or key for the
|
|
4314
|
-
* data being stored in the data structure. It helps in quickly accessing or retrieving the
|
|
4315
|
-
* associated value in the data structure.
|
|
4316
|
-
* @param {V[]} value - The `value` parameter in the constructor represents an array of values of
|
|
4317
|
-
* type `V`.
|
|
4318
|
-
*/
|
|
4319
|
-
constructor(key, value) {
|
|
4320
|
-
super(key, value);
|
|
4321
|
-
}
|
|
4322
|
-
_left = void 0;
|
|
4323
|
-
get left() {
|
|
4324
|
-
return this._left;
|
|
4325
|
-
}
|
|
4326
|
-
set left(v) {
|
|
4327
|
-
if (v) {
|
|
4328
|
-
v.parent = this;
|
|
4329
|
-
}
|
|
4330
|
-
this._left = v;
|
|
4331
|
-
}
|
|
4332
|
-
_right = void 0;
|
|
4333
|
-
get right() {
|
|
4334
|
-
return this._right;
|
|
4335
|
-
}
|
|
4336
|
-
set right(v) {
|
|
4337
|
-
if (v) {
|
|
4338
|
-
v.parent = this;
|
|
4339
|
-
}
|
|
4340
|
-
this._right = v;
|
|
4341
|
-
}
|
|
4342
|
-
};
|
|
4343
|
-
var AVLTreeMultiMap = class _AVLTreeMultiMap extends AVLTree {
|
|
4344
|
-
/**
|
|
4345
|
-
* The constructor initializes an AVLTreeMultiMap with the provided keys, nodes, entries, or raw data
|
|
4346
|
-
* and options.
|
|
4347
|
-
* @param keysNodesEntriesOrRaws - The `keysNodesEntriesOrRaws` parameter in the constructor is an
|
|
4348
|
-
* iterable that can contain either key-value pairs represented as `BTNRep<K, V[],
|
|
4349
|
-
* AVLTreeMultiMapNode<K, V>>` or raw data represented as `R`. This parameter is used to initialize
|
|
4350
|
-
* the AVLTreeMulti
|
|
4351
|
-
* @param [options] - The `options` parameter in the constructor is of type
|
|
4352
|
-
* `AVLTreeMultiMapOptions<K, V[], R>`. It is an optional parameter that allows you to specify
|
|
4353
|
-
* additional options for configuring the AVLTreeMultiMap instance.
|
|
4354
|
-
*/
|
|
4355
|
-
constructor(keysNodesEntriesOrRaws = [], options) {
|
|
4356
|
-
super([], { ...options, isMapMode: true });
|
|
4357
|
-
if (keysNodesEntriesOrRaws) {
|
|
4358
|
-
this.addMany(keysNodesEntriesOrRaws);
|
|
4359
|
-
}
|
|
4360
|
-
}
|
|
4361
|
-
/**
|
|
4362
|
-
* Time Complexity: O(1)
|
|
4363
|
-
* Space Complexity: O(1)
|
|
4364
|
-
*
|
|
4365
|
-
* The function `createTree` in TypeScript overrides the creation of an AVLTreeMultiMap with
|
|
4366
|
-
* specified options.
|
|
4367
|
-
* @param [options] - The `options` parameter in the `createTree` function is of type
|
|
4368
|
-
* `AVLTreeMultiMapOptions<K, V[], R>`. This means it is an object that can have properties of type
|
|
4369
|
-
* `K`, `V[]`, and `R`. The function creates a new `AVL
|
|
4370
|
-
* @returns The `createTree` method is returning a new instance of `AVLTreeMultiMap` with the
|
|
4371
|
-
* provided options.
|
|
4372
|
-
*/
|
|
4373
|
-
createTree(options) {
|
|
4374
|
-
return new _AVLTreeMultiMap([], {
|
|
4375
|
-
iterationType: this.iterationType,
|
|
4376
|
-
specifyComparable: this._specifyComparable,
|
|
4377
|
-
toEntryFn: this._toEntryFn,
|
|
4378
|
-
isReverse: this._isReverse,
|
|
4379
|
-
isMapMode: this._isMapMode,
|
|
4380
|
-
...options
|
|
4381
|
-
});
|
|
4382
|
-
}
|
|
4383
|
-
/**
|
|
4384
|
-
* Time Complexity: O(1)
|
|
4385
|
-
* Space Complexity: O(1)
|
|
4386
|
-
*
|
|
4387
|
-
* The `createNode` function in TypeScript overrides the default implementation to create a new
|
|
4388
|
-
* AVLTreeMultiMapNode with a specified key and value array.
|
|
4389
|
-
* @param {K} key - The `key` parameter represents the key of the node being created in the
|
|
4390
|
-
* AVLTreeMultiMap.
|
|
4391
|
-
* @param {V[]} value - The `value` parameter in the `createNode` method represents an array of
|
|
4392
|
-
* values associated with a specific key in the AVLTreeMultiMapNode. If no value is provided when
|
|
4393
|
-
* calling the method, an empty array `[]` is used as the default value.
|
|
4394
|
-
* @returns An AVLTreeMultiMapNode object is being returned, with the specified key and value. If the
|
|
4395
|
-
* AVLTreeMultiMap is in map mode, an empty array is used as the value, otherwise the provided value
|
|
4396
|
-
* array is used.
|
|
4397
|
-
*/
|
|
4398
|
-
createNode(key, value = []) {
|
|
4399
|
-
return new AVLTreeMultiMapNode(key, this._isMapMode ? [] : value);
|
|
4400
|
-
}
|
|
4401
|
-
/**
|
|
4402
|
-
* Time Complexity: O(log n)
|
|
4403
|
-
* Space Complexity: O(log n)
|
|
4404
|
-
*
|
|
4405
|
-
* The function `add` in this TypeScript code overrides the superclass method to add key-value pairs
|
|
4406
|
-
* to an AVLTreeMultiMap, handling different input types and scenarios.
|
|
4407
|
-
* @param [key] - The `key` parameter in the `override add` method represents the key of the entry to
|
|
4408
|
-
* be added to the AVLTreeMultiMap. It can be of type `K`, which is the key type of the map. The key
|
|
4409
|
-
* can be a single key value, a node of the AVLTree
|
|
4410
|
-
* @param {V[]} [values] - The `values` parameter in the `add` method represents an array of values
|
|
4411
|
-
* that you want to add to the AVLTreeMultiMap. It can contain one or more values associated with a
|
|
4412
|
-
* specific key.
|
|
4413
|
-
* @returns The `add` method is returning a boolean value, which indicates whether the operation was
|
|
4414
|
-
* successful or not.
|
|
4415
|
-
*/
|
|
4416
|
-
add(keyNodeOrEntry, value) {
|
|
4417
|
-
if (this.isRealNode(keyNodeOrEntry)) return super.add(keyNodeOrEntry);
|
|
4418
|
-
const _commonAdd = (key, values) => {
|
|
4419
|
-
if (key === void 0 || key === null) return false;
|
|
4420
|
-
const _addToValues = () => {
|
|
4421
|
-
const existingValues = this.get(key);
|
|
4422
|
-
if (existingValues !== void 0 && values !== void 0) {
|
|
4423
|
-
for (const value2 of values) existingValues.push(value2);
|
|
4424
|
-
return true;
|
|
4425
|
-
}
|
|
4426
|
-
return false;
|
|
4427
|
-
};
|
|
4428
|
-
const _addByNode = () => {
|
|
4429
|
-
const existingNode = this.getNode(key);
|
|
4430
|
-
if (this.isRealNode(existingNode)) {
|
|
4431
|
-
const existingValues = this.get(existingNode);
|
|
4432
|
-
if (existingValues === void 0) {
|
|
4433
|
-
super.add(key, values);
|
|
4434
|
-
return true;
|
|
4435
|
-
}
|
|
4436
|
-
if (values !== void 0) {
|
|
4437
|
-
for (const value2 of values) existingValues.push(value2);
|
|
4438
|
-
return true;
|
|
4439
|
-
} else {
|
|
4440
|
-
return false;
|
|
4441
|
-
}
|
|
4442
|
-
} else {
|
|
4443
|
-
return super.add(key, values);
|
|
4444
|
-
}
|
|
4445
|
-
};
|
|
4446
|
-
if (this._isMapMode) {
|
|
4447
|
-
return _addByNode() || _addToValues();
|
|
4448
|
-
}
|
|
4449
|
-
return _addToValues() || _addByNode();
|
|
4450
|
-
};
|
|
4451
|
-
if (this.isEntry(keyNodeOrEntry)) {
|
|
4452
|
-
const [key, values] = keyNodeOrEntry;
|
|
4453
|
-
return _commonAdd(key, value !== void 0 ? [value] : values);
|
|
4454
|
-
}
|
|
4455
|
-
return _commonAdd(keyNodeOrEntry, value !== void 0 ? [value] : void 0);
|
|
4456
|
-
}
|
|
4457
|
-
/**
|
|
4458
|
-
* Time Complexity: O(log n)
|
|
4459
|
-
* Space Complexity: O(log n)
|
|
4460
|
-
*
|
|
4461
|
-
* The function `deleteValue` removes a specific value from a key in an AVLTreeMultiMap data
|
|
4462
|
-
* structure and deletes the entire node if no values are left for that key.
|
|
4463
|
-
* @param {K | AVLTreeMultiMapNode<K, V> | [K | null | undefined, V[] | undefined] | null | undefined | K} keyNodeOrEntry - The `keyNodeOrEntry`
|
|
4464
|
-
* parameter in the `deleteValue` function can be either a `BTNRep` object representing a key-value
|
|
4465
|
-
* pair in the AVLTreeMultiMapNode, or just the key itself.
|
|
4466
|
-
* @param {V} value - The `value` parameter in the `deleteValue` function represents the specific
|
|
4467
|
-
* value that you want to delete from the multi-map data structure associated with a particular key.
|
|
4468
|
-
* The function checks if the value exists in the array of values associated with the key, and if
|
|
4469
|
-
* found, removes it from the array.
|
|
4470
|
-
* @returns The `deleteValue` function returns a boolean value. It returns `true` if the specified
|
|
4471
|
-
* `value` was successfully deleted from the array of values associated with the `keyNodeOrEntry`. If
|
|
4472
|
-
* the value was not found in the array, it returns `false`.
|
|
4473
|
-
*/
|
|
4474
|
-
deleteValue(keyNodeOrEntry, value) {
|
|
4475
|
-
const values = this.get(keyNodeOrEntry);
|
|
4476
|
-
if (Array.isArray(values)) {
|
|
4477
|
-
const index = values.indexOf(value);
|
|
4478
|
-
if (index === -1) return false;
|
|
4479
|
-
values.splice(index, 1);
|
|
4480
|
-
if (values.length === 0) this.delete(keyNodeOrEntry);
|
|
4481
|
-
return true;
|
|
4482
|
-
}
|
|
4483
|
-
return false;
|
|
4484
|
-
}
|
|
4485
|
-
/**
|
|
4486
|
-
* Time Complexity: O(n)
|
|
4487
|
-
* Space Complexity: O(n)
|
|
4488
|
-
*
|
|
4489
|
-
* The function `clone` overrides the default cloning behavior to create a deep copy of a tree
|
|
4490
|
-
* structure.
|
|
4491
|
-
* @returns A cloned tree object is being returned.
|
|
4492
|
-
*/
|
|
4493
|
-
clone() {
|
|
4494
|
-
const cloned = this.createTree();
|
|
4495
|
-
this._clone(cloned);
|
|
4496
|
-
return cloned;
|
|
4497
|
-
}
|
|
4498
|
-
};
|
|
4499
|
-
export {
|
|
4500
|
-
AVLTreeMultiMap,
|
|
4501
|
-
AVLTreeMultiMapNode
|
|
4502
|
-
};
|
|
4503
|
-
/**
|
|
4504
|
-
* data-structure-typed
|
|
4505
|
-
*
|
|
4506
|
-
* @author Pablo Zeng
|
|
4507
|
-
* @copyright Copyright (c) 2022 Pablo Zeng <zrwusa@gmail.com>
|
|
4508
|
-
* @license MIT License
|
|
4509
|
-
*/
|
|
4510
|
-
/**
|
|
4511
|
-
* @license MIT
|
|
4512
|
-
* @copyright Pablo Zeng <zrwusa@gmail.com>
|
|
4513
|
-
* @class
|
|
4514
|
-
*/
|