stack-typed 2.0.5 → 2.1.1
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/dist/data-structures/base/iterable-element-base.d.ts +186 -83
- package/dist/data-structures/base/iterable-element-base.js +149 -107
- package/dist/data-structures/base/iterable-entry-base.d.ts +95 -119
- package/dist/data-structures/base/iterable-entry-base.js +59 -116
- package/dist/data-structures/base/linear-base.d.ts +250 -192
- package/dist/data-structures/base/linear-base.js +137 -274
- package/dist/data-structures/binary-tree/avl-tree-counter.d.ts +126 -158
- package/dist/data-structures/binary-tree/avl-tree-counter.js +171 -205
- package/dist/data-structures/binary-tree/avl-tree-multi-map.d.ts +100 -69
- package/dist/data-structures/binary-tree/avl-tree-multi-map.js +135 -87
- package/dist/data-structures/binary-tree/avl-tree.d.ts +138 -149
- package/dist/data-structures/binary-tree/avl-tree.js +208 -195
- package/dist/data-structures/binary-tree/binary-tree.d.ts +476 -632
- package/dist/data-structures/binary-tree/binary-tree.js +602 -873
- package/dist/data-structures/binary-tree/bst.d.ts +258 -306
- package/dist/data-structures/binary-tree/bst.js +505 -481
- package/dist/data-structures/binary-tree/red-black-tree.d.ts +107 -179
- package/dist/data-structures/binary-tree/red-black-tree.js +114 -209
- package/dist/data-structures/binary-tree/tree-counter.d.ts +132 -154
- package/dist/data-structures/binary-tree/tree-counter.js +172 -203
- package/dist/data-structures/binary-tree/tree-multi-map.d.ts +72 -69
- package/dist/data-structures/binary-tree/tree-multi-map.js +105 -85
- package/dist/data-structures/graph/abstract-graph.d.ts +238 -233
- package/dist/data-structures/graph/abstract-graph.js +267 -237
- package/dist/data-structures/graph/directed-graph.d.ts +108 -224
- package/dist/data-structures/graph/directed-graph.js +146 -233
- package/dist/data-structures/graph/map-graph.d.ts +49 -55
- package/dist/data-structures/graph/map-graph.js +56 -59
- package/dist/data-structures/graph/undirected-graph.d.ts +103 -146
- package/dist/data-structures/graph/undirected-graph.js +129 -149
- package/dist/data-structures/hash/hash-map.d.ts +164 -338
- package/dist/data-structures/hash/hash-map.js +270 -457
- package/dist/data-structures/heap/heap.d.ts +214 -289
- package/dist/data-structures/heap/heap.js +340 -349
- package/dist/data-structures/heap/max-heap.d.ts +11 -47
- package/dist/data-structures/heap/max-heap.js +11 -66
- package/dist/data-structures/heap/min-heap.d.ts +12 -47
- package/dist/data-structures/heap/min-heap.js +11 -66
- package/dist/data-structures/linked-list/doubly-linked-list.d.ts +231 -347
- package/dist/data-structures/linked-list/doubly-linked-list.js +368 -494
- package/dist/data-structures/linked-list/singly-linked-list.d.ts +261 -310
- package/dist/data-structures/linked-list/singly-linked-list.js +447 -466
- package/dist/data-structures/linked-list/skip-linked-list.d.ts +0 -107
- package/dist/data-structures/linked-list/skip-linked-list.js +0 -100
- package/dist/data-structures/priority-queue/max-priority-queue.d.ts +12 -56
- package/dist/data-structures/priority-queue/max-priority-queue.js +11 -78
- package/dist/data-structures/priority-queue/min-priority-queue.d.ts +11 -57
- package/dist/data-structures/priority-queue/min-priority-queue.js +10 -79
- package/dist/data-structures/priority-queue/priority-queue.d.ts +2 -61
- package/dist/data-structures/priority-queue/priority-queue.js +8 -83
- package/dist/data-structures/queue/deque.d.ts +227 -254
- package/dist/data-structures/queue/deque.js +309 -348
- package/dist/data-structures/queue/queue.d.ts +180 -201
- package/dist/data-structures/queue/queue.js +265 -248
- package/dist/data-structures/stack/stack.d.ts +124 -102
- package/dist/data-structures/stack/stack.js +181 -125
- package/dist/data-structures/trie/trie.d.ts +164 -165
- package/dist/data-structures/trie/trie.js +189 -172
- package/dist/interfaces/binary-tree.d.ts +56 -6
- package/dist/interfaces/graph.d.ts +16 -0
- package/dist/types/data-structures/base/base.d.ts +1 -1
- package/dist/types/data-structures/graph/abstract-graph.d.ts +4 -0
- package/dist/types/utils/utils.d.ts +1 -0
- package/dist/utils/utils.d.ts +1 -1
- package/dist/utils/utils.js +2 -1
- package/package.json +2 -2
- package/src/data-structures/base/iterable-element-base.ts +238 -115
- package/src/data-structures/base/iterable-entry-base.ts +96 -120
- package/src/data-structures/base/linear-base.ts +271 -277
- package/src/data-structures/binary-tree/avl-tree-counter.ts +196 -217
- package/src/data-structures/binary-tree/avl-tree-multi-map.ts +188 -102
- package/src/data-structures/binary-tree/avl-tree.ts +237 -206
- package/src/data-structures/binary-tree/binary-tree.ts +665 -896
- package/src/data-structures/binary-tree/bst.ts +565 -572
- package/src/data-structures/binary-tree/red-black-tree.ts +157 -223
- package/src/data-structures/binary-tree/tree-counter.ts +195 -219
- package/src/data-structures/binary-tree/tree-multi-map.ts +127 -98
- package/src/data-structures/graph/abstract-graph.ts +339 -264
- package/src/data-structures/graph/directed-graph.ts +146 -236
- package/src/data-structures/graph/map-graph.ts +63 -60
- package/src/data-structures/graph/undirected-graph.ts +129 -152
- package/src/data-structures/hash/hash-map.ts +274 -496
- package/src/data-structures/heap/heap.ts +389 -402
- package/src/data-structures/heap/max-heap.ts +12 -76
- package/src/data-structures/heap/min-heap.ts +13 -76
- package/src/data-structures/linked-list/doubly-linked-list.ts +426 -530
- package/src/data-structures/linked-list/singly-linked-list.ts +495 -517
- package/src/data-structures/linked-list/skip-linked-list.ts +1 -108
- package/src/data-structures/priority-queue/max-priority-queue.ts +12 -87
- package/src/data-structures/priority-queue/min-priority-queue.ts +11 -88
- package/src/data-structures/priority-queue/priority-queue.ts +3 -92
- package/src/data-structures/queue/deque.ts +381 -357
- package/src/data-structures/queue/queue.ts +310 -264
- package/src/data-structures/stack/stack.ts +217 -131
- package/src/data-structures/trie/trie.ts +240 -175
- package/src/interfaces/binary-tree.ts +240 -6
- package/src/interfaces/graph.ts +37 -0
- package/src/types/data-structures/base/base.ts +5 -5
- package/src/types/data-structures/graph/abstract-graph.ts +5 -0
- package/src/types/utils/utils.ts +2 -0
- package/src/utils/utils.ts +9 -14
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
* @copyright Copyright (c) 2022 Pablo Zeng <zrwusa@gmail.com>
|
|
6
6
|
* @license MIT License
|
|
7
7
|
*/
|
|
8
|
+
|
|
8
9
|
import type {
|
|
10
|
+
BinaryTreeOptions,
|
|
9
11
|
BSTNOptKeyOrNode,
|
|
10
12
|
BSTOptions,
|
|
11
13
|
BTNRep,
|
|
@@ -25,17 +27,21 @@ import { Queue } from '../queue';
|
|
|
25
27
|
import { isComparable } from '../../utils';
|
|
26
28
|
import { Range } from '../../common';
|
|
27
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Represents a Node in a Binary Search Tree.
|
|
32
|
+
*
|
|
33
|
+
* @template K - The type of the key.
|
|
34
|
+
* @template V - The type of the value.
|
|
35
|
+
*/
|
|
28
36
|
export class BSTNode<K = any, V = any> extends BinaryTreeNode<K, V> {
|
|
29
37
|
override parent?: BSTNode<K, V> = undefined;
|
|
30
38
|
|
|
31
39
|
/**
|
|
32
|
-
*
|
|
33
|
-
* @
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* @param
|
|
37
|
-
* have to be provided when creating an instance of the class. If a value is not provided, it will
|
|
38
|
-
* default to `undefined`.
|
|
40
|
+
* Creates an instance of BSTNode.
|
|
41
|
+
* @remarks Time O(1), Space O(1)
|
|
42
|
+
*
|
|
43
|
+
* @param key - The key of the node.
|
|
44
|
+
* @param [value] - The value associated with the key.
|
|
39
45
|
*/
|
|
40
46
|
constructor(key: K, value?: V) {
|
|
41
47
|
super(key, value);
|
|
@@ -43,32 +49,58 @@ export class BSTNode<K = any, V = any> extends BinaryTreeNode<K, V> {
|
|
|
43
49
|
|
|
44
50
|
override _left?: BSTNode<K, V> | null | undefined = undefined;
|
|
45
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Gets the left child of the node.
|
|
54
|
+
* @remarks Time O(1), Space O(1)
|
|
55
|
+
*
|
|
56
|
+
* @returns The left child.
|
|
57
|
+
*/
|
|
46
58
|
override get left(): BSTNode<K, V> | null | undefined {
|
|
47
59
|
return this._left;
|
|
48
60
|
}
|
|
49
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Sets the left child of the node and updates its parent reference.
|
|
64
|
+
* @remarks Time O(1), Space O(1)
|
|
65
|
+
*
|
|
66
|
+
* @param v - The node to set as the left child.
|
|
67
|
+
*/
|
|
50
68
|
override set left(v: BSTNode<K, V> | null | undefined) {
|
|
51
|
-
if (v)
|
|
52
|
-
v.parent = this;
|
|
53
|
-
}
|
|
69
|
+
if (v) v.parent = this;
|
|
54
70
|
this._left = v;
|
|
55
71
|
}
|
|
56
72
|
|
|
57
73
|
override _right?: BSTNode<K, V> | null | undefined = undefined;
|
|
58
74
|
|
|
75
|
+
/**
|
|
76
|
+
* Gets the right child of the node.
|
|
77
|
+
* @remarks Time O(1), Space O(1)
|
|
78
|
+
*
|
|
79
|
+
* @returns The right child.
|
|
80
|
+
*/
|
|
59
81
|
override get right(): BSTNode<K, V> | null | undefined {
|
|
60
82
|
return this._right;
|
|
61
83
|
}
|
|
62
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Sets the right child of the node and updates its parent reference.
|
|
87
|
+
* @remarks Time O(1), Space O(1)
|
|
88
|
+
*
|
|
89
|
+
* @param v - The node to set as the right child.
|
|
90
|
+
*/
|
|
63
91
|
override set right(v: BSTNode<K, V> | null | undefined) {
|
|
64
|
-
if (v)
|
|
65
|
-
v.parent = this;
|
|
66
|
-
}
|
|
92
|
+
if (v) v.parent = this;
|
|
67
93
|
this._right = v;
|
|
68
94
|
}
|
|
69
95
|
}
|
|
70
96
|
|
|
71
97
|
/**
|
|
98
|
+
* Represents a Binary Search Tree (BST).
|
|
99
|
+
* Keys are ordered, allowing for faster search operations compared to a standard Binary Tree.
|
|
100
|
+
* @template K - The type of the key.
|
|
101
|
+
* @template V - The type of the value.
|
|
102
|
+
* @template R - The type of the raw data object (if using `toEntryFn`).
|
|
103
|
+
*
|
|
72
104
|
* 1. Node Order: Each node's left child has a lesser value, and the right child has a greater value.
|
|
73
105
|
* 2. Unique Keys: No duplicate keys in a standard BST.
|
|
74
106
|
* 3. Efficient Search: Enables quick search, minimum, and maximum operations.
|
|
@@ -133,18 +165,13 @@ export class BSTNode<K = any, V = any> extends BinaryTreeNode<K, V> {
|
|
|
133
165
|
* console.log(findLCA(5, 35)); // 15
|
|
134
166
|
* console.log(findLCA(20, 30)); // 25
|
|
135
167
|
*/
|
|
136
|
-
export class BST<K = any, V = any, R =
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
* @param keysNodesEntriesOrRaws - The `keysNodesEntriesOrRaws` parameter in the constructor is an
|
|
144
|
-
* iterable that can contain elements of type `K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined ` or `R`. It is used to
|
|
145
|
-
* initialize the binary search tree with keys, nodes, entries, or raw data.
|
|
146
|
-
* @param [options] - The `options` parameter is an optional object that can contain the following
|
|
147
|
-
* properties:
|
|
168
|
+
export class BST<K = any, V = any, R = any> extends BinaryTree<K, V, R> implements IBinaryTree<K, V, R> {
|
|
169
|
+
/**
|
|
170
|
+
* Creates an instance of BST.
|
|
171
|
+
* @remarks Time O(N log N) or O(N^2) depending on `isBalanceAdd` in `addMany` and input order. Space O(N).
|
|
172
|
+
*
|
|
173
|
+
* @param [keysNodesEntriesOrRaws=[]] - An iterable of items to add.
|
|
174
|
+
* @param [options] - Configuration options for the BST, including comparator.
|
|
148
175
|
*/
|
|
149
176
|
constructor(
|
|
150
177
|
keysNodesEntriesOrRaws: Iterable<
|
|
@@ -159,22 +186,37 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|
|
159
186
|
if (typeof specifyComparable === 'function') this._specifyComparable = specifyComparable;
|
|
160
187
|
if (isReverse !== undefined) this._isReverse = isReverse;
|
|
161
188
|
}
|
|
162
|
-
|
|
163
189
|
if (keysNodesEntriesOrRaws) this.addMany(keysNodesEntriesOrRaws);
|
|
164
190
|
}
|
|
165
191
|
|
|
166
192
|
protected override _root?: BSTNode<K, V> = undefined;
|
|
167
193
|
|
|
194
|
+
/**
|
|
195
|
+
* Gets the root node of the tree.
|
|
196
|
+
* @remarks Time O(1)
|
|
197
|
+
*
|
|
198
|
+
* @returns The root node.
|
|
199
|
+
*/
|
|
168
200
|
override get root(): OptNode<BSTNode<K, V>> {
|
|
169
201
|
return this._root;
|
|
170
202
|
}
|
|
171
203
|
|
|
172
204
|
protected _isReverse: boolean = false;
|
|
173
205
|
|
|
206
|
+
/**
|
|
207
|
+
* Gets whether the tree's comparison logic is reversed.
|
|
208
|
+
* @remarks Time O(1)
|
|
209
|
+
*
|
|
210
|
+
* @returns True if the tree is reversed (e.g., a max-heap logic).
|
|
211
|
+
*/
|
|
174
212
|
get isReverse(): boolean {
|
|
175
213
|
return this._isReverse;
|
|
176
214
|
}
|
|
177
215
|
|
|
216
|
+
/**
|
|
217
|
+
* The default comparator function.
|
|
218
|
+
* @remarks Time O(1) (or O(C) if `specifyComparable` is used, C is complexity of that function).
|
|
219
|
+
*/
|
|
178
220
|
protected _comparator: Comparator<K> = (a: K, b: K): number => {
|
|
179
221
|
if (isComparable(a) && isComparable(b)) {
|
|
180
222
|
if (a > b) return 1;
|
|
@@ -182,79 +224,61 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|
|
182
224
|
return 0;
|
|
183
225
|
}
|
|
184
226
|
if (this._specifyComparable) {
|
|
185
|
-
|
|
186
|
-
|
|
227
|
+
const va = this._specifyComparable(a);
|
|
228
|
+
const vb = this._specifyComparable(b);
|
|
229
|
+
if (va > vb) return 1;
|
|
230
|
+
if (va < vb) return -1;
|
|
187
231
|
return 0;
|
|
188
232
|
}
|
|
189
233
|
if (typeof a === 'object' || typeof b === 'object') {
|
|
190
234
|
throw TypeError(
|
|
191
|
-
`When comparing object types, a custom specifyComparable must be defined in the constructor's options
|
|
235
|
+
`When comparing object types, a custom specifyComparable must be defined in the constructor's options.`
|
|
192
236
|
);
|
|
193
237
|
}
|
|
194
|
-
|
|
195
238
|
return 0;
|
|
196
239
|
};
|
|
197
240
|
|
|
198
|
-
|
|
241
|
+
/**
|
|
242
|
+
* Gets the comparator function used by the tree.
|
|
243
|
+
* @remarks Time O(1)
|
|
244
|
+
*
|
|
245
|
+
* @returns The comparator function.
|
|
246
|
+
*/
|
|
247
|
+
get comparator(): Comparator<K> {
|
|
199
248
|
return this._comparator;
|
|
200
249
|
}
|
|
201
250
|
|
|
202
251
|
protected _specifyComparable?: (key: K) => Comparable;
|
|
203
252
|
|
|
204
|
-
get specifyComparable() {
|
|
205
|
-
return this._specifyComparable;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
253
|
/**
|
|
209
|
-
*
|
|
210
|
-
*
|
|
254
|
+
* Gets the function used to extract a comparable value from a complex key.
|
|
255
|
+
* @remarks Time O(1)
|
|
211
256
|
*
|
|
212
|
-
* The
|
|
213
|
-
* @param {K} key - The key parameter is of type K, which represents the type of the key for the node
|
|
214
|
-
* being created.
|
|
215
|
-
* @param {V} [value] - The "value" parameter is an optional parameter of type V. It represents the
|
|
216
|
-
* value associated with the key in the node being created.
|
|
217
|
-
* @returns The method is returning a new instance of the BSTNode class, casted as the BSTNode<K, V> type.
|
|
257
|
+
* @returns The key-to-comparable conversion function.
|
|
218
258
|
*/
|
|
219
|
-
|
|
220
|
-
return
|
|
259
|
+
get specifyComparable(): ((key: K) => Comparable) | undefined {
|
|
260
|
+
return this._specifyComparable;
|
|
221
261
|
}
|
|
222
262
|
|
|
223
263
|
/**
|
|
224
|
-
*
|
|
225
|
-
*
|
|
264
|
+
* (Protected) Creates a new BST node.
|
|
265
|
+
* @remarks Time O(1), Space O(1)
|
|
226
266
|
*
|
|
227
|
-
*
|
|
228
|
-
* @param [
|
|
229
|
-
*
|
|
230
|
-
* following properties:
|
|
231
|
-
* @returns a new instance of the BST class with the provided options.
|
|
267
|
+
* @param key - The key for the new node.
|
|
268
|
+
* @param [value] - The value for the new node (used if not in Map mode).
|
|
269
|
+
* @returns The newly created BSTNode.
|
|
232
270
|
*/
|
|
233
|
-
override
|
|
234
|
-
return new
|
|
235
|
-
iterationType: this.iterationType,
|
|
236
|
-
isMapMode: this._isMapMode,
|
|
237
|
-
specifyComparable: this._specifyComparable,
|
|
238
|
-
toEntryFn: this._toEntryFn,
|
|
239
|
-
isReverse: this._isReverse,
|
|
240
|
-
...options
|
|
241
|
-
});
|
|
271
|
+
override _createNode(key: K, value?: V): BSTNode<K, V> {
|
|
272
|
+
return new BSTNode<K, V>(key, this._isMapMode ? undefined : value);
|
|
242
273
|
}
|
|
243
274
|
|
|
244
275
|
/**
|
|
245
|
-
*
|
|
246
|
-
*
|
|
276
|
+
* Ensures the input is a node. If it's a key or entry, it searches for the node.
|
|
277
|
+
* @remarks Time O(log N) (height of the tree), O(N) worst-case.
|
|
247
278
|
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
* @
|
|
251
|
-
* `keyNodeOrEntry` can accept a value of type `R`, which represents the key, node,
|
|
252
|
-
* entry, or raw element that needs to be ensured in the tree.
|
|
253
|
-
* @param {IterationType} [iterationType=ITERATIVE] - The `iterationType` parameter is an optional
|
|
254
|
-
* parameter that specifies the type of iteration to be used when ensuring a node. It has a default
|
|
255
|
-
* value of `'ITERATIVE'`.
|
|
256
|
-
* @returns The method is returning either the node that was ensured or `undefined` if the node could
|
|
257
|
-
* not be ensured.
|
|
279
|
+
* @param keyNodeOrEntry - The item to resolve to a node.
|
|
280
|
+
* @param [iterationType=this.iterationType] - The traversal method to use if searching.
|
|
281
|
+
* @returns The resolved node, or undefined if not found.
|
|
258
282
|
*/
|
|
259
283
|
override ensureNode(
|
|
260
284
|
keyNodeOrEntry: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
|
@@ -264,14 +288,11 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|
|
264
288
|
}
|
|
265
289
|
|
|
266
290
|
/**
|
|
267
|
-
*
|
|
268
|
-
*
|
|
291
|
+
* Checks if the given item is a `BSTNode` instance.
|
|
292
|
+
* @remarks Time O(1), Space O(1)
|
|
269
293
|
*
|
|
270
|
-
*
|
|
271
|
-
* @
|
|
272
|
-
* `keyNodeOrEntry` can be of type `R` or `K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined `.
|
|
273
|
-
* @returns a boolean value indicating whether the input parameter `keyNodeOrEntry` is
|
|
274
|
-
* an instance of the `BSTNode` class.
|
|
294
|
+
* @param keyNodeOrEntry - The item to check.
|
|
295
|
+
* @returns True if it's a BSTNode, false otherwise.
|
|
275
296
|
*/
|
|
276
297
|
override isNode(
|
|
277
298
|
keyNodeOrEntry: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined
|
|
@@ -280,30 +301,221 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|
|
280
301
|
}
|
|
281
302
|
|
|
282
303
|
/**
|
|
283
|
-
*
|
|
284
|
-
*
|
|
304
|
+
* Checks if the given key is valid (comparable).
|
|
305
|
+
* @remarks Time O(1)
|
|
285
306
|
*
|
|
286
|
-
*
|
|
287
|
-
* @
|
|
288
|
-
* type `K`.
|
|
289
|
-
* @returns The `override isValidKey(key: any): key is K` function is returning a boolean value based on
|
|
290
|
-
* the result of the `isComparable` function with the condition `this._compare !==
|
|
291
|
-
* this._DEFAULT_COMPARATOR`.
|
|
307
|
+
* @param key - The key to validate.
|
|
308
|
+
* @returns True if the key is valid, false otherwise.
|
|
292
309
|
*/
|
|
293
310
|
override isValidKey(key: any): key is K {
|
|
294
311
|
return isComparable(key, this._specifyComparable !== undefined);
|
|
295
312
|
}
|
|
296
313
|
|
|
297
314
|
/**
|
|
298
|
-
*
|
|
299
|
-
*
|
|
315
|
+
* Performs a Depth-First Search (DFS) traversal.
|
|
316
|
+
* @remarks Time O(N), visits every node. Space O(log N) for the call/explicit stack. O(N) worst-case.
|
|
317
|
+
*
|
|
318
|
+
* @template C - The type of the callback function.
|
|
319
|
+
* @param [callback=this._DEFAULT_NODE_CALLBACK] - Function to call on each node.
|
|
320
|
+
* @param [pattern='IN'] - The traversal order ('IN', 'PRE', 'POST').
|
|
321
|
+
* @param [onlyOne=false] - If true, stops after the first callback.
|
|
322
|
+
* @param [startNode=this._root] - The node to start from.
|
|
323
|
+
* @param [iterationType=this.iterationType] - The traversal method.
|
|
324
|
+
* @returns An array of callback results.
|
|
325
|
+
*/
|
|
326
|
+
override dfs<C extends NodeCallback<BSTNode<K, V>>>(
|
|
327
|
+
callback: C = this._DEFAULT_NODE_CALLBACK as C,
|
|
328
|
+
pattern: DFSOrderPattern = 'IN',
|
|
329
|
+
onlyOne: boolean = false,
|
|
330
|
+
startNode: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
|
|
331
|
+
iterationType: IterationType = this.iterationType
|
|
332
|
+
): ReturnType<C>[] {
|
|
333
|
+
return super.dfs(callback, pattern, onlyOne, startNode, iterationType);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Performs a Breadth-First Search (BFS) or Level-Order traversal.
|
|
338
|
+
* @remarks Time O(N), visits every node. Space O(N) in the worst case for the queue.
|
|
300
339
|
*
|
|
301
|
-
*
|
|
302
|
-
* @param
|
|
303
|
-
*
|
|
304
|
-
* @param
|
|
305
|
-
*
|
|
306
|
-
|
|
340
|
+
* @template C - The type of the callback function.
|
|
341
|
+
* @param [callback=this._DEFAULT_NODE_CALLBACK] - Function to call on each node.
|
|
342
|
+
* @param [startNode=this._root] - The node to start from.
|
|
343
|
+
* @param [iterationType=this.iterationType] - The traversal method.
|
|
344
|
+
* @returns An array of callback results.
|
|
345
|
+
*/
|
|
346
|
+
override bfs<C extends NodeCallback<BSTNode<K, V>>>(
|
|
347
|
+
callback: C = this._DEFAULT_NODE_CALLBACK as C,
|
|
348
|
+
startNode: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
|
|
349
|
+
iterationType: IterationType = this.iterationType
|
|
350
|
+
): ReturnType<C>[] {
|
|
351
|
+
return super.bfs(callback, startNode, iterationType, false);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Returns a 2D array of nodes, grouped by level.
|
|
356
|
+
* @remarks Time O(N), visits every node. Space O(N) for the result array and the queue/stack.
|
|
357
|
+
*
|
|
358
|
+
* @template C - The type of the callback function.
|
|
359
|
+
* @param [callback=this._DEFAULT_NODE_CALLBACK] - Function to call on each node.
|
|
360
|
+
* @param [startNode=this._root] - The node to start from.
|
|
361
|
+
* @param [iterationType=this.iterationType] - The traversal method.
|
|
362
|
+
* @returns A 2D array of callback results.
|
|
363
|
+
*/
|
|
364
|
+
override listLevels<C extends NodeCallback<BSTNode<K, V>>>(
|
|
365
|
+
callback: C = this._DEFAULT_NODE_CALLBACK as C,
|
|
366
|
+
startNode: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
|
|
367
|
+
iterationType: IterationType = this.iterationType
|
|
368
|
+
): ReturnType<C>[][] {
|
|
369
|
+
return super.listLevels(callback, startNode, iterationType, false);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Gets the first node matching a predicate.
|
|
374
|
+
* @remarks Time O(log N) if searching by key, O(N) if searching by predicate. Space O(log N) or O(N).
|
|
375
|
+
*
|
|
376
|
+
* @param keyNodeEntryOrPredicate - The key, node, entry, or predicate function to search for.
|
|
377
|
+
* @param [startNode=this._root] - The node to start the search from.
|
|
378
|
+
* @param [iterationType=this.iterationType] - The traversal method.
|
|
379
|
+
* @returns The first matching node, or undefined if not found.
|
|
380
|
+
*/
|
|
381
|
+
override getNode(
|
|
382
|
+
keyNodeEntryOrPredicate:
|
|
383
|
+
| K
|
|
384
|
+
| BSTNode<K, V>
|
|
385
|
+
| [K | null | undefined, V | undefined]
|
|
386
|
+
| null
|
|
387
|
+
| undefined
|
|
388
|
+
| NodePredicate<BSTNode<K, V>>,
|
|
389
|
+
startNode: BSTNOptKeyOrNode<K, BSTNode<K, V>> = this._root,
|
|
390
|
+
iterationType: IterationType = this.iterationType
|
|
391
|
+
): OptNode<BSTNode<K, V>> {
|
|
392
|
+
return this.getNodes(keyNodeEntryOrPredicate, true, startNode, iterationType)[0] ?? undefined;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Searches the tree for nodes matching a predicate, key, or range.
|
|
397
|
+
* @remarks This is an optimized search for a BST. If searching by key or range, it prunes branches.
|
|
398
|
+
* Time O(H + M) for key/range search (H=height, M=matches). O(N) for predicate search.
|
|
399
|
+
* Space O(log N) for the stack.
|
|
400
|
+
*
|
|
401
|
+
* @template C - The type of the callback function.
|
|
402
|
+
* @param keyNodeEntryOrPredicate - The key, node, entry, predicate, or range to search for.
|
|
403
|
+
* @param [onlyOne=false] - If true, stops after finding the first match.
|
|
404
|
+
* @param [callback=this._DEFAULT_NODE_CALLBACK] - A function to call on matching nodes.
|
|
405
|
+
* @param [startNode=this._root] - The node to start the search from.
|
|
406
|
+
* @param [iterationType=this.iterationType] - Whether to use 'RECURSIVE' or 'ITERATIVE' search.
|
|
407
|
+
* @returns An array of results from the callback function for each matching node.
|
|
408
|
+
*/
|
|
409
|
+
override search<C extends NodeCallback<BSTNode<K, V>>>(
|
|
410
|
+
keyNodeEntryOrPredicate:
|
|
411
|
+
| K
|
|
412
|
+
| BSTNode<K, V>
|
|
413
|
+
| [K | null | undefined, V | undefined]
|
|
414
|
+
| null
|
|
415
|
+
| undefined
|
|
416
|
+
| NodePredicate<BSTNode<K, V>>
|
|
417
|
+
| Range<K>,
|
|
418
|
+
onlyOne = false,
|
|
419
|
+
callback: C = this._DEFAULT_NODE_CALLBACK as C,
|
|
420
|
+
startNode: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
|
|
421
|
+
iterationType: IterationType = this.iterationType
|
|
422
|
+
): ReturnType<C>[] {
|
|
423
|
+
if (keyNodeEntryOrPredicate === undefined) return [];
|
|
424
|
+
if (keyNodeEntryOrPredicate === null) return [];
|
|
425
|
+
startNode = this.ensureNode(startNode);
|
|
426
|
+
if (!startNode) return [];
|
|
427
|
+
|
|
428
|
+
let predicate: NodePredicate<BSTNode<K, V>>;
|
|
429
|
+
const isRange = this.isRange(keyNodeEntryOrPredicate);
|
|
430
|
+
|
|
431
|
+
if (isRange) {
|
|
432
|
+
predicate = node => {
|
|
433
|
+
if (!node) return false;
|
|
434
|
+
return (keyNodeEntryOrPredicate as Range<K>).isInRange(node.key, this._comparator);
|
|
435
|
+
};
|
|
436
|
+
} else {
|
|
437
|
+
predicate = this._ensurePredicate(keyNodeEntryOrPredicate);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Optimization: Pruning logic
|
|
441
|
+
const shouldVisitLeft = (cur: BSTNode<K, V> | null | undefined) => {
|
|
442
|
+
if (!cur) return false;
|
|
443
|
+
if (!this.isRealNode(cur.left)) return false;
|
|
444
|
+
if (isRange) {
|
|
445
|
+
// Range search: Only go left if the current key is >= the lower bound
|
|
446
|
+
const range = keyNodeEntryOrPredicate as Range<K>;
|
|
447
|
+
const leftS = this.isReverse ? range.high : range.low;
|
|
448
|
+
const leftI = this.isReverse ? range.includeHigh : range.includeLow;
|
|
449
|
+
return (leftI && this._compare(cur.key, leftS) >= 0) || (!leftI && this._compare(cur.key, leftS) > 0);
|
|
450
|
+
}
|
|
451
|
+
if (!isRange && !this._isPredicate(keyNodeEntryOrPredicate)) {
|
|
452
|
+
// Key search: Only go left if current key > target key
|
|
453
|
+
const benchmarkKey = this._extractKey(keyNodeEntryOrPredicate);
|
|
454
|
+
return benchmarkKey !== null && benchmarkKey !== undefined && this._compare(cur.key, benchmarkKey) > 0;
|
|
455
|
+
}
|
|
456
|
+
return true; // Predicate search: must visit all
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
const shouldVisitRight = (cur: BSTNode<K, V> | null | undefined) => {
|
|
460
|
+
if (!cur) return false;
|
|
461
|
+
if (!this.isRealNode(cur.right)) return false;
|
|
462
|
+
if (isRange) {
|
|
463
|
+
// Range search: Only go right if current key <= upper bound
|
|
464
|
+
const range = keyNodeEntryOrPredicate as Range<K>;
|
|
465
|
+
const rightS = this.isReverse ? range.low : range.high;
|
|
466
|
+
const rightI = this.isReverse ? range.includeLow : range.includeHigh;
|
|
467
|
+
return (rightI && this._compare(cur.key, rightS) <= 0) || (!rightI && this._compare(cur.key, rightS) < 0);
|
|
468
|
+
}
|
|
469
|
+
if (!isRange && !this._isPredicate(keyNodeEntryOrPredicate)) {
|
|
470
|
+
// Key search: Only go right if current key < target key
|
|
471
|
+
const benchmarkKey = this._extractKey(keyNodeEntryOrPredicate);
|
|
472
|
+
return benchmarkKey !== null && benchmarkKey !== undefined && this._compare(cur.key, benchmarkKey) < 0;
|
|
473
|
+
}
|
|
474
|
+
return true; // Predicate search: must visit all
|
|
475
|
+
};
|
|
476
|
+
|
|
477
|
+
return super._dfs(
|
|
478
|
+
callback,
|
|
479
|
+
'IN', // In-order is efficient for range/key search
|
|
480
|
+
onlyOne,
|
|
481
|
+
startNode,
|
|
482
|
+
iterationType,
|
|
483
|
+
false,
|
|
484
|
+
shouldVisitLeft,
|
|
485
|
+
shouldVisitRight,
|
|
486
|
+
() => true, // shouldVisitRoot (always visit)
|
|
487
|
+
cur => !!cur && predicate(cur) // shouldProcessRoot (only process if predicate matches)
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/**
|
|
492
|
+
* Performs an optimized search for nodes within a given key range.
|
|
493
|
+
* @remarks Time O(H + M), where H is tree height and M is the number of matches.
|
|
494
|
+
*
|
|
495
|
+
* @template C - The type of the callback function.
|
|
496
|
+
* @param range - A `Range` object or a `[low, high]` tuple.
|
|
497
|
+
* @param [callback=this._DEFAULT_NODE_CALLBACK] - A function to call on matching nodes.
|
|
498
|
+
* @param [startNode=this._root] - The node to start the search from.
|
|
499
|
+
* @param [iterationType=this.iterationType] - The traversal method.
|
|
500
|
+
* @returns An array of callback results.
|
|
501
|
+
*/
|
|
502
|
+
rangeSearch<C extends NodeCallback<BSTNode<K, V>>>(
|
|
503
|
+
range: Range<K> | [K, K],
|
|
504
|
+
callback: C = this._DEFAULT_NODE_CALLBACK as C,
|
|
505
|
+
startNode: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
|
|
506
|
+
iterationType: IterationType = this.iterationType
|
|
507
|
+
) {
|
|
508
|
+
const searchRange: Range<K> = range instanceof Range ? range : new Range(range[0], range[1]);
|
|
509
|
+
return this.search(searchRange, false, callback, startNode, iterationType);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Adds a new node to the BST based on key comparison.
|
|
514
|
+
* @remarks Time O(log N), where H is tree height. O(N) worst-case (unbalanced tree), O(log N) average. Space O(1).
|
|
515
|
+
*
|
|
516
|
+
* @param keyNodeOrEntry - The key, node, or entry to add.
|
|
517
|
+
* @param [value] - The value, if providing just a key.
|
|
518
|
+
* @returns True if the addition was successful, false otherwise.
|
|
307
519
|
*/
|
|
308
520
|
override add(
|
|
309
521
|
keyNodeOrEntry: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
|
@@ -322,10 +534,12 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|
|
322
534
|
let current = this._root;
|
|
323
535
|
while (current !== undefined) {
|
|
324
536
|
if (this._compare(current.key, newNode.key) === 0) {
|
|
537
|
+
// Key exists, replace node
|
|
325
538
|
this._replaceNode(current, newNode);
|
|
326
539
|
if (this._isMapMode) this._setValue(current.key, newValue);
|
|
327
540
|
return true;
|
|
328
541
|
} else if (this._compare(current.key, newNode.key) > 0) {
|
|
542
|
+
// Go left
|
|
329
543
|
if (current.left === undefined) {
|
|
330
544
|
current.left = newNode;
|
|
331
545
|
if (this._isMapMode) this._setValue(newNode?.key, newValue);
|
|
@@ -334,6 +548,7 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|
|
334
548
|
}
|
|
335
549
|
if (current.left !== null) current = current.left;
|
|
336
550
|
} else {
|
|
551
|
+
// Go right
|
|
337
552
|
if (current.right === undefined) {
|
|
338
553
|
current.right = newNode;
|
|
339
554
|
if (this._isMapMode) this._setValue(newNode?.key, newValue);
|
|
@@ -343,30 +558,20 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|
|
343
558
|
if (current.right !== null) current = current.right;
|
|
344
559
|
}
|
|
345
560
|
}
|
|
346
|
-
|
|
347
561
|
return false;
|
|
348
562
|
}
|
|
349
563
|
|
|
350
564
|
/**
|
|
351
|
-
*
|
|
352
|
-
*
|
|
565
|
+
* Adds multiple items to the tree.
|
|
566
|
+
* @remarks If `isBalanceAdd` is true, sorts the input and builds a balanced tree. Time O(N log N) (due to sort and balanced add).
|
|
567
|
+
* If false, adds items one by one. Time O(N * H), which is O(N^2) worst-case.
|
|
568
|
+
* Space O(N) for sorting and recursion/iteration stack.
|
|
353
569
|
*
|
|
354
|
-
*
|
|
355
|
-
*
|
|
356
|
-
* @param
|
|
357
|
-
*
|
|
358
|
-
* @
|
|
359
|
-
* added. If provided, the values will be assigned to the corresponding keys or nodes in the same
|
|
360
|
-
* order. If not provided, undefined will be assigned as the value for each key or node.
|
|
361
|
-
* @param [isBalanceAdd=true] - A boolean flag indicating whether the tree should be balanced after
|
|
362
|
-
* adding the elements. If set to true, the tree will be balanced using a binary search tree
|
|
363
|
-
* algorithm. If set to false, the elements will be added without balancing the tree. The default
|
|
364
|
-
* value is true.
|
|
365
|
-
* @param {IterationType} iterationType - The `iterationType` parameter is an optional parameter that
|
|
366
|
-
* specifies the type of iteration to use when adding multiple keys or nodes to the binary search
|
|
367
|
-
* tree. It can have two possible values:
|
|
368
|
-
* @returns The function `addMany` returns an array of booleans indicating whether each element was
|
|
369
|
-
* successfully inserted into the data structure.
|
|
570
|
+
* @param keysNodesEntriesOrRaws - An iterable of items to add.
|
|
571
|
+
* @param [values] - An optional parallel iterable of values.
|
|
572
|
+
* @param [isBalanceAdd=true] - If true, builds a balanced tree from the items.
|
|
573
|
+
* @param [iterationType=this.iterationType] - The traversal method for balanced add (recursive or iterative).
|
|
574
|
+
* @returns An array of booleans indicating the success of each individual `add` operation.
|
|
370
575
|
*/
|
|
371
576
|
override addMany(
|
|
372
577
|
keysNodesEntriesOrRaws: Iterable<R | BTNRep<K, V, BSTNode<K, V>>>,
|
|
@@ -375,22 +580,19 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|
|
375
580
|
iterationType: IterationType = this.iterationType
|
|
376
581
|
): boolean[] {
|
|
377
582
|
const inserted: boolean[] = [];
|
|
378
|
-
|
|
379
|
-
let valuesIterator: Iterator<V | undefined> | undefined;
|
|
380
|
-
|
|
381
|
-
if (values) {
|
|
382
|
-
valuesIterator = values[Symbol.iterator]();
|
|
383
|
-
}
|
|
583
|
+
const valuesIterator: Iterator<V | undefined> | undefined = values?.[Symbol.iterator]();
|
|
384
584
|
|
|
385
585
|
if (!isBalanceAdd) {
|
|
586
|
+
// Standard O(N*H) insertion
|
|
386
587
|
for (let kve of keysNodesEntriesOrRaws) {
|
|
387
|
-
const
|
|
588
|
+
const val = valuesIterator?.next().value;
|
|
388
589
|
if (this.isRaw(kve)) kve = this._toEntryFn!(kve);
|
|
389
|
-
inserted.push(this.add(kve,
|
|
590
|
+
inserted.push(this.add(kve, val));
|
|
390
591
|
}
|
|
391
592
|
return inserted;
|
|
392
593
|
}
|
|
393
594
|
|
|
595
|
+
// Balanced O(N log N) insertion
|
|
394
596
|
const realBTNExemplars: {
|
|
395
597
|
key: R | K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined;
|
|
396
598
|
value: V | undefined;
|
|
@@ -399,50 +601,31 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|
|
399
601
|
|
|
400
602
|
let i = 0;
|
|
401
603
|
for (const kve of keysNodesEntriesOrRaws) {
|
|
402
|
-
realBTNExemplars.push({ key: kve, value: valuesIterator?.next().value, orgIndex: i });
|
|
403
|
-
i++;
|
|
604
|
+
realBTNExemplars.push({ key: kve, value: valuesIterator?.next().value, orgIndex: i++ });
|
|
404
605
|
}
|
|
405
606
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
value: V | undefined;
|
|
409
|
-
orgIndex: number;
|
|
410
|
-
}[] = [];
|
|
411
|
-
|
|
412
|
-
sorted = realBTNExemplars.sort(({ key: a }, { key: b }) => {
|
|
607
|
+
// Sort items by key
|
|
608
|
+
const sorted = realBTNExemplars.sort(({ key: a }, { key: b }) => {
|
|
413
609
|
let keyA: K | undefined | null, keyB: K | undefined | null;
|
|
414
610
|
if (this.isRaw(a)) keyA = this._toEntryFn!(a)[0];
|
|
415
611
|
else if (this.isEntry(a)) keyA = a[0];
|
|
416
612
|
else if (this.isRealNode(a)) keyA = a.key;
|
|
417
|
-
else
|
|
418
|
-
keyA = a as K;
|
|
419
|
-
}
|
|
613
|
+
else keyA = a as K;
|
|
420
614
|
|
|
421
615
|
if (this.isRaw(b)) keyB = this._toEntryFn!(b)[0];
|
|
422
616
|
else if (this.isEntry(b)) keyB = b[0];
|
|
423
617
|
else if (this.isRealNode(b)) keyB = b.key;
|
|
424
|
-
else
|
|
425
|
-
keyB = b as K;
|
|
426
|
-
}
|
|
618
|
+
else keyB = b as K;
|
|
427
619
|
|
|
428
|
-
if (keyA
|
|
429
|
-
return this._compare(keyA, keyB);
|
|
430
|
-
}
|
|
620
|
+
if (keyA != null && keyB != null) return this._compare(keyA, keyB);
|
|
431
621
|
return 0;
|
|
432
622
|
});
|
|
433
623
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
key: R | K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined;
|
|
437
|
-
value: V | undefined;
|
|
438
|
-
orgIndex: number;
|
|
439
|
-
}[]
|
|
440
|
-
) => {
|
|
624
|
+
// Recursive balanced build
|
|
625
|
+
const _dfs = (arr: typeof realBTNExemplars) => {
|
|
441
626
|
if (arr.length === 0) return;
|
|
442
|
-
|
|
443
627
|
const mid = Math.floor((arr.length - 1) / 2);
|
|
444
|
-
const { key, value } = arr[mid];
|
|
445
|
-
const { orgIndex } = arr[mid];
|
|
628
|
+
const { key, value, orgIndex } = arr[mid];
|
|
446
629
|
if (this.isRaw(key)) {
|
|
447
630
|
const entry = this._toEntryFn!(key);
|
|
448
631
|
inserted[orgIndex] = this.add(entry);
|
|
@@ -453,318 +636,44 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|
|
453
636
|
_dfs(arr.slice(mid + 1));
|
|
454
637
|
};
|
|
455
638
|
|
|
639
|
+
// Iterative balanced build
|
|
456
640
|
const _iterate = () => {
|
|
457
641
|
const n = sorted.length;
|
|
458
|
-
const stack: [
|
|
642
|
+
const stack: Array<[number, number]> = [[0, n - 1]];
|
|
459
643
|
while (stack.length > 0) {
|
|
460
644
|
const popped = stack.pop();
|
|
461
|
-
if (popped)
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
inserted[orgIndex] = this.add(key, value);
|
|
472
|
-
}
|
|
473
|
-
stack.push([m + 1, r]);
|
|
474
|
-
stack.push([l, m - 1]);
|
|
475
|
-
}
|
|
645
|
+
if (!popped) continue;
|
|
646
|
+
const [l, r] = popped;
|
|
647
|
+
if (l > r) continue;
|
|
648
|
+
const m = l + Math.floor((r - l) / 2);
|
|
649
|
+
const { key, value, orgIndex } = sorted[m];
|
|
650
|
+
if (this.isRaw(key)) {
|
|
651
|
+
const entry = this._toEntryFn!(key);
|
|
652
|
+
inserted[orgIndex] = this.add(entry);
|
|
653
|
+
} else {
|
|
654
|
+
inserted[orgIndex] = this.add(key, value);
|
|
476
655
|
}
|
|
656
|
+
stack.push([m + 1, r]);
|
|
657
|
+
stack.push([l, m - 1]);
|
|
477
658
|
}
|
|
478
659
|
};
|
|
479
660
|
|
|
480
|
-
if (iterationType === 'RECURSIVE')
|
|
481
|
-
|
|
482
|
-
} else {
|
|
483
|
-
_iterate();
|
|
484
|
-
}
|
|
661
|
+
if (iterationType === 'RECURSIVE') _dfs(sorted);
|
|
662
|
+
else _iterate();
|
|
485
663
|
|
|
486
664
|
return inserted;
|
|
487
665
|
}
|
|
488
666
|
|
|
489
667
|
/**
|
|
490
|
-
*
|
|
491
|
-
*
|
|
492
|
-
*
|
|
493
|
-
* The function `search` in TypeScript overrides the search behavior in a binary tree structure based
|
|
494
|
-
* on specified criteria.
|
|
495
|
-
* @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined | NodePredicate<BSTNode<K, V>>} keyNodeEntryOrPredicate - The
|
|
496
|
-
* `keyNodeEntryOrPredicate` parameter in the `override search` method can accept one of the
|
|
497
|
-
* following types:
|
|
498
|
-
* @param [onlyOne=false] - The `onlyOne` parameter is a boolean flag that determines whether the
|
|
499
|
-
* search should stop after finding the first matching node. If `onlyOne` is set to `true`, the
|
|
500
|
-
* search will return as soon as a matching node is found. If `onlyOne` is set to `false`, the
|
|
501
|
-
* @param {C} callback - The `callback` parameter in the `override search` function is a function
|
|
502
|
-
* that will be called on each node that matches the search criteria. It is of type `C`, which
|
|
503
|
-
* extends `NodeCallback<BSTNode<K, V> | null>`. The callback function should accept a node of type `BSTNode<K, V>` as its
|
|
504
|
-
* argument and
|
|
505
|
-
* @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the `override search`
|
|
506
|
-
* method represents the node from which the search operation will begin. It is the starting point
|
|
507
|
-
* for searching within the tree data structure. The method ensures that the `startNode` is a valid
|
|
508
|
-
* node before proceeding with the search operation. If the `
|
|
509
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `override search`
|
|
510
|
-
* function determines the type of iteration to be used during the search operation. It can have two
|
|
511
|
-
* possible values:
|
|
512
|
-
* @returns The `override search` method returns an array of values that match the search criteria
|
|
513
|
-
* specified by the input parameters. The method performs a search operation on a binary tree
|
|
514
|
-
* structure based on the provided key, predicate, and other options. The search results are
|
|
515
|
-
* collected in an array and returned as the output of the method.
|
|
516
|
-
*/
|
|
517
|
-
override search<C extends NodeCallback<BSTNode<K, V>>>(
|
|
518
|
-
keyNodeEntryOrPredicate:
|
|
519
|
-
| K
|
|
520
|
-
| BSTNode<K, V>
|
|
521
|
-
| [K | null | undefined, V | undefined]
|
|
522
|
-
| null
|
|
523
|
-
| undefined
|
|
524
|
-
| NodePredicate<BSTNode<K, V>>
|
|
525
|
-
| Range<K>,
|
|
526
|
-
onlyOne = false,
|
|
527
|
-
callback: C = this._DEFAULT_NODE_CALLBACK as C,
|
|
528
|
-
startNode: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
|
|
529
|
-
iterationType: IterationType = this.iterationType
|
|
530
|
-
): ReturnType<C>[] {
|
|
531
|
-
if (keyNodeEntryOrPredicate === undefined) return [];
|
|
532
|
-
if (keyNodeEntryOrPredicate === null) return [];
|
|
533
|
-
startNode = this.ensureNode(startNode);
|
|
534
|
-
if (!startNode) return [];
|
|
535
|
-
let predicate: NodePredicate<BSTNode<K, V>>;
|
|
536
|
-
|
|
537
|
-
const isRange = this.isRange(keyNodeEntryOrPredicate);
|
|
538
|
-
// Set predicate based on parameter type
|
|
539
|
-
if (isRange) {
|
|
540
|
-
predicate = node => {
|
|
541
|
-
if (!node) return false;
|
|
542
|
-
return keyNodeEntryOrPredicate.isInRange(node.key, this._comparator);
|
|
543
|
-
};
|
|
544
|
-
} else {
|
|
545
|
-
predicate = this._ensurePredicate(keyNodeEntryOrPredicate);
|
|
546
|
-
}
|
|
547
|
-
const shouldVisitLeft = (cur: BSTNode<K, V> | null | undefined) => {
|
|
548
|
-
if (!cur) return false;
|
|
549
|
-
if (!this.isRealNode(cur.left)) return false;
|
|
550
|
-
if (isRange) {
|
|
551
|
-
const range = keyNodeEntryOrPredicate;
|
|
552
|
-
const leftS = this.isReverse ? range.high : range.low;
|
|
553
|
-
const leftI = this.isReverse ? range.includeHigh : range.includeLow;
|
|
554
|
-
return (leftI && this._compare(cur.key, leftS) >= 0) || (!leftI && this._compare(cur.key, leftS) > 0);
|
|
555
|
-
}
|
|
556
|
-
if (!isRange && !this._isPredicate(keyNodeEntryOrPredicate)) {
|
|
557
|
-
const benchmarkKey = this._extractKey(keyNodeEntryOrPredicate);
|
|
558
|
-
return benchmarkKey !== null && benchmarkKey !== undefined && this._compare(cur.key, benchmarkKey) > 0;
|
|
559
|
-
}
|
|
560
|
-
return true;
|
|
561
|
-
};
|
|
562
|
-
|
|
563
|
-
const shouldVisitRight = (cur: BSTNode<K, V> | null | undefined) => {
|
|
564
|
-
if (!cur) return false;
|
|
565
|
-
if (!this.isRealNode(cur.right)) return false;
|
|
566
|
-
if (isRange) {
|
|
567
|
-
const range = keyNodeEntryOrPredicate;
|
|
568
|
-
const rightS = this.isReverse ? range.low : range.high;
|
|
569
|
-
const rightI = this.isReverse ? range.includeLow : range.includeLow;
|
|
570
|
-
|
|
571
|
-
return (rightI && this._compare(cur.key, rightS) <= 0) || (!rightI && this._compare(cur.key, rightS) < 0);
|
|
572
|
-
}
|
|
573
|
-
if (!isRange && !this._isPredicate(keyNodeEntryOrPredicate)) {
|
|
574
|
-
const benchmarkKey = this._extractKey(keyNodeEntryOrPredicate);
|
|
575
|
-
return benchmarkKey !== null && benchmarkKey !== undefined && this._compare(cur.key, benchmarkKey) < 0;
|
|
576
|
-
}
|
|
577
|
-
return true;
|
|
578
|
-
};
|
|
579
|
-
return super._dfs(
|
|
580
|
-
callback,
|
|
581
|
-
'IN',
|
|
582
|
-
onlyOne,
|
|
583
|
-
startNode,
|
|
584
|
-
iterationType,
|
|
585
|
-
false,
|
|
586
|
-
shouldVisitLeft,
|
|
587
|
-
shouldVisitRight,
|
|
588
|
-
() => true,
|
|
589
|
-
cur => {
|
|
590
|
-
if (cur) return predicate(cur);
|
|
591
|
-
return false;
|
|
592
|
-
}
|
|
593
|
-
);
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
/**
|
|
597
|
-
* Time Complexity: O(log n)
|
|
598
|
-
* Space Complexity: O(k + log n)
|
|
668
|
+
* Traverses the tree and returns nodes that are lesser or greater than a target node.
|
|
669
|
+
* @remarks Time O(N), as it performs a full traversal. Space O(log N) or O(N).
|
|
599
670
|
*
|
|
600
|
-
*
|
|
601
|
-
* @param
|
|
602
|
-
*
|
|
603
|
-
* @param
|
|
604
|
-
*
|
|
605
|
-
*
|
|
606
|
-
* data structure.
|
|
607
|
-
* @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the `rangeSearch`
|
|
608
|
-
* function represents the node from which the search for nodes within the specified range will
|
|
609
|
-
* begin. It is the starting point for the range search operation.
|
|
610
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `rangeSearch` function
|
|
611
|
-
* is used to specify the type of iteration to be performed during the search operation. It has a
|
|
612
|
-
* default value of `this.iterationType`, which suggests that it is likely a property of the class or
|
|
613
|
-
* object that the `rangeSearch`
|
|
614
|
-
* @returns The `rangeSearch` function is returning the result of calling the `search` method with
|
|
615
|
-
* the specified parameters.
|
|
616
|
-
*/
|
|
617
|
-
rangeSearch<C extends NodeCallback<BSTNode<K, V>>>(
|
|
618
|
-
range: Range<K> | [K, K],
|
|
619
|
-
callback: C = this._DEFAULT_NODE_CALLBACK as C,
|
|
620
|
-
startNode: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
|
|
621
|
-
iterationType: IterationType = this.iterationType
|
|
622
|
-
) {
|
|
623
|
-
const searchRange: Range<K> = range instanceof Range ? range : new Range(range[0], range[1]);
|
|
624
|
-
return this.search(searchRange, false, callback, startNode, iterationType);
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
/**
|
|
628
|
-
* Time Complexity: O(log n)
|
|
629
|
-
* Space Complexity: O(log n)
|
|
630
|
-
*
|
|
631
|
-
* This function retrieves a node based on a given keyNodeEntryOrPredicate within a binary search tree structure.
|
|
632
|
-
* @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined | NodePredicate<BSTNode<K, V>>} keyNodeEntryOrPredicate - The `keyNodeEntryOrPredicate`
|
|
633
|
-
* parameter can be of type `K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined `, `R`, or `NodePredicate<BSTNode<K, V>>`.
|
|
634
|
-
* @param {BSTNOptKeyOrNode<K, BSTNode<K, V>>} startNode - The `startNode` parameter in the `getNode` method
|
|
635
|
-
* is used to specify the starting point for searching nodes in the binary search tree. If no
|
|
636
|
-
* specific starting point is provided, the default value is set to `this._root`, which is the root
|
|
637
|
-
* node of the binary search tree.
|
|
638
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `getNode` method is a
|
|
639
|
-
* parameter that specifies the type of iteration to be used. It has a default value of
|
|
640
|
-
* `this.iterationType`, which means it will use the iteration type defined in the class instance if
|
|
641
|
-
* no value is provided when calling the method.
|
|
642
|
-
* @returns The `getNode` method is returning an optional binary search tree node (`OptNode<BSTNode<K, V>>`).
|
|
643
|
-
* It is using the `getNodes` method to find the node based on the provided keyNodeEntryOrPredicate, beginning at
|
|
644
|
-
* the specified root node (`startNode`) and using the specified iteration type. The method then
|
|
645
|
-
* returns the first node found or `undefined` if no node is found.
|
|
646
|
-
*/
|
|
647
|
-
override getNode(
|
|
648
|
-
keyNodeEntryOrPredicate:
|
|
649
|
-
| K
|
|
650
|
-
| BSTNode<K, V>
|
|
651
|
-
| [K | null | undefined, V | undefined]
|
|
652
|
-
| null
|
|
653
|
-
| undefined
|
|
654
|
-
| NodePredicate<BSTNode<K, V>>,
|
|
655
|
-
startNode: BSTNOptKeyOrNode<K, BSTNode<K, V>> = this._root,
|
|
656
|
-
iterationType: IterationType = this.iterationType
|
|
657
|
-
): OptNode<BSTNode<K, V>> {
|
|
658
|
-
return this.getNodes(keyNodeEntryOrPredicate, true, startNode, iterationType)[0] ?? undefined;
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
/**
|
|
662
|
-
* Time complexity: O(n)
|
|
663
|
-
* Space complexity: O(n)
|
|
664
|
-
*
|
|
665
|
-
* The function `dfs` in TypeScript overrides the base class method with default parameters and
|
|
666
|
-
* returns the result of the super class `dfs` method.
|
|
667
|
-
* @param {C} callback - The `callback` parameter is a function that will be called for each node
|
|
668
|
-
* visited during the Depth-First Search traversal. It is a generic type `C` that extends the
|
|
669
|
-
* `NodeCallback` interface for `BSTNode<K, V>`. The default value for `callback` is `this._
|
|
670
|
-
* @param {DFSOrderPattern} [pattern=IN] - The `pattern` parameter in the `override dfs` method
|
|
671
|
-
* specifies the order in which the Depth-First Search (DFS) traversal should be performed on the
|
|
672
|
-
* Binary Search Tree (BST). The possible values for the `pattern` parameter are:
|
|
673
|
-
* @param {boolean} [onlyOne=false] - The `onlyOne` parameter in the `override dfs` method is a
|
|
674
|
-
* boolean flag that indicates whether you want to stop the depth-first search traversal after
|
|
675
|
-
* finding the first matching node or continue searching for all matching nodes. If `onlyOne` is set
|
|
676
|
-
* to `true`, the traversal will stop after finding
|
|
677
|
-
* @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined} startNode -
|
|
678
|
-
* The `startNode` parameter in the `override dfs` method can be one of the following types:
|
|
679
|
-
* @param {IterationType} iterationType - The `iterationType` parameter in the `override dfs` method
|
|
680
|
-
* specifies the type of iteration to be performed during the Depth-First Search (DFS) traversal of a
|
|
681
|
-
* Binary Search Tree (BST). It is used to determine the order in which nodes are visited during the
|
|
682
|
-
* traversal. The possible values for `
|
|
683
|
-
* @returns The `override` function is returning the result of calling the `dfs` method from the
|
|
684
|
-
* superclass, with the provided arguments `callback`, `pattern`, `onlyOne`, `startNode`, and
|
|
685
|
-
* `iterationType`. The return type is an array of the return type of the callback function `C`.
|
|
686
|
-
*/
|
|
687
|
-
override dfs<C extends NodeCallback<BSTNode<K, V>>>(
|
|
688
|
-
callback: C = this._DEFAULT_NODE_CALLBACK as C,
|
|
689
|
-
pattern: DFSOrderPattern = 'IN',
|
|
690
|
-
onlyOne: boolean = false,
|
|
691
|
-
startNode: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
|
|
692
|
-
iterationType: IterationType = this.iterationType
|
|
693
|
-
): ReturnType<C>[] {
|
|
694
|
-
return super.dfs(callback, pattern, onlyOne, startNode, iterationType);
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
/**
|
|
698
|
-
* Time complexity: O(n)
|
|
699
|
-
* Space complexity: O(n)
|
|
700
|
-
*
|
|
701
|
-
* The function overrides the breadth-first search method and returns an array of the return types of
|
|
702
|
-
* the callback function.
|
|
703
|
-
* @param {C} callback - The `callback` parameter is a function that will be called for each node
|
|
704
|
-
* visited during the breadth-first search. It should take a single argument, which is the current
|
|
705
|
-
* node being visited, and it can return a value of any type.
|
|
706
|
-
* @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter is the starting
|
|
707
|
-
* point for the breadth-first search. It can be either a root node, a key-value pair, or an entry
|
|
708
|
-
* object. If no value is provided, the default value is the root of the tree.
|
|
709
|
-
* @param {IterationType} iterationType - The `iterationType` parameter is used to specify the type
|
|
710
|
-
* of iteration to be performed during the breadth-first search (BFS) traversal. It can have one of
|
|
711
|
-
* the following values:
|
|
712
|
-
* @returns an array of the return type of the callback function.
|
|
713
|
-
*/
|
|
714
|
-
override bfs<C extends NodeCallback<BSTNode<K, V>>>(
|
|
715
|
-
callback: C = this._DEFAULT_NODE_CALLBACK as C,
|
|
716
|
-
startNode: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
|
|
717
|
-
iterationType: IterationType = this.iterationType
|
|
718
|
-
): ReturnType<C>[] {
|
|
719
|
-
return super.bfs(callback, startNode, iterationType, false);
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
/**
|
|
723
|
-
* Time complexity: O(n)
|
|
724
|
-
* Space complexity: O(n)
|
|
725
|
-
*
|
|
726
|
-
* The function overrides the listLevels method from the superclass and returns an array of arrays
|
|
727
|
-
* containing the results of the callback function applied to each level of the tree.
|
|
728
|
-
* @param {C} callback - The `callback` parameter is a generic type `C` that extends
|
|
729
|
-
* `NodeCallback<BSTNode<K, V> | null>`. It represents a callback function that will be called for each node in the
|
|
730
|
-
* tree during the iteration process.
|
|
731
|
-
* @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter is the starting
|
|
732
|
-
* point for listing the levels of the binary tree. It can be either a root node of the tree, a
|
|
733
|
-
* key-value pair representing a node in the tree, or a key representing a node in the tree. If no
|
|
734
|
-
* value is provided, the root of
|
|
735
|
-
* @param {IterationType} iterationType - The `iterationType` parameter is used to specify the type
|
|
736
|
-
* of iteration to be performed on the tree. It can have one of the following values:
|
|
737
|
-
* @returns The method is returning a two-dimensional array of the return type of the callback
|
|
738
|
-
* function.
|
|
739
|
-
*/
|
|
740
|
-
override listLevels<C extends NodeCallback<BSTNode<K, V>>>(
|
|
741
|
-
callback: C = this._DEFAULT_NODE_CALLBACK as C,
|
|
742
|
-
startNode: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
|
|
743
|
-
iterationType: IterationType = this.iterationType
|
|
744
|
-
): ReturnType<C>[][] {
|
|
745
|
-
return super.listLevels(callback, startNode, iterationType, false);
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
/**
|
|
749
|
-
* Time complexity: O(n)
|
|
750
|
-
* Space complexity: O(n)
|
|
751
|
-
*
|
|
752
|
-
* The `lesserOrGreaterTraverse` function traverses a binary tree and applies a callback function to
|
|
753
|
-
* each node that meets a certain condition based on a target node and a comparison value.
|
|
754
|
-
* @param {C} callback - The `callback` parameter is a function that will be called for each node
|
|
755
|
-
* that meets the condition specified by the `lesserOrGreater` parameter. It takes a single argument,
|
|
756
|
-
* which is the current node being traversed, and returns a value of any type.
|
|
757
|
-
* @param {CP} lesserOrGreater - The `lesserOrGreater` parameter is used to determine whether to
|
|
758
|
-
* traverse nodes that are lesser, greater, or both than the `targetNode`. It accepts the values -1,
|
|
759
|
-
* 0, or 1, where:
|
|
760
|
-
* @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } targetNode - The `targetNode` parameter is the node in
|
|
761
|
-
* the binary tree that you want to start traversing from. It can be specified either by providing
|
|
762
|
-
* the key of the node, the node itself, or an entry containing the key and value of the node. If no
|
|
763
|
-
* `targetNode` is provided,
|
|
764
|
-
* @param {IterationType} iterationType - The `iterationType` parameter determines the type of
|
|
765
|
-
* traversal to be performed on the binary tree. It can have two possible values:
|
|
766
|
-
* @returns The function `lesserOrGreaterTraverse` returns an array of values of type
|
|
767
|
-
* `ReturnType<C>`, which is the return type of the callback function passed as an argument.
|
|
671
|
+
* @template C - The type of the callback function.
|
|
672
|
+
* @param [callback=this._DEFAULT_NODE_CALLBACK] - Function to call on matching nodes.
|
|
673
|
+
* @param [lesserOrGreater=-1] - -1 for lesser, 1 for greater, 0 for equal.
|
|
674
|
+
* @param [targetNode=this._root] - The node to compare against.
|
|
675
|
+
* @param [iterationType=this.iterationType] - The traversal method.
|
|
676
|
+
* @returns An array of callback results.
|
|
768
677
|
*/
|
|
769
678
|
lesserOrGreaterTraverse<C extends NodeCallback<BSTNode<K, V>>>(
|
|
770
679
|
callback: C = this._DEFAULT_NODE_CALLBACK as C,
|
|
@@ -774,20 +683,18 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|
|
774
683
|
): ReturnType<C>[] {
|
|
775
684
|
const targetNodeEnsured = this.ensureNode(targetNode);
|
|
776
685
|
const ans: ReturnType<NodeCallback<BSTNode<K, V>>>[] = [];
|
|
777
|
-
if (!this._root) return ans;
|
|
778
|
-
if (!targetNodeEnsured) return ans;
|
|
686
|
+
if (!this._root || !targetNodeEnsured) return ans;
|
|
779
687
|
|
|
780
688
|
const targetKey = targetNodeEnsured.key;
|
|
781
689
|
|
|
782
690
|
if (iterationType === 'RECURSIVE') {
|
|
783
691
|
const dfs = (cur: BSTNode<K, V>) => {
|
|
784
692
|
const compared = this._compare(cur.key, targetKey);
|
|
785
|
-
if (Math.sign(compared)
|
|
786
|
-
|
|
693
|
+
if (Math.sign(compared) == lesserOrGreater) ans.push(callback(cur));
|
|
694
|
+
|
|
787
695
|
if (this.isRealNode(cur.left)) dfs(cur.left);
|
|
788
696
|
if (this.isRealNode(cur.right)) dfs(cur.right);
|
|
789
697
|
};
|
|
790
|
-
|
|
791
698
|
dfs(this._root);
|
|
792
699
|
return ans;
|
|
793
700
|
} else {
|
|
@@ -796,8 +703,7 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|
|
796
703
|
const cur = queue.shift();
|
|
797
704
|
if (this.isRealNode(cur)) {
|
|
798
705
|
const compared = this._compare(cur.key, targetKey);
|
|
799
|
-
if (Math.sign(compared)
|
|
800
|
-
|
|
706
|
+
if (Math.sign(compared) == lesserOrGreater) ans.push(callback(cur));
|
|
801
707
|
if (this.isRealNode(cur.left)) queue.push(cur.left);
|
|
802
708
|
if (this.isRealNode(cur.right)) queue.push(cur.right);
|
|
803
709
|
}
|
|
@@ -807,83 +713,60 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|
|
807
713
|
}
|
|
808
714
|
|
|
809
715
|
/**
|
|
810
|
-
*
|
|
811
|
-
*
|
|
716
|
+
* Rebuilds the tree to be perfectly balanced.
|
|
717
|
+
* @remarks Time O(N) (O(N) for DFS, O(N) for sorted build). Space O(N) for node array and recursion stack.
|
|
812
718
|
*
|
|
813
|
-
*
|
|
814
|
-
*
|
|
815
|
-
* @param {IterationType} iterationType - The `iterationType` parameter is an optional parameter that
|
|
816
|
-
* specifies the type of iteration to use when building a balanced binary search tree. It has a
|
|
817
|
-
* default value of `this.iterationType`, which means it will use the iteration type specified in the
|
|
818
|
-
* current instance of the class.
|
|
819
|
-
* @returns The function `perfectlyBalance` returns a boolean value.
|
|
719
|
+
* @param [iterationType=this.iterationType] - The traversal method for the initial node export.
|
|
720
|
+
* @returns True if successful, false if the tree was empty.
|
|
820
721
|
*/
|
|
821
722
|
perfectlyBalance(iterationType: IterationType = this.iterationType): boolean {
|
|
822
|
-
const
|
|
823
|
-
|
|
723
|
+
const nodes = this.dfs(node => node, 'IN', false, this._root, iterationType);
|
|
724
|
+
const n = nodes.length;
|
|
824
725
|
this._clearNodes();
|
|
726
|
+
if (n === 0) return false;
|
|
727
|
+
|
|
728
|
+
// Build balanced tree from sorted array
|
|
729
|
+
const build = (l: number, r: number, parent?: BSTNode<K, V>): BSTNode<K, V> | undefined => {
|
|
730
|
+
if (l > r) return undefined;
|
|
731
|
+
const m = l + ((r - l) >> 1);
|
|
732
|
+
const root = nodes[m]! as BSTNode<K, V>;
|
|
733
|
+
const leftChild = build(l, m - 1, root);
|
|
734
|
+
const rightChild = build(m + 1, r, root);
|
|
735
|
+
root.left = leftChild;
|
|
736
|
+
root.right = rightChild;
|
|
737
|
+
root.parent = parent;
|
|
738
|
+
return root;
|
|
739
|
+
};
|
|
825
740
|
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
const m = l + Math.floor((r - l) / 2);
|
|
831
|
-
const midNode = sorted[m];
|
|
832
|
-
if (this._isMapMode && midNode !== null) this.add(midNode.key);
|
|
833
|
-
else if (midNode !== null) this.add([midNode.key, midNode.value]);
|
|
834
|
-
buildBalanceBST(l, m - 1);
|
|
835
|
-
buildBalanceBST(m + 1, r);
|
|
836
|
-
};
|
|
837
|
-
|
|
838
|
-
buildBalanceBST(0, n - 1);
|
|
839
|
-
return true;
|
|
840
|
-
} else {
|
|
841
|
-
const stack: [[number, number]] = [[0, n - 1]];
|
|
842
|
-
while (stack.length > 0) {
|
|
843
|
-
const popped = stack.pop();
|
|
844
|
-
if (popped) {
|
|
845
|
-
const [l, r] = popped;
|
|
846
|
-
if (l <= r) {
|
|
847
|
-
const m = l + Math.floor((r - l) / 2);
|
|
848
|
-
const midNode = sorted[m];
|
|
849
|
-
if (this._isMapMode && midNode !== null) this.add(midNode.key);
|
|
850
|
-
else if (midNode !== null) this.add([midNode.key, midNode.value]);
|
|
851
|
-
stack.push([m + 1, r]);
|
|
852
|
-
stack.push([l, m - 1]);
|
|
853
|
-
}
|
|
854
|
-
}
|
|
855
|
-
}
|
|
856
|
-
return true;
|
|
857
|
-
}
|
|
741
|
+
const newRoot = build(0, n - 1, undefined);
|
|
742
|
+
this._setRoot(newRoot);
|
|
743
|
+
this._size = n;
|
|
744
|
+
return true;
|
|
858
745
|
}
|
|
859
746
|
|
|
860
747
|
/**
|
|
861
|
-
*
|
|
862
|
-
*
|
|
748
|
+
* Checks if the tree meets the AVL balance condition (height difference <= 1).
|
|
749
|
+
* @remarks Time O(N), as it must visit every node to compute height. Space O(log N) for recursion or O(N) for iterative map.
|
|
863
750
|
*
|
|
864
|
-
*
|
|
865
|
-
*
|
|
866
|
-
* @param {IterationType} iterationType - The `iterationType` parameter is an optional parameter that
|
|
867
|
-
* specifies the type of iteration to use when checking if the AVL tree is balanced. It has a default
|
|
868
|
-
* value of `this.iterationType`, which means it will use the iteration type specified in the current
|
|
869
|
-
* instance of the AVL tree.
|
|
870
|
-
* @returns a boolean value.
|
|
751
|
+
* @param [iterationType=this.iterationType] - The traversal method.
|
|
752
|
+
* @returns True if the tree is AVL balanced, false otherwise.
|
|
871
753
|
*/
|
|
872
754
|
isAVLBalanced(iterationType: IterationType = this.iterationType): boolean {
|
|
873
755
|
if (!this._root) return true;
|
|
874
|
-
|
|
875
756
|
let balanced = true;
|
|
876
757
|
|
|
877
758
|
if (iterationType === 'RECURSIVE') {
|
|
759
|
+
// Recursive height check
|
|
878
760
|
const _height = (cur: BSTNode<K, V> | null | undefined): number => {
|
|
879
761
|
if (!cur) return 0;
|
|
880
|
-
const leftHeight = _height(cur.left)
|
|
881
|
-
|
|
762
|
+
const leftHeight = _height(cur.left);
|
|
763
|
+
const rightHeight = _height(cur.right);
|
|
882
764
|
if (Math.abs(leftHeight - rightHeight) > 1) balanced = false;
|
|
883
765
|
return Math.max(leftHeight, rightHeight) + 1;
|
|
884
766
|
};
|
|
885
767
|
_height(this._root);
|
|
886
768
|
} else {
|
|
769
|
+
// Iterative post-order height check
|
|
887
770
|
const stack: BSTNode<K, V>[] = [];
|
|
888
771
|
let node: OptNode<BSTNode<K, V>> = this._root,
|
|
889
772
|
last: OptNode<BSTNode<K, V>> = undefined;
|
|
@@ -909,107 +792,217 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
|
|
|
909
792
|
}
|
|
910
793
|
}
|
|
911
794
|
}
|
|
912
|
-
|
|
913
795
|
return balanced;
|
|
914
796
|
}
|
|
915
797
|
|
|
916
798
|
/**
|
|
917
|
-
*
|
|
918
|
-
*
|
|
799
|
+
* Creates a new BST by mapping each [key, value] pair to a new entry.
|
|
800
|
+
* @remarks Time O(N * H), where N is nodes in this tree, and H is height of the new tree during insertion.
|
|
801
|
+
* Space O(N) for the new tree.
|
|
919
802
|
*
|
|
920
|
-
*
|
|
921
|
-
*
|
|
922
|
-
* @
|
|
923
|
-
*
|
|
924
|
-
* the BST
|
|
925
|
-
* @param [
|
|
926
|
-
*
|
|
927
|
-
* Search Tree (BST) being created in the `map` method. These options could include configuration
|
|
928
|
-
* @param {any} [thisArg] - The `thisArg` parameter in the `override map` method is used to specify
|
|
929
|
-
* the value of `this` that should be used when executing the `callback` function. It allows you to
|
|
930
|
-
* set the context or scope in which the callback function will be called. This can be useful when
|
|
931
|
-
* you want
|
|
932
|
-
* @returns The `map` method is returning a new Binary Search Tree (`BST`) instance with the entries
|
|
933
|
-
* transformed by the provided callback function.
|
|
803
|
+
* @template MK - New key type.
|
|
804
|
+
* @template MV - New value type.
|
|
805
|
+
* @template MR - New raw type.
|
|
806
|
+
* @param callback - A function to map each [key, value] pair.
|
|
807
|
+
* @param [options] - Options for the new BST.
|
|
808
|
+
* @param [thisArg] - `this` context for the callback.
|
|
809
|
+
* @returns A new, mapped BST.
|
|
934
810
|
*/
|
|
935
|
-
override map(
|
|
811
|
+
override map<MK = K, MV = V, MR = any>(
|
|
936
812
|
callback: EntryCallback<K, V | undefined, [MK, MV]>,
|
|
937
|
-
options?:
|
|
938
|
-
thisArg?:
|
|
813
|
+
options?: Partial<BinaryTreeOptions<MK, MV, MR>>,
|
|
814
|
+
thisArg?: unknown
|
|
939
815
|
): BST<MK, MV, MR> {
|
|
940
|
-
const
|
|
816
|
+
const out = this._createLike<MK, MV, MR>([], options);
|
|
941
817
|
let index = 0;
|
|
818
|
+
// Iterates in-order
|
|
942
819
|
for (const [key, value] of this) {
|
|
943
|
-
|
|
820
|
+
out.add(callback.call(thisArg, key, value, index++, this));
|
|
821
|
+
}
|
|
822
|
+
return out;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
/**
|
|
826
|
+
* Deletes the first node found that satisfies the predicate.
|
|
827
|
+
* @remarks Performs an in-order traversal. Time O(N) worst-case (O(log N) to find + O(log N) to delete). Space O(log N) for stack.
|
|
828
|
+
*
|
|
829
|
+
* @param predicate - A function to test each [key, value] pair.
|
|
830
|
+
* @returns True if a node was deleted, false otherwise.
|
|
831
|
+
*/
|
|
832
|
+
deleteWhere(predicate: (key: K, value: V | undefined, index: number, tree: this) => boolean): boolean {
|
|
833
|
+
const stack: Array<BSTNode<K, V> | null | undefined> = [];
|
|
834
|
+
let cur = this._root as BSTNode<K, V> | null | undefined;
|
|
835
|
+
let index = 0;
|
|
836
|
+
|
|
837
|
+
// In-order traversal to find the node
|
|
838
|
+
while (stack.length > 0 || cur !== undefined) {
|
|
839
|
+
while (cur !== undefined && cur !== null) {
|
|
840
|
+
stack.push(cur);
|
|
841
|
+
cur = cur.left as BSTNode<K, V> | null | undefined;
|
|
842
|
+
}
|
|
843
|
+
const node = stack.pop() as BSTNode<K, V> | undefined;
|
|
844
|
+
if (!node) break;
|
|
845
|
+
|
|
846
|
+
const key = node.key as K;
|
|
847
|
+
const val = node.value as V | undefined;
|
|
848
|
+
if (predicate(key, val, index++, this)) {
|
|
849
|
+
return this._deleteByKey(key); // Found, now delete
|
|
850
|
+
}
|
|
851
|
+
cur = node.right as BSTNode<K, V> | null | undefined;
|
|
944
852
|
}
|
|
945
|
-
return
|
|
853
|
+
return false;
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
/**
|
|
857
|
+
* (Protected) Creates a new, empty instance of the same BST constructor.
|
|
858
|
+
* @remarks Time O(1)
|
|
859
|
+
*
|
|
860
|
+
* @template TK, TV, TR - Generic types for the new instance.
|
|
861
|
+
* @param [options] - Options for the new BST.
|
|
862
|
+
* @returns A new, empty BST.
|
|
863
|
+
*/
|
|
864
|
+
protected override _createInstance<TK = K, TV = V, TR = R>(options?: Partial<BSTOptions<TK, TV, TR>>): this {
|
|
865
|
+
const Ctor = this.constructor as unknown as new (
|
|
866
|
+
iter?: Iterable<TK | BSTNode<TK, TV> | [TK | null | undefined, TV | undefined] | null | undefined | TR>,
|
|
867
|
+
opts?: BSTOptions<TK, TV, TR>
|
|
868
|
+
) => BST<TK, TV, TR>;
|
|
869
|
+
return new Ctor([], { ...this._snapshotOptions<TK, TV, TR>(), ...(options ?? {}) }) as unknown as this;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
/**
|
|
873
|
+
* (Protected) Creates a new instance of the same BST constructor, potentially with different generic types.
|
|
874
|
+
* @remarks Time O(N log N) or O(N^2) (from constructor) due to processing the iterable.
|
|
875
|
+
*
|
|
876
|
+
* @template TK, TV, TR - Generic types for the new instance.
|
|
877
|
+
* @param [iter=[]] - An iterable to populate the new BST.
|
|
878
|
+
* @param [options] - Options for the new BST.
|
|
879
|
+
* @returns A new BST.
|
|
880
|
+
*/
|
|
881
|
+
protected override _createLike<TK = K, TV = V, TR = R>(
|
|
882
|
+
iter: Iterable<TK | BSTNode<TK, TV> | [TK | null | undefined, TV | undefined] | null | undefined | TR> = [],
|
|
883
|
+
options?: Partial<BSTOptions<TK, TV, TR>>
|
|
884
|
+
): BST<TK, TV, TR> {
|
|
885
|
+
const Ctor = this.constructor as unknown as new (
|
|
886
|
+
iter?: Iterable<TK | BSTNode<TK, TV> | [TK | null | undefined, TV | undefined] | null | undefined | TR>,
|
|
887
|
+
opts?: BSTOptions<TK, TV, TR>
|
|
888
|
+
) => BST<TK, TV, TR>;
|
|
889
|
+
return new Ctor(iter, { ...this._snapshotOptions<TK, TV, TR>(), ...(options ?? {}) });
|
|
946
890
|
}
|
|
947
891
|
|
|
948
892
|
/**
|
|
949
|
-
*
|
|
950
|
-
*
|
|
893
|
+
* (Protected) Snapshots the current BST's configuration options.
|
|
894
|
+
* @remarks Time O(1)
|
|
951
895
|
*
|
|
952
|
-
*
|
|
953
|
-
*
|
|
954
|
-
* @returns The `cloned` object is being returned.
|
|
896
|
+
* @template TK, TV, TR - Generic types for the options.
|
|
897
|
+
* @returns The options object.
|
|
955
898
|
*/
|
|
956
|
-
override
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
899
|
+
protected override _snapshotOptions<TK = K, TV = V, TR = R>(): BSTOptions<TK, TV, TR> {
|
|
900
|
+
return {
|
|
901
|
+
...super._snapshotOptions<TK, TV, TR>(),
|
|
902
|
+
specifyComparable: this.specifyComparable as BSTOptions<TK, TV, TR>['specifyComparable'],
|
|
903
|
+
isReverse: this.isReverse as BSTOptions<TK, TV, TR>['isReverse']
|
|
904
|
+
};
|
|
960
905
|
}
|
|
961
906
|
|
|
962
907
|
/**
|
|
963
|
-
*
|
|
964
|
-
*
|
|
908
|
+
* (Protected) Converts a key, node, or entry into a standardized [node, value] tuple.
|
|
909
|
+
* @remarks Time O(1)
|
|
965
910
|
*
|
|
966
|
-
*
|
|
967
|
-
* @param
|
|
968
|
-
*
|
|
969
|
-
* element.
|
|
970
|
-
* @param {V} [value] - The `value` parameter is an optional value of type `V`. It represents the
|
|
971
|
-
* value associated with a key in a key-value pair.
|
|
972
|
-
* @returns either a BSTNode<K, V> object or undefined.
|
|
911
|
+
* @param keyNodeOrEntry - The input item.
|
|
912
|
+
* @param [value] - An optional value (used if input is just a key).
|
|
913
|
+
* @returns A tuple of [node, value].
|
|
973
914
|
*/
|
|
974
915
|
protected override _keyValueNodeOrEntryToNodeAndValue(
|
|
975
916
|
keyNodeOrEntry: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
|
976
917
|
value?: V
|
|
977
918
|
): [OptNode<BSTNode<K, V>>, V | undefined] {
|
|
978
919
|
const [node, entryValue] = super._keyValueNodeOrEntryToNodeAndValue(keyNodeOrEntry, value);
|
|
979
|
-
if (node === null) return [undefined, undefined];
|
|
920
|
+
if (node === null) return [undefined, undefined]; // BST handles null differently (as undefined)
|
|
980
921
|
return [node, value ?? entryValue];
|
|
981
922
|
}
|
|
982
923
|
|
|
983
924
|
/**
|
|
984
|
-
*
|
|
985
|
-
*
|
|
925
|
+
* (Protected) Sets the root node and clears its parent reference.
|
|
926
|
+
* @remarks Time O(1)
|
|
986
927
|
*
|
|
987
|
-
*
|
|
988
|
-
* root.
|
|
989
|
-
* @param {OptNode<BSTNode<K, V>>} v - v is a parameter of type BSTNode<K, V> or undefined.
|
|
928
|
+
* @param v - The node to set as root.
|
|
990
929
|
*/
|
|
991
930
|
protected override _setRoot(v: OptNode<BSTNode<K, V>>) {
|
|
992
|
-
if (v)
|
|
993
|
-
v.parent = undefined;
|
|
994
|
-
}
|
|
931
|
+
if (v) v.parent = undefined;
|
|
995
932
|
this._root = v;
|
|
996
933
|
}
|
|
997
934
|
|
|
998
935
|
/**
|
|
999
|
-
*
|
|
1000
|
-
*
|
|
936
|
+
* (Protected) Compares two keys using the tree's comparator and reverse setting.
|
|
937
|
+
* @remarks Time O(1) (or O(C) if `specifyComparable` is used).
|
|
1001
938
|
*
|
|
1002
|
-
*
|
|
1003
|
-
*
|
|
1004
|
-
* @
|
|
1005
|
-
* `_compare` method.
|
|
1006
|
-
* @param {K} b - The parameter `b` in the `_compare` function is of type `K`.
|
|
1007
|
-
* @returns The `_compare` method is returning the result of the ternary expression. If `_isReverse`
|
|
1008
|
-
* is true, it returns the negation of the result of calling the `_comparator` function with
|
|
1009
|
-
* arguments `a` and `b`. If `_isReverse` is false, it returns the result of calling the
|
|
1010
|
-
* `_comparator` function with arguments `a` and `b`.
|
|
939
|
+
* @param a - The first key.
|
|
940
|
+
* @param b - The second key.
|
|
941
|
+
* @returns A number (1, -1, or 0) representing the comparison.
|
|
1011
942
|
*/
|
|
1012
943
|
protected _compare(a: K, b: K) {
|
|
1013
944
|
return this._isReverse ? -this._comparator(a, b) : this._comparator(a, b);
|
|
1014
945
|
}
|
|
946
|
+
|
|
947
|
+
/**
|
|
948
|
+
* (Private) Deletes a node by its key.
|
|
949
|
+
* @remarks Standard BST deletion algorithm. Time O(log N), O(N) worst-case. Space O(1).
|
|
950
|
+
*
|
|
951
|
+
* @param key - The key of the node to delete.
|
|
952
|
+
* @returns True if the node was found and deleted, false otherwise.
|
|
953
|
+
*/
|
|
954
|
+
private _deleteByKey(key: K): boolean {
|
|
955
|
+
let node = this._root as BSTNode<K, V> | undefined;
|
|
956
|
+
|
|
957
|
+
// 1. Find the node
|
|
958
|
+
while (node) {
|
|
959
|
+
const cmp = this._compare(node.key, key);
|
|
960
|
+
if (cmp === 0) break;
|
|
961
|
+
node = cmp > 0 ? (node.left as BSTNode<K, V> | undefined) : (node.right as BSTNode<K, V> | undefined);
|
|
962
|
+
}
|
|
963
|
+
if (!node) return false; // Not found
|
|
964
|
+
|
|
965
|
+
// Helper to replace node `u` with node `v`
|
|
966
|
+
const transplant = (u: BSTNode<K, V> | undefined, v: BSTNode<K, V> | undefined) => {
|
|
967
|
+
const p = u?.parent as BSTNode<K, V> | undefined;
|
|
968
|
+
if (!p) {
|
|
969
|
+
this._setRoot(v);
|
|
970
|
+
} else if (p.left === u) {
|
|
971
|
+
p.left = v;
|
|
972
|
+
} else {
|
|
973
|
+
p.right = v;
|
|
974
|
+
}
|
|
975
|
+
if (v) v.parent = p;
|
|
976
|
+
};
|
|
977
|
+
|
|
978
|
+
// Helper to find the minimum node in a subtree
|
|
979
|
+
const minNode = (x: BSTNode<K, V> | undefined): BSTNode<K, V> | undefined => {
|
|
980
|
+
if (!x) return undefined;
|
|
981
|
+
while (x.left !== undefined && x.left !== null) x = x.left as BSTNode<K, V>;
|
|
982
|
+
return x;
|
|
983
|
+
};
|
|
984
|
+
|
|
985
|
+
// 2. Perform deletion
|
|
986
|
+
if (node.left === undefined) {
|
|
987
|
+
// Case 1: No left child
|
|
988
|
+
transplant(node, node.right as BSTNode<K, V> | undefined);
|
|
989
|
+
} else if (node.right === undefined) {
|
|
990
|
+
// Case 2: No right child
|
|
991
|
+
transplant(node, node.left as BSTNode<K, V> | undefined);
|
|
992
|
+
} else {
|
|
993
|
+
// Case 3: Two children
|
|
994
|
+
const succ = minNode(node.right as BSTNode<K, V> | undefined)!; // Find successor
|
|
995
|
+
if (succ.parent !== node) {
|
|
996
|
+
transplant(succ, succ.right as BSTNode<K, V> | undefined);
|
|
997
|
+
succ.right = node.right as BSTNode<K, V> | undefined;
|
|
998
|
+
if (succ.right) (succ.right as BSTNode<K, V>).parent = succ;
|
|
999
|
+
}
|
|
1000
|
+
transplant(node, succ);
|
|
1001
|
+
succ.left = node.left as BSTNode<K, V> | undefined;
|
|
1002
|
+
if (succ.left) (succ.left as BSTNode<K, V>).parent = succ;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
this._size = Math.max(0, ((this as any)._size ?? 0) - 1);
|
|
1006
|
+
return true;
|
|
1007
|
+
}
|
|
1015
1008
|
}
|