binary-tree-typed 2.5.1 → 2.5.2
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/cjs/index.cjs +146 -52
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs-legacy/index.cjs +145 -51
- package/dist/cjs-legacy/index.cjs.map +1 -1
- package/dist/esm/index.mjs +146 -53
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm-legacy/index.mjs +145 -52
- package/dist/esm-legacy/index.mjs.map +1 -1
- package/dist/types/common/error.d.ts +9 -0
- package/dist/types/common/index.d.ts +1 -1
- package/dist/types/data-structures/binary-tree/avl-tree.d.ts +36 -0
- package/dist/types/data-structures/binary-tree/binary-indexed-tree.d.ts +42 -0
- package/dist/types/data-structures/binary-tree/binary-tree.d.ts +77 -2
- package/dist/types/data-structures/binary-tree/bst.d.ts +171 -0
- package/dist/types/data-structures/binary-tree/red-black-tree.d.ts +57 -0
- package/dist/types/data-structures/binary-tree/segment-tree.d.ts +18 -0
- package/dist/types/data-structures/binary-tree/tree-map.d.ts +409 -0
- package/dist/types/data-structures/binary-tree/tree-multi-map.d.ts +411 -6
- package/dist/types/data-structures/binary-tree/tree-multi-set.d.ts +339 -6
- package/dist/types/data-structures/binary-tree/tree-set.d.ts +391 -0
- package/dist/types/data-structures/graph/directed-graph.d.ts +30 -0
- package/dist/types/data-structures/graph/undirected-graph.d.ts +27 -0
- package/dist/types/data-structures/hash/hash-map.d.ts +33 -0
- package/dist/types/data-structures/heap/heap.d.ts +42 -0
- package/dist/types/data-structures/linked-list/doubly-linked-list.d.ts +51 -0
- package/dist/types/data-structures/linked-list/singly-linked-list.d.ts +45 -0
- package/dist/types/data-structures/linked-list/skip-linked-list.d.ts +54 -0
- package/dist/types/data-structures/matrix/matrix.d.ts +24 -0
- package/dist/types/data-structures/queue/deque.d.ts +45 -0
- package/dist/types/data-structures/queue/queue.d.ts +36 -0
- package/dist/types/data-structures/stack/stack.d.ts +30 -0
- package/dist/types/data-structures/trie/trie.d.ts +36 -0
- package/dist/types/types/data-structures/binary-tree/bst.d.ts +1 -0
- package/dist/types/types/data-structures/binary-tree/tree-map.d.ts +5 -0
- package/dist/types/types/data-structures/binary-tree/tree-multi-set.d.ts +4 -0
- package/dist/types/types/data-structures/binary-tree/tree-set.d.ts +4 -0
- package/dist/umd/binary-tree-typed.js +143 -50
- package/dist/umd/binary-tree-typed.js.map +1 -1
- package/dist/umd/binary-tree-typed.min.js +3 -3
- package/dist/umd/binary-tree-typed.min.js.map +1 -1
- package/package.json +2 -2
- package/src/common/error.ts +19 -1
- package/src/common/index.ts +1 -1
- package/src/data-structures/base/iterable-element-base.ts +3 -2
- package/src/data-structures/binary-tree/avl-tree.ts +47 -0
- package/src/data-structures/binary-tree/binary-indexed-tree.ts +46 -4
- package/src/data-structures/binary-tree/binary-tree.ts +79 -4
- package/src/data-structures/binary-tree/bst.ts +441 -6
- package/src/data-structures/binary-tree/red-black-tree.ts +73 -0
- package/src/data-structures/binary-tree/segment-tree.ts +18 -0
- package/src/data-structures/binary-tree/tree-map.ts +434 -9
- package/src/data-structures/binary-tree/tree-multi-map.ts +426 -5
- package/src/data-structures/binary-tree/tree-multi-set.ts +350 -6
- package/src/data-structures/binary-tree/tree-set.ts +410 -8
- package/src/data-structures/graph/abstract-graph.ts +2 -2
- package/src/data-structures/graph/directed-graph.ts +30 -0
- package/src/data-structures/graph/undirected-graph.ts +27 -0
- package/src/data-structures/hash/hash-map.ts +35 -4
- package/src/data-structures/heap/heap.ts +46 -4
- package/src/data-structures/heap/max-heap.ts +2 -2
- package/src/data-structures/linked-list/doubly-linked-list.ts +51 -0
- package/src/data-structures/linked-list/singly-linked-list.ts +45 -0
- package/src/data-structures/linked-list/skip-linked-list.ts +59 -5
- package/src/data-structures/matrix/matrix.ts +33 -9
- package/src/data-structures/priority-queue/max-priority-queue.ts +2 -2
- package/src/data-structures/queue/deque.ts +45 -0
- package/src/data-structures/queue/queue.ts +36 -0
- package/src/data-structures/stack/stack.ts +30 -0
- package/src/data-structures/trie/trie.ts +38 -2
- package/src/types/data-structures/binary-tree/bst.ts +1 -0
- package/src/types/data-structures/binary-tree/tree-map.ts +6 -0
- package/src/types/data-structures/binary-tree/tree-multi-set.ts +5 -0
- package/src/types/data-structures/binary-tree/tree-set.ts +5 -0
|
@@ -26,7 +26,7 @@ import { BinaryTree } from './binary-tree';
|
|
|
26
26
|
import { IBinaryTree } from '../../interfaces';
|
|
27
27
|
import { Queue } from '../queue';
|
|
28
28
|
import { isComparable } from '../../utils';
|
|
29
|
-
import { ERR, Range } from '../../common';
|
|
29
|
+
import { ERR, Range, raise } from '../../common';
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
32
|
* Represents a Node in a Binary Search Tree.
|
|
@@ -345,6 +345,9 @@ export class BST<K = any, V = any, R = any> extends BinaryTree<K, V, R> implemen
|
|
|
345
345
|
} else {
|
|
346
346
|
this._comparator = this._createDefaultComparator();
|
|
347
347
|
}
|
|
348
|
+
if (options.enableOrderStatistic) {
|
|
349
|
+
this._enableOrderStatistic = true;
|
|
350
|
+
}
|
|
348
351
|
} else {
|
|
349
352
|
this._comparator = this._createDefaultComparator();
|
|
350
353
|
}
|
|
@@ -354,6 +357,8 @@ export class BST<K = any, V = any, R = any> extends BinaryTree<K, V, R> implemen
|
|
|
354
357
|
|
|
355
358
|
protected override _root?: BSTNode<K, V> = undefined;
|
|
356
359
|
|
|
360
|
+
protected _enableOrderStatistic: boolean = false;
|
|
361
|
+
|
|
357
362
|
/**
|
|
358
363
|
* Gets the root node of the tree.
|
|
359
364
|
* @remarks Time O(1)
|
|
@@ -491,6 +496,12 @@ export class BST<K = any, V = any, R = any> extends BinaryTree<K, V, R> implemen
|
|
|
491
496
|
|
|
492
497
|
|
|
493
498
|
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
|
|
494
505
|
|
|
495
506
|
|
|
496
507
|
|
|
@@ -587,6 +598,12 @@ export class BST<K = any, V = any, R = any> extends BinaryTree<K, V, R> implemen
|
|
|
587
598
|
|
|
588
599
|
|
|
589
600
|
|
|
601
|
+
|
|
602
|
+
|
|
603
|
+
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
|
|
590
607
|
|
|
591
608
|
|
|
592
609
|
|
|
@@ -679,6 +696,12 @@ export class BST<K = any, V = any, R = any> extends BinaryTree<K, V, R> implemen
|
|
|
679
696
|
|
|
680
697
|
|
|
681
698
|
|
|
699
|
+
|
|
700
|
+
|
|
701
|
+
|
|
702
|
+
|
|
703
|
+
|
|
704
|
+
|
|
682
705
|
|
|
683
706
|
|
|
684
707
|
|
|
@@ -783,6 +806,12 @@ export class BST<K = any, V = any, R = any> extends BinaryTree<K, V, R> implemen
|
|
|
783
806
|
|
|
784
807
|
|
|
785
808
|
|
|
809
|
+
|
|
810
|
+
|
|
811
|
+
|
|
812
|
+
|
|
813
|
+
|
|
814
|
+
|
|
786
815
|
|
|
787
816
|
|
|
788
817
|
|
|
@@ -906,6 +935,12 @@ export class BST<K = any, V = any, R = any> extends BinaryTree<K, V, R> implemen
|
|
|
906
935
|
|
|
907
936
|
|
|
908
937
|
|
|
938
|
+
|
|
939
|
+
|
|
940
|
+
|
|
941
|
+
|
|
942
|
+
|
|
943
|
+
|
|
909
944
|
|
|
910
945
|
|
|
911
946
|
|
|
@@ -1101,6 +1136,9 @@ export class BST<K = any, V = any, R = any> extends BinaryTree<K, V, R> implemen
|
|
|
1101
1136
|
|
|
1102
1137
|
|
|
1103
1138
|
|
|
1139
|
+
|
|
1140
|
+
|
|
1141
|
+
|
|
1104
1142
|
|
|
1105
1143
|
|
|
1106
1144
|
|
|
@@ -1140,6 +1178,232 @@ export class BST<K = any, V = any, R = any> extends BinaryTree<K, V, R> implemen
|
|
|
1140
1178
|
return this.search(searchRange, false, callback, startNode, iterationType);
|
|
1141
1179
|
}
|
|
1142
1180
|
|
|
1181
|
+
// ─── Order-Statistic Methods ───────────────────────────
|
|
1182
|
+
|
|
1183
|
+
/**
|
|
1184
|
+
* Returns the element at the k-th position in tree order (0-indexed).
|
|
1185
|
+
* @remarks Time O(log n), Space O(1) iterative / O(log n) recursive. Requires `enableOrderStatistic: true`.
|
|
1186
|
+
* Tree order is defined by the comparator — ascending by default, but respects custom comparators (e.g. descending).
|
|
1187
|
+
*
|
|
1188
|
+
* @param k - The 0-based position in tree order (0 = first element).
|
|
1189
|
+
* @returns The key at position k, or `undefined` if out of bounds.
|
|
1190
|
+
* @example
|
|
1191
|
+
* // Order-statistic on BST
|
|
1192
|
+
* const tree = new BST<number>([30, 10, 50, 20, 40], { enableOrderStatistic: true });
|
|
1193
|
+
* console.log(tree.getByRank(0)); // 10;
|
|
1194
|
+
* console.log(tree.getByRank(4)); // 50;
|
|
1195
|
+
* console.log(tree.getRank(30)); // 2;
|
|
1196
|
+
*/
|
|
1197
|
+
getByRank(k: number): K | undefined;
|
|
1198
|
+
|
|
1199
|
+
/**
|
|
1200
|
+
* Returns the element at the k-th position in tree order and applies a callback.
|
|
1201
|
+
* @remarks Time O(log n), Space O(1) iterative / O(log n) recursive. Requires `enableOrderStatistic: true`.
|
|
1202
|
+
*
|
|
1203
|
+
* @param k - The 0-based position in tree order (0 = first element).
|
|
1204
|
+
* @param callback - Callback to apply to the found node.
|
|
1205
|
+
* @param iterationType - Iteration strategy ('ITERATIVE' or 'RECURSIVE').
|
|
1206
|
+
* @returns The callback result, or `undefined` if out of bounds.
|
|
1207
|
+
*/
|
|
1208
|
+
getByRank<C extends NodeCallback<BSTNode<K, V>>>(
|
|
1209
|
+
k: number,
|
|
1210
|
+
callback: C,
|
|
1211
|
+
iterationType?: IterationType
|
|
1212
|
+
): ReturnType<C> | undefined;
|
|
1213
|
+
|
|
1214
|
+
getByRank<C extends NodeCallback<BSTNode<K, V>>>(
|
|
1215
|
+
k: number,
|
|
1216
|
+
callback: C = this._DEFAULT_NODE_CALLBACK as C,
|
|
1217
|
+
iterationType: IterationType = this.iterationType
|
|
1218
|
+
): K | undefined | ReturnType<C> | undefined {
|
|
1219
|
+
if (!this._enableOrderStatistic) {
|
|
1220
|
+
raise(Error, ERR.orderStatisticNotEnabled('getByRank'));
|
|
1221
|
+
}
|
|
1222
|
+
if (k < 0 || k >= this._size) return undefined;
|
|
1223
|
+
|
|
1224
|
+
let actualCallback: C | undefined = undefined;
|
|
1225
|
+
let actualIterationType: IterationType = this.iterationType;
|
|
1226
|
+
|
|
1227
|
+
if (typeof callback === 'string') {
|
|
1228
|
+
actualIterationType = callback;
|
|
1229
|
+
} else if (callback) {
|
|
1230
|
+
actualCallback = callback;
|
|
1231
|
+
if (iterationType) {
|
|
1232
|
+
actualIterationType = iterationType;
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
const node = actualIterationType === 'RECURSIVE'
|
|
1237
|
+
? this._getByRankRecursive(this._root, k)
|
|
1238
|
+
: this._getByRankIterative(this._root, k);
|
|
1239
|
+
|
|
1240
|
+
if (!node) return undefined;
|
|
1241
|
+
return actualCallback ? actualCallback(node) : node.key;
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
/**
|
|
1245
|
+
* Returns the 0-based rank of a key (number of elements that precede it in tree order).
|
|
1246
|
+
* @remarks Time O(log n), Space O(1) iterative / O(log n) recursive. Requires `enableOrderStatistic: true`.
|
|
1247
|
+
* Tree order is defined by the comparator. When the key is not found, returns the insertion position.
|
|
1248
|
+
*
|
|
1249
|
+
* @param keyNodeEntryOrPredicate - The key, node, entry `[K, V]`, or predicate to find.
|
|
1250
|
+
* @returns The rank (0-indexed), or -1 if the tree is empty or input is invalid.
|
|
1251
|
+
*/
|
|
1252
|
+
getRank(
|
|
1253
|
+
keyNodeEntryOrPredicate:
|
|
1254
|
+
| K
|
|
1255
|
+
| BSTNode<K, V>
|
|
1256
|
+
| [K | null | undefined, V | undefined]
|
|
1257
|
+
| null
|
|
1258
|
+
| undefined
|
|
1259
|
+
| NodePredicate<BSTNode<K, V>>
|
|
1260
|
+
): number;
|
|
1261
|
+
|
|
1262
|
+
/**
|
|
1263
|
+
* Returns the 0-based rank (number of preceding elements in tree order) with explicit iteration type.
|
|
1264
|
+
* @remarks Time O(log n), Space O(1) iterative / O(log n) recursive. Requires `enableOrderStatistic: true`.
|
|
1265
|
+
*
|
|
1266
|
+
* @param keyNodeEntryOrPredicate - The key, node, entry, or predicate to find.
|
|
1267
|
+
* @param iterationType - Iteration strategy ('ITERATIVE' or 'RECURSIVE').
|
|
1268
|
+
* @returns The rank (0-indexed), or -1 if the tree is empty or input is invalid.
|
|
1269
|
+
*/
|
|
1270
|
+
getRank(
|
|
1271
|
+
keyNodeEntryOrPredicate:
|
|
1272
|
+
| K
|
|
1273
|
+
| BSTNode<K, V>
|
|
1274
|
+
| [K | null | undefined, V | undefined]
|
|
1275
|
+
| null
|
|
1276
|
+
| undefined
|
|
1277
|
+
| NodePredicate<BSTNode<K, V>>,
|
|
1278
|
+
iterationType: IterationType
|
|
1279
|
+
): number;
|
|
1280
|
+
|
|
1281
|
+
getRank(
|
|
1282
|
+
keyNodeEntryOrPredicate:
|
|
1283
|
+
| K
|
|
1284
|
+
| BSTNode<K, V>
|
|
1285
|
+
| [K | null | undefined, V | undefined]
|
|
1286
|
+
| null
|
|
1287
|
+
| undefined
|
|
1288
|
+
| NodePredicate<BSTNode<K, V>>,
|
|
1289
|
+
iterationType: IterationType = this.iterationType
|
|
1290
|
+
): number {
|
|
1291
|
+
if (!this._enableOrderStatistic) {
|
|
1292
|
+
raise(Error, ERR.orderStatisticNotEnabled('getRank'));
|
|
1293
|
+
}
|
|
1294
|
+
if (!this._root || this._size === 0) return -1;
|
|
1295
|
+
|
|
1296
|
+
let actualIterationType: IterationType = this.iterationType;
|
|
1297
|
+
if (iterationType) actualIterationType = iterationType;
|
|
1298
|
+
|
|
1299
|
+
// Resolve key from input
|
|
1300
|
+
let key: K | undefined;
|
|
1301
|
+
if (typeof keyNodeEntryOrPredicate === 'function') {
|
|
1302
|
+
// Predicate: find first matching node
|
|
1303
|
+
const results = this.search(keyNodeEntryOrPredicate as NodePredicate<BSTNode<K, V>>, true);
|
|
1304
|
+
if (results.length === 0 || results[0] === undefined) return -1;
|
|
1305
|
+
key = results[0];
|
|
1306
|
+
} else if (keyNodeEntryOrPredicate === null || keyNodeEntryOrPredicate === undefined) {
|
|
1307
|
+
return -1;
|
|
1308
|
+
} else if (this.isNode(keyNodeEntryOrPredicate)) {
|
|
1309
|
+
key = keyNodeEntryOrPredicate.key;
|
|
1310
|
+
} else if (Array.isArray(keyNodeEntryOrPredicate)) {
|
|
1311
|
+
key = keyNodeEntryOrPredicate[0] ?? undefined;
|
|
1312
|
+
if (key === undefined || key === null) return -1;
|
|
1313
|
+
} else {
|
|
1314
|
+
key = keyNodeEntryOrPredicate as K;
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
if (key === undefined) return -1;
|
|
1318
|
+
|
|
1319
|
+
return actualIterationType === 'RECURSIVE'
|
|
1320
|
+
? this._getRankRecursive(this._root, key)
|
|
1321
|
+
: this._getRankIterative(this._root, key);
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
/**
|
|
1325
|
+
* Returns elements by position range in tree order (0-indexed, inclusive on both ends).
|
|
1326
|
+
* @remarks Time O(log n + k), Space O(k), where k = end - start + 1. Requires `enableOrderStatistic: true`.
|
|
1327
|
+
*
|
|
1328
|
+
* @param start - Start position (inclusive, 0-indexed). Clamped to 0 if negative.
|
|
1329
|
+
* @param end - End position (inclusive, 0-indexed). Clamped to size-1 if too large.
|
|
1330
|
+
* @returns Array of keys in tree order within the specified range.
|
|
1331
|
+
*/
|
|
1332
|
+
rangeByRank(start: number, end: number): (K | undefined)[];
|
|
1333
|
+
|
|
1334
|
+
/**
|
|
1335
|
+
* Returns elements by position range in tree order with callback and optional iteration type.
|
|
1336
|
+
* @remarks Time O(log n + k), Space O(k), where k = end - start + 1. Requires `enableOrderStatistic: true`.
|
|
1337
|
+
*
|
|
1338
|
+
* @param start - Start rank (inclusive, 0-indexed).
|
|
1339
|
+
* @param end - End rank (inclusive, 0-indexed).
|
|
1340
|
+
* @param callback - Callback to apply to each node in the range.
|
|
1341
|
+
* @param iterationType - Iteration strategy ('ITERATIVE' or 'RECURSIVE').
|
|
1342
|
+
* @returns Array of callback results for nodes in the rank range.
|
|
1343
|
+
*/
|
|
1344
|
+
rangeByRank<C extends NodeCallback<BSTNode<K, V>>>(
|
|
1345
|
+
start: number,
|
|
1346
|
+
end: number,
|
|
1347
|
+
callback: C,
|
|
1348
|
+
iterationType?: IterationType
|
|
1349
|
+
): ReturnType<C>[];
|
|
1350
|
+
|
|
1351
|
+
rangeByRank<C extends NodeCallback<BSTNode<K, V>>>(
|
|
1352
|
+
start: number,
|
|
1353
|
+
end: number,
|
|
1354
|
+
callback: C = this._DEFAULT_NODE_CALLBACK as C,
|
|
1355
|
+
iterationType: IterationType = this.iterationType
|
|
1356
|
+
): (K | undefined)[] | ReturnType<C>[] {
|
|
1357
|
+
if (!this._enableOrderStatistic) {
|
|
1358
|
+
raise(Error, ERR.orderStatisticNotEnabled('rangeByRank'));
|
|
1359
|
+
}
|
|
1360
|
+
if (this._size === 0) return [];
|
|
1361
|
+
|
|
1362
|
+
// Clamp
|
|
1363
|
+
const lo = Math.max(0, start);
|
|
1364
|
+
const hi = Math.min(this._size - 1, end);
|
|
1365
|
+
if (lo > hi) return [];
|
|
1366
|
+
|
|
1367
|
+
let actualCallback: C | undefined = undefined;
|
|
1368
|
+
let actualIterationType: IterationType = this.iterationType;
|
|
1369
|
+
|
|
1370
|
+
if (typeof callback === 'string') {
|
|
1371
|
+
actualIterationType = callback;
|
|
1372
|
+
} else if (callback) {
|
|
1373
|
+
actualCallback = callback;
|
|
1374
|
+
if (iterationType) {
|
|
1375
|
+
actualIterationType = iterationType;
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
const results: (K | undefined | ReturnType<C>)[] = [];
|
|
1380
|
+
const count = hi - lo + 1;
|
|
1381
|
+
|
|
1382
|
+
// Find the lo-th node, then in-order traverse count nodes
|
|
1383
|
+
const startNode = actualIterationType === 'RECURSIVE'
|
|
1384
|
+
? this._getByRankRecursive(this._root, lo)
|
|
1385
|
+
: this._getByRankIterative(this._root, lo);
|
|
1386
|
+
|
|
1387
|
+
if (!startNode) return [];
|
|
1388
|
+
|
|
1389
|
+
// In-order traversal from startNode collecting count elements
|
|
1390
|
+
let collected = 0;
|
|
1391
|
+
const cb = actualCallback ?? this._DEFAULT_NODE_CALLBACK as C;
|
|
1392
|
+
|
|
1393
|
+
// Use higher() to iterate — it's already O(log n) amortized per step
|
|
1394
|
+
let current: BSTNode<K, V> | undefined = startNode;
|
|
1395
|
+
while (current && collected < count) {
|
|
1396
|
+
results.push(cb(current));
|
|
1397
|
+
collected++;
|
|
1398
|
+
if (collected < count) {
|
|
1399
|
+
// Find next in-order node
|
|
1400
|
+
current = this._next(current);
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
return results as (K | undefined)[] | ReturnType<C>[];
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1143
1407
|
/**
|
|
1144
1408
|
* Adds a new node to the BST based on key comparison.
|
|
1145
1409
|
* @remarks Time O(log N), where H is tree height. O(N) worst-case (unbalanced tree), O(log N) average. Space O(1).
|
|
@@ -1225,6 +1489,15 @@ export class BST<K = any, V = any, R = any> extends BinaryTree<K, V, R> implemen
|
|
|
1225
1489
|
|
|
1226
1490
|
|
|
1227
1491
|
|
|
1492
|
+
|
|
1493
|
+
|
|
1494
|
+
|
|
1495
|
+
|
|
1496
|
+
|
|
1497
|
+
|
|
1498
|
+
|
|
1499
|
+
|
|
1500
|
+
|
|
1228
1501
|
|
|
1229
1502
|
|
|
1230
1503
|
|
|
@@ -1253,6 +1526,7 @@ export class BST<K = any, V = any, R = any> extends BinaryTree<K, V, R> implemen
|
|
|
1253
1526
|
this._setRoot(newNode);
|
|
1254
1527
|
if (this._isMapMode && this.isRealNode(newNode)) this._store.set(newNode.key, newNode);
|
|
1255
1528
|
this._size++;
|
|
1529
|
+
this._updateCount(newNode);
|
|
1256
1530
|
return true;
|
|
1257
1531
|
}
|
|
1258
1532
|
|
|
@@ -1269,6 +1543,7 @@ export class BST<K = any, V = any, R = any> extends BinaryTree<K, V, R> implemen
|
|
|
1269
1543
|
current.left = newNode;
|
|
1270
1544
|
if (this._isMapMode && this.isRealNode(newNode)) this._store.set(newNode.key, newNode);
|
|
1271
1545
|
this._size++;
|
|
1546
|
+
this._updateCountAlongPath(newNode);
|
|
1272
1547
|
return true;
|
|
1273
1548
|
}
|
|
1274
1549
|
if (current.left !== null) current = current.left;
|
|
@@ -1278,6 +1553,7 @@ export class BST<K = any, V = any, R = any> extends BinaryTree<K, V, R> implemen
|
|
|
1278
1553
|
current.right = newNode;
|
|
1279
1554
|
if (this._isMapMode && this.isRealNode(newNode)) this._store.set(newNode.key, newNode);
|
|
1280
1555
|
this._size++;
|
|
1556
|
+
this._updateCountAlongPath(newNode);
|
|
1281
1557
|
return true;
|
|
1282
1558
|
}
|
|
1283
1559
|
if (current.right !== null) current = current.right;
|
|
@@ -1344,6 +1620,12 @@ export class BST<K = any, V = any, R = any> extends BinaryTree<K, V, R> implemen
|
|
|
1344
1620
|
|
|
1345
1621
|
|
|
1346
1622
|
|
|
1623
|
+
|
|
1624
|
+
|
|
1625
|
+
|
|
1626
|
+
|
|
1627
|
+
|
|
1628
|
+
|
|
1347
1629
|
|
|
1348
1630
|
|
|
1349
1631
|
|
|
@@ -1483,6 +1765,9 @@ export class BST<K = any, V = any, R = any> extends BinaryTree<K, V, R> implemen
|
|
|
1483
1765
|
|
|
1484
1766
|
|
|
1485
1767
|
|
|
1768
|
+
|
|
1769
|
+
|
|
1770
|
+
|
|
1486
1771
|
|
|
1487
1772
|
|
|
1488
1773
|
|
|
@@ -1586,6 +1871,9 @@ export class BST<K = any, V = any, R = any> extends BinaryTree<K, V, R> implemen
|
|
|
1586
1871
|
|
|
1587
1872
|
|
|
1588
1873
|
|
|
1874
|
+
|
|
1875
|
+
|
|
1876
|
+
|
|
1589
1877
|
|
|
1590
1878
|
|
|
1591
1879
|
|
|
@@ -1688,6 +1976,9 @@ export class BST<K = any, V = any, R = any> extends BinaryTree<K, V, R> implemen
|
|
|
1688
1976
|
|
|
1689
1977
|
|
|
1690
1978
|
|
|
1979
|
+
|
|
1980
|
+
|
|
1981
|
+
|
|
1691
1982
|
|
|
1692
1983
|
|
|
1693
1984
|
|
|
@@ -1834,6 +2125,9 @@ export class BST<K = any, V = any, R = any> extends BinaryTree<K, V, R> implemen
|
|
|
1834
2125
|
|
|
1835
2126
|
|
|
1836
2127
|
|
|
2128
|
+
|
|
2129
|
+
|
|
2130
|
+
|
|
1837
2131
|
|
|
1838
2132
|
|
|
1839
2133
|
|
|
@@ -2036,6 +2330,9 @@ export class BST<K = any, V = any, R = any> extends BinaryTree<K, V, R> implemen
|
|
|
2036
2330
|
|
|
2037
2331
|
|
|
2038
2332
|
|
|
2333
|
+
|
|
2334
|
+
|
|
2335
|
+
|
|
2039
2336
|
|
|
2040
2337
|
|
|
2041
2338
|
|
|
@@ -2106,6 +2403,9 @@ export class BST<K = any, V = any, R = any> extends BinaryTree<K, V, R> implemen
|
|
|
2106
2403
|
|
|
2107
2404
|
|
|
2108
2405
|
|
|
2406
|
+
|
|
2407
|
+
|
|
2408
|
+
|
|
2109
2409
|
|
|
2110
2410
|
|
|
2111
2411
|
|
|
@@ -2225,6 +2525,12 @@ export class BST<K = any, V = any, R = any> extends BinaryTree<K, V, R> implemen
|
|
|
2225
2525
|
|
|
2226
2526
|
|
|
2227
2527
|
|
|
2528
|
+
|
|
2529
|
+
|
|
2530
|
+
|
|
2531
|
+
|
|
2532
|
+
|
|
2533
|
+
|
|
2228
2534
|
|
|
2229
2535
|
|
|
2230
2536
|
|
|
@@ -2331,15 +2637,13 @@ export class BST<K = any, V = any, R = any> extends BinaryTree<K, V, R> implemen
|
|
|
2331
2637
|
if (a instanceof Date && b instanceof Date) {
|
|
2332
2638
|
const ta = a.getTime();
|
|
2333
2639
|
const tb = b.getTime();
|
|
2334
|
-
if (Number.isNaN(ta) || Number.isNaN(tb))
|
|
2640
|
+
if (Number.isNaN(ta) || Number.isNaN(tb)) raise(TypeError, ERR.invalidDate('BST'));
|
|
2335
2641
|
return ta > tb ? 1 : ta < tb ? -1 : 0;
|
|
2336
2642
|
}
|
|
2337
2643
|
|
|
2338
2644
|
// If keys are objects and no comparator is provided, throw an error
|
|
2339
2645
|
if (typeof a === 'object' || typeof b === 'object') {
|
|
2340
|
-
|
|
2341
|
-
ERR.comparatorRequired('BST')
|
|
2342
|
-
);
|
|
2646
|
+
raise(TypeError, ERR.comparatorRequired('BST'));
|
|
2343
2647
|
}
|
|
2344
2648
|
|
|
2345
2649
|
// Default: keys are equal (fallback case)
|
|
@@ -2804,7 +3108,8 @@ export class BST<K = any, V = any, R = any> extends BinaryTree<K, V, R> implemen
|
|
|
2804
3108
|
protected override _snapshotOptions<TK = K, TV = V, TR = R>(): BSTOptions<TK, TV, TR> {
|
|
2805
3109
|
return {
|
|
2806
3110
|
...super._snapshotOptions<TK, TV, TR>(),
|
|
2807
|
-
comparator: this._comparator as unknown as BSTOptions<TK, TV, TR>['comparator']
|
|
3111
|
+
comparator: this._comparator as unknown as BSTOptions<TK, TV, TR>['comparator'],
|
|
3112
|
+
enableOrderStatistic: this._enableOrderStatistic
|
|
2808
3113
|
};
|
|
2809
3114
|
}
|
|
2810
3115
|
|
|
@@ -2831,6 +3136,129 @@ export class BST<K = any, V = any, R = any> extends BinaryTree<K, V, R> implemen
|
|
|
2831
3136
|
*
|
|
2832
3137
|
* @param v - The node to set as root.
|
|
2833
3138
|
*/
|
|
3139
|
+
/**
|
|
3140
|
+
* (Protected) Recalculates the subtree count for a single node.
|
|
3141
|
+
* @remarks Time O(1). Only active when enableOrderStatistic is true.
|
|
3142
|
+
*/
|
|
3143
|
+
protected _updateCount(node: BSTNode<K, V>): void {
|
|
3144
|
+
if (!this._enableOrderStatistic) return;
|
|
3145
|
+
node._count = 1
|
|
3146
|
+
+ (this.isRealNode(node.left) ? node.left._count : 0)
|
|
3147
|
+
+ (this.isRealNode(node.right) ? node.right._count : 0);
|
|
3148
|
+
}
|
|
3149
|
+
|
|
3150
|
+
/**
|
|
3151
|
+
* (Protected) Updates subtree counts from a node up to the root.
|
|
3152
|
+
* @remarks Time O(log n). Only active when enableOrderStatistic is true.
|
|
3153
|
+
*/
|
|
3154
|
+
protected _updateCountAlongPath(node: OptNode<BSTNode<K, V>>): void {
|
|
3155
|
+
if (!this._enableOrderStatistic) return;
|
|
3156
|
+
let current = node;
|
|
3157
|
+
while (current) {
|
|
3158
|
+
this._updateCount(current);
|
|
3159
|
+
current = current.parent as BSTNode<K, V> | undefined;
|
|
3160
|
+
}
|
|
3161
|
+
}
|
|
3162
|
+
|
|
3163
|
+
/**
|
|
3164
|
+
* (Protected) Finds the node at position k in tree order (iterative).
|
|
3165
|
+
* @remarks Time O(log n), Space O(1)
|
|
3166
|
+
*/
|
|
3167
|
+
protected _getByRankIterative(node: OptNode<BSTNode<K, V>>, k: number): BSTNode<K, V> | undefined {
|
|
3168
|
+
let current = node;
|
|
3169
|
+
let remaining = k;
|
|
3170
|
+
while (current) {
|
|
3171
|
+
const leftCount = this.isRealNode(current.left) ? current.left._count : 0;
|
|
3172
|
+
if (remaining < leftCount) {
|
|
3173
|
+
current = current.left as BSTNode<K, V> | undefined;
|
|
3174
|
+
} else if (remaining === leftCount) {
|
|
3175
|
+
return current;
|
|
3176
|
+
} else {
|
|
3177
|
+
remaining = remaining - leftCount - 1;
|
|
3178
|
+
current = current.right as BSTNode<K, V> | undefined;
|
|
3179
|
+
}
|
|
3180
|
+
}
|
|
3181
|
+
return undefined;
|
|
3182
|
+
}
|
|
3183
|
+
|
|
3184
|
+
/**
|
|
3185
|
+
* (Protected) Finds the node at position k in tree order (recursive).
|
|
3186
|
+
* @remarks Time O(log n), Space O(log n) call stack
|
|
3187
|
+
*/
|
|
3188
|
+
protected _getByRankRecursive(node: OptNode<BSTNode<K, V>>, k: number): BSTNode<K, V> | undefined {
|
|
3189
|
+
if (!node) return undefined;
|
|
3190
|
+
const leftCount = this.isRealNode(node.left) ? node.left._count : 0;
|
|
3191
|
+
if (k < leftCount) return this._getByRankRecursive(node.left as BSTNode<K, V> | undefined, k);
|
|
3192
|
+
if (k === leftCount) return node;
|
|
3193
|
+
return this._getByRankRecursive(node.right as BSTNode<K, V> | undefined, k - leftCount - 1);
|
|
3194
|
+
}
|
|
3195
|
+
|
|
3196
|
+
/**
|
|
3197
|
+
* (Protected) Computes the rank of a key iteratively.
|
|
3198
|
+
* @remarks Time O(log n), Space O(1)
|
|
3199
|
+
*/
|
|
3200
|
+
protected _getRankIterative(node: OptNode<BSTNode<K, V>>, key: K): number {
|
|
3201
|
+
let rank = 0;
|
|
3202
|
+
let current = node;
|
|
3203
|
+
while (this.isRealNode(current)) {
|
|
3204
|
+
const cmp = this._compare(current.key, key);
|
|
3205
|
+
if (cmp > 0) {
|
|
3206
|
+
// key < current.key, go left
|
|
3207
|
+
current = current.left as BSTNode<K, V> | undefined;
|
|
3208
|
+
} else if (cmp < 0) {
|
|
3209
|
+
// key > current.key
|
|
3210
|
+
rank += (this.isRealNode(current.left) ? current.left._count : 0) + 1;
|
|
3211
|
+
current = current.right as BSTNode<K, V> | undefined;
|
|
3212
|
+
} else {
|
|
3213
|
+
// Found
|
|
3214
|
+
rank += this.isRealNode(current.left) ? current.left._count : 0;
|
|
3215
|
+
return rank;
|
|
3216
|
+
}
|
|
3217
|
+
}
|
|
3218
|
+
// Key not found, rank = insertion position
|
|
3219
|
+
return rank;
|
|
3220
|
+
}
|
|
3221
|
+
|
|
3222
|
+
/**
|
|
3223
|
+
* (Protected) Computes the rank of a key recursively.
|
|
3224
|
+
* @remarks Time O(log n), Space O(log n) call stack
|
|
3225
|
+
*/
|
|
3226
|
+
protected _getRankRecursive(node: OptNode<BSTNode<K, V>>, key: K): number {
|
|
3227
|
+
if (!node) return 0;
|
|
3228
|
+
const cmp = this._compare(node.key, key);
|
|
3229
|
+
if (cmp > 0) {
|
|
3230
|
+
return this._getRankRecursive(node.left as BSTNode<K, V> | undefined, key);
|
|
3231
|
+
} else if (cmp < 0) {
|
|
3232
|
+
return (this.isRealNode(node.left) ? node.left._count : 0) + 1
|
|
3233
|
+
+ this._getRankRecursive(node.right as BSTNode<K, V> | undefined, key);
|
|
3234
|
+
} else {
|
|
3235
|
+
return this.isRealNode(node.left) ? node.left._count : 0;
|
|
3236
|
+
}
|
|
3237
|
+
}
|
|
3238
|
+
|
|
3239
|
+
/**
|
|
3240
|
+
* (Protected) Finds the in-order successor of a node.
|
|
3241
|
+
* @remarks Time O(log n), Space O(1)
|
|
3242
|
+
*/
|
|
3243
|
+
protected _next(node: BSTNode<K, V>): BSTNode<K, V> | undefined {
|
|
3244
|
+
if (this.isRealNode(node.right)) {
|
|
3245
|
+
// Leftmost in right subtree
|
|
3246
|
+
let current = node.right as BSTNode<K, V>;
|
|
3247
|
+
while (this.isRealNode(current.left)) {
|
|
3248
|
+
current = current.left as BSTNode<K, V>;
|
|
3249
|
+
}
|
|
3250
|
+
return current;
|
|
3251
|
+
}
|
|
3252
|
+
// Go up until we come from a left child
|
|
3253
|
+
let current: BSTNode<K, V> | undefined = node;
|
|
3254
|
+
let parent = current.parent as BSTNode<K, V> | undefined;
|
|
3255
|
+
while (parent && current === parent.right) {
|
|
3256
|
+
current = parent;
|
|
3257
|
+
parent = parent.parent as BSTNode<K, V> | undefined;
|
|
3258
|
+
}
|
|
3259
|
+
return parent;
|
|
3260
|
+
}
|
|
3261
|
+
|
|
2834
3262
|
protected override _setRoot(v: OptNode<BSTNode<K, V>>) {
|
|
2835
3263
|
if (v) v.parent = undefined;
|
|
2836
3264
|
this._root = v;
|
|
@@ -2887,25 +3315,32 @@ export class BST<K = any, V = any, R = any> extends BinaryTree<K, V, R> implemen
|
|
|
2887
3315
|
};
|
|
2888
3316
|
|
|
2889
3317
|
// 2. Perform deletion
|
|
3318
|
+
let countUpdateStart: BSTNode<K, V> | undefined;
|
|
2890
3319
|
if (node.left === undefined) {
|
|
2891
3320
|
// Case 1: No left child
|
|
3321
|
+
countUpdateStart = node.parent as BSTNode<K, V> | undefined;
|
|
2892
3322
|
transplant(node, node.right as BSTNode<K, V> | undefined);
|
|
2893
3323
|
} else if (node.right === undefined) {
|
|
2894
3324
|
// Case 2: No right child
|
|
3325
|
+
countUpdateStart = node.parent as BSTNode<K, V> | undefined;
|
|
2895
3326
|
transplant(node, node.left as BSTNode<K, V> | undefined);
|
|
2896
3327
|
} else {
|
|
2897
3328
|
// Case 3: Two children
|
|
2898
3329
|
const succ = minNode(node.right as BSTNode<K, V> | undefined)!; // Find successor
|
|
2899
3330
|
if (succ.parent !== node) {
|
|
3331
|
+
countUpdateStart = succ.parent as BSTNode<K, V> | undefined;
|
|
2900
3332
|
transplant(succ, succ.right as BSTNode<K, V> | undefined);
|
|
2901
3333
|
succ.right = node.right as BSTNode<K, V> | undefined;
|
|
2902
3334
|
if (succ.right) (succ.right as BSTNode<K, V>).parent = succ;
|
|
3335
|
+
} else {
|
|
3336
|
+
countUpdateStart = succ;
|
|
2903
3337
|
}
|
|
2904
3338
|
transplant(node, succ);
|
|
2905
3339
|
succ.left = node.left as BSTNode<K, V> | undefined;
|
|
2906
3340
|
if (succ.left) (succ.left as BSTNode<K, V>).parent = succ;
|
|
2907
3341
|
}
|
|
2908
3342
|
|
|
3343
|
+
this._updateCountAlongPath(countUpdateStart);
|
|
2909
3344
|
this._size = Math.max(0, this._size - 1);
|
|
2910
3345
|
return true;
|
|
2911
3346
|
}
|