data-structure-typed 2.2.4 → 2.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1 -1
- package/dist/cjs/index.cjs +284 -28
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs-legacy/index.cjs +286 -28
- package/dist/cjs-legacy/index.cjs.map +1 -1
- package/dist/esm/index.mjs +284 -28
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm-legacy/index.mjs +286 -28
- package/dist/esm-legacy/index.mjs.map +1 -1
- package/dist/types/data-structures/binary-tree/bst.d.ts +100 -6
- package/dist/umd/data-structure-typed.js +286 -28
- package/dist/umd/data-structure-typed.js.map +1 -1
- package/dist/umd/data-structure-typed.min.js +3 -3
- package/dist/umd/data-structure-typed.min.js.map +1 -1
- package/package.json +2 -2
- package/src/data-structures/binary-tree/avl-tree-multi-map.ts +3 -1
- package/src/data-structures/binary-tree/bst.ts +429 -48
- package/test/unit/data-structures/binary-tree/avl-tree-counter.test.ts +1 -1
- package/test/unit/data-structures/binary-tree/bst.test.ts +456 -2
- package/test/unit/data-structures/binary-tree/overall.test.ts +2 -2
- package/test/unit/data-structures/binary-tree/red-black-tree.test.ts +1 -1
- package/test/unit/data-structures/binary-tree/tree-multi-map.test.ts +1 -1
|
@@ -1015,7 +1015,7 @@ describe('BST isBST', function () {
|
|
|
1015
1015
|
|
|
1016
1016
|
it('isBST when variant is Max', () => {
|
|
1017
1017
|
const bst = new BST<number, number>([1, 2, 3, 9, 8, 5, 6, 7, 4], {
|
|
1018
|
-
comparator: (a, b) => b - a
|
|
1018
|
+
comparator: (a, b) => b - a
|
|
1019
1019
|
});
|
|
1020
1020
|
bst.addMany([1, 2, 3, 9, 8, 5, 6, 7, 4]);
|
|
1021
1021
|
expect(bst.isBST()).toBe(true);
|
|
@@ -1539,7 +1539,7 @@ describe('BST iterative methods not map mode test', () => {
|
|
|
1539
1539
|
describe('BST constructor and comparator edge cases', () => {
|
|
1540
1540
|
it('should support comparator', () => {
|
|
1541
1541
|
const bst = new BST<number>([], {
|
|
1542
|
-
comparator: (a, b) => b - a
|
|
1542
|
+
comparator: (a, b) => b - a
|
|
1543
1543
|
});
|
|
1544
1544
|
bst.add(1);
|
|
1545
1545
|
bst.add(2);
|
|
@@ -2232,6 +2232,460 @@ describe('BST Advanced Bound Methods Tests', () => {
|
|
|
2232
2232
|
});
|
|
2233
2233
|
});
|
|
2234
2234
|
|
|
2235
|
+
describe('BST Range Query Methods', () => {
|
|
2236
|
+
let bst: BST<number, string>;
|
|
2237
|
+
|
|
2238
|
+
beforeEach(() => {
|
|
2239
|
+
// Create a balanced BST: [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 20]
|
|
2240
|
+
bst = new BST([10, 5, 15, 3, 7, 13, 17, 1, 4, 6, 9, 11, 14, 16, 19, 20]);
|
|
2241
|
+
});
|
|
2242
|
+
|
|
2243
|
+
describe('ceilingEntry - finds >= key (minimum value >= target)', () => {
|
|
2244
|
+
test('should find ceiling when key exists', () => {
|
|
2245
|
+
const result = bst.ceilingEntry(10);
|
|
2246
|
+
expect(result).toBeDefined();
|
|
2247
|
+
expect(result?.key).toBe(10);
|
|
2248
|
+
});
|
|
2249
|
+
|
|
2250
|
+
test('should find ceiling when key does not exist but higher value exists', () => {
|
|
2251
|
+
const result = bst.ceilingEntry(8);
|
|
2252
|
+
expect(result).toBeDefined();
|
|
2253
|
+
expect(result?.key).toBe(9);
|
|
2254
|
+
});
|
|
2255
|
+
|
|
2256
|
+
test('should return undefined when no ceiling exists (key greater than all)', () => {
|
|
2257
|
+
const result = bst.ceilingEntry(100);
|
|
2258
|
+
expect(result).toBeUndefined();
|
|
2259
|
+
});
|
|
2260
|
+
|
|
2261
|
+
test('should find minimum element as ceiling for key smaller than all', () => {
|
|
2262
|
+
const result = bst.ceilingEntry(-10);
|
|
2263
|
+
expect(result).toBeDefined();
|
|
2264
|
+
expect(result?.key).toBe(1);
|
|
2265
|
+
});
|
|
2266
|
+
|
|
2267
|
+
test('should handle ceiling with node input', () => {
|
|
2268
|
+
const targetNode = bst.getNode(7);
|
|
2269
|
+
expect(targetNode).toBeDefined();
|
|
2270
|
+
const result = bst.ceilingEntry(targetNode!);
|
|
2271
|
+
expect(result?.key).toBe(7);
|
|
2272
|
+
});
|
|
2273
|
+
|
|
2274
|
+
test('should handle ceiling with entry input', () => {
|
|
2275
|
+
const result = bst.ceilingEntry([11, 'test']);
|
|
2276
|
+
expect(result).toBeDefined();
|
|
2277
|
+
expect(result?.key).toBe(11);
|
|
2278
|
+
});
|
|
2279
|
+
|
|
2280
|
+
test('should handle null/undefined inputs', () => {
|
|
2281
|
+
expect(bst.ceilingEntry(null)).toBeUndefined();
|
|
2282
|
+
expect(bst.ceilingEntry(undefined)).toBeUndefined();
|
|
2283
|
+
});
|
|
2284
|
+
|
|
2285
|
+
test('should work with ITERATIVE mode', () => {
|
|
2286
|
+
const result = bst.ceilingEntry(12, 'ITERATIVE');
|
|
2287
|
+
expect(result).toBeDefined();
|
|
2288
|
+
expect(result?.key).toBe(13);
|
|
2289
|
+
});
|
|
2290
|
+
|
|
2291
|
+
test('should work with RECURSIVE mode', () => {
|
|
2292
|
+
const result = bst.ceilingEntry(12, 'RECURSIVE');
|
|
2293
|
+
expect(result).toBeDefined();
|
|
2294
|
+
expect(result?.key).toBe(13);
|
|
2295
|
+
});
|
|
2296
|
+
|
|
2297
|
+
test('should find exact match as ceiling', () => {
|
|
2298
|
+
const result = bst.ceilingEntry(15);
|
|
2299
|
+
expect(result).toBeDefined();
|
|
2300
|
+
expect(result?.key).toBe(15);
|
|
2301
|
+
});
|
|
2302
|
+
});
|
|
2303
|
+
|
|
2304
|
+
describe('higherEntry - finds > key (minimum value > target)', () => {
|
|
2305
|
+
test('should find higher when key exists (exclude exact match)', () => {
|
|
2306
|
+
const result = bst.higherEntry(10);
|
|
2307
|
+
expect(result).toBeDefined();
|
|
2308
|
+
expect(result?.key).toBe(11);
|
|
2309
|
+
expect(result?.key).not.toBe(10);
|
|
2310
|
+
});
|
|
2311
|
+
|
|
2312
|
+
test('should find higher when key does not exist', () => {
|
|
2313
|
+
const result = bst.higherEntry(8);
|
|
2314
|
+
expect(result).toBeDefined();
|
|
2315
|
+
expect(result?.key).toBe(9);
|
|
2316
|
+
});
|
|
2317
|
+
|
|
2318
|
+
test('should return undefined when no higher exists (key >= all)', () => {
|
|
2319
|
+
const result = bst.higherEntry(20);
|
|
2320
|
+
expect(result).toBeUndefined();
|
|
2321
|
+
});
|
|
2322
|
+
|
|
2323
|
+
test('should find minimum element as higher for key < all', () => {
|
|
2324
|
+
const result = bst.higherEntry(-10);
|
|
2325
|
+
expect(result).toBeDefined();
|
|
2326
|
+
expect(result?.key).toBe(1);
|
|
2327
|
+
});
|
|
2328
|
+
|
|
2329
|
+
test('should not return the key itself', () => {
|
|
2330
|
+
const result = bst.higherEntry(7);
|
|
2331
|
+
expect(result?.key).not.toBe(7);
|
|
2332
|
+
expect(result?.key).toBe(9);
|
|
2333
|
+
});
|
|
2334
|
+
|
|
2335
|
+
test('should handle higher with node input', () => {
|
|
2336
|
+
const targetNode = bst.getNode(5);
|
|
2337
|
+
expect(targetNode).toBeDefined();
|
|
2338
|
+
const result = bst.higherEntry(targetNode!);
|
|
2339
|
+
expect(result?.key).toBeGreaterThan(5);
|
|
2340
|
+
expect(result?.key).toBe(6);
|
|
2341
|
+
});
|
|
2342
|
+
|
|
2343
|
+
test('should work with ITERATIVE mode', () => {
|
|
2344
|
+
const result = bst.higherEntry(13, 'ITERATIVE');
|
|
2345
|
+
expect(result).toBeDefined();
|
|
2346
|
+
expect(result?.key).toBe(14);
|
|
2347
|
+
});
|
|
2348
|
+
|
|
2349
|
+
test('should work with RECURSIVE mode', () => {
|
|
2350
|
+
const result = bst.higherEntry(13, 'RECURSIVE');
|
|
2351
|
+
expect(result).toBeDefined();
|
|
2352
|
+
expect(result?.key).toBe(14);
|
|
2353
|
+
});
|
|
2354
|
+
});
|
|
2355
|
+
|
|
2356
|
+
describe('floorEntry - finds <= key (maximum value <= target)', () => {
|
|
2357
|
+
test('should find floor when key exists', () => {
|
|
2358
|
+
const result = bst.floorEntry(10);
|
|
2359
|
+
expect(result).toBeDefined();
|
|
2360
|
+
expect(result?.key).toBe(10);
|
|
2361
|
+
});
|
|
2362
|
+
|
|
2363
|
+
test('should find floor when key does not exist but lower value exists', () => {
|
|
2364
|
+
const result = bst.floorEntry(12);
|
|
2365
|
+
expect(result).toBeDefined();
|
|
2366
|
+
expect(result?.key).toBe(11);
|
|
2367
|
+
});
|
|
2368
|
+
|
|
2369
|
+
test('should return undefined when no floor exists (key less than all)', () => {
|
|
2370
|
+
const result = bst.floorEntry(-10);
|
|
2371
|
+
expect(result).toBeUndefined();
|
|
2372
|
+
});
|
|
2373
|
+
|
|
2374
|
+
test('should find maximum element as floor for key greater than all', () => {
|
|
2375
|
+
const result = bst.floorEntry(100);
|
|
2376
|
+
expect(result).toBeDefined();
|
|
2377
|
+
expect(result?.key).toBe(20);
|
|
2378
|
+
});
|
|
2379
|
+
|
|
2380
|
+
test('should handle floor with node input', () => {
|
|
2381
|
+
const targetNode = bst.getNode(13);
|
|
2382
|
+
expect(targetNode).toBeDefined();
|
|
2383
|
+
const result = bst.floorEntry(targetNode!);
|
|
2384
|
+
expect(result?.key).toBe(13);
|
|
2385
|
+
});
|
|
2386
|
+
|
|
2387
|
+
test('should handle floor with entry input', () => {
|
|
2388
|
+
const result = bst.floorEntry([16, 'test']);
|
|
2389
|
+
expect(result).toBeDefined();
|
|
2390
|
+
expect(result?.key).toBe(16);
|
|
2391
|
+
});
|
|
2392
|
+
|
|
2393
|
+
test('should handle null/undefined inputs', () => {
|
|
2394
|
+
expect(bst.floorEntry(null)).toBeUndefined();
|
|
2395
|
+
expect(bst.floorEntry(undefined)).toBeUndefined();
|
|
2396
|
+
});
|
|
2397
|
+
|
|
2398
|
+
test('should work with ITERATIVE mode', () => {
|
|
2399
|
+
const result = bst.floorEntry(12, 'ITERATIVE');
|
|
2400
|
+
expect(result).toBeDefined();
|
|
2401
|
+
expect(result?.key).toBe(11);
|
|
2402
|
+
});
|
|
2403
|
+
|
|
2404
|
+
test('should work with RECURSIVE mode', () => {
|
|
2405
|
+
const result = bst.floorEntry(12, 'RECURSIVE');
|
|
2406
|
+
expect(result).toBeDefined();
|
|
2407
|
+
expect(result?.key).toBe(11);
|
|
2408
|
+
});
|
|
2409
|
+
|
|
2410
|
+
test('should find exact match as floor', () => {
|
|
2411
|
+
const result = bst.floorEntry(15);
|
|
2412
|
+
expect(result).toBeDefined();
|
|
2413
|
+
expect(result?.key).toBe(15);
|
|
2414
|
+
});
|
|
2415
|
+
|
|
2416
|
+
test('should correctly find floor between two keys', () => {
|
|
2417
|
+
const result = bst.floorEntry(8);
|
|
2418
|
+
expect(result).toBeDefined();
|
|
2419
|
+
expect(result?.key).toBe(7);
|
|
2420
|
+
expect(result?.key).toBeLessThan(8);
|
|
2421
|
+
});
|
|
2422
|
+
});
|
|
2423
|
+
|
|
2424
|
+
describe('lowerEntry - finds < key (maximum value < target)', () => {
|
|
2425
|
+
test('should find lower when key exists (exclude exact match)', () => {
|
|
2426
|
+
const result = bst.lowerEntry(10);
|
|
2427
|
+
expect(result).toBeDefined();
|
|
2428
|
+
expect(result?.key).toBe(9);
|
|
2429
|
+
expect(result?.key).not.toBe(10);
|
|
2430
|
+
});
|
|
2431
|
+
|
|
2432
|
+
test('should find lower when key does not exist', () => {
|
|
2433
|
+
const result = bst.lowerEntry(12);
|
|
2434
|
+
expect(result).toBeDefined();
|
|
2435
|
+
expect(result?.key).toBe(11);
|
|
2436
|
+
});
|
|
2437
|
+
|
|
2438
|
+
test('should return undefined when no lower exists (key <= all)', () => {
|
|
2439
|
+
const result = bst.lowerEntry(1);
|
|
2440
|
+
expect(result).toBeUndefined();
|
|
2441
|
+
});
|
|
2442
|
+
|
|
2443
|
+
test('should find maximum element as lower for key > all', () => {
|
|
2444
|
+
const result = bst.lowerEntry(100);
|
|
2445
|
+
expect(result).toBeDefined();
|
|
2446
|
+
expect(result?.key).toBe(20);
|
|
2447
|
+
});
|
|
2448
|
+
|
|
2449
|
+
test('should not return the key itself', () => {
|
|
2450
|
+
const result = bst.lowerEntry(15);
|
|
2451
|
+
expect(result?.key).not.toBe(15);
|
|
2452
|
+
expect(result?.key).toBe(14);
|
|
2453
|
+
});
|
|
2454
|
+
|
|
2455
|
+
test('should handle lower with node input', () => {
|
|
2456
|
+
const targetNode = bst.getNode(13);
|
|
2457
|
+
expect(targetNode).toBeDefined();
|
|
2458
|
+
const result = bst.lowerEntry(targetNode!);
|
|
2459
|
+
expect(result?.key).toBeLessThan(13);
|
|
2460
|
+
expect(result?.key).toBe(11);
|
|
2461
|
+
});
|
|
2462
|
+
|
|
2463
|
+
test('should handle lower with entry input', () => {
|
|
2464
|
+
const result = bst.lowerEntry([17, 'test']);
|
|
2465
|
+
expect(result).toBeDefined();
|
|
2466
|
+
expect(result?.key).toBe(16);
|
|
2467
|
+
});
|
|
2468
|
+
|
|
2469
|
+
test('should work with ITERATIVE mode', () => {
|
|
2470
|
+
const result = bst.lowerEntry(14, 'ITERATIVE');
|
|
2471
|
+
expect(result).toBeDefined();
|
|
2472
|
+
expect(result?.key).toBe(13);
|
|
2473
|
+
});
|
|
2474
|
+
|
|
2475
|
+
test('should work with RECURSIVE mode', () => {
|
|
2476
|
+
const result = bst.lowerEntry(14, 'RECURSIVE');
|
|
2477
|
+
expect(result).toBeDefined();
|
|
2478
|
+
expect(result?.key).toBe(13);
|
|
2479
|
+
});
|
|
2480
|
+
});
|
|
2481
|
+
|
|
2482
|
+
describe('Edge cases and special scenarios', () => {
|
|
2483
|
+
test('single element tree - ceiling', () => {
|
|
2484
|
+
const singleBst = new BST([5]);
|
|
2485
|
+
expect(singleBst.ceilingEntry(5)?.key).toBe(5);
|
|
2486
|
+
expect(singleBst.ceilingEntry(3)?.key).toBe(5);
|
|
2487
|
+
expect(singleBst.ceilingEntry(7)).toBeUndefined();
|
|
2488
|
+
});
|
|
2489
|
+
|
|
2490
|
+
test('single element tree - higher', () => {
|
|
2491
|
+
const singleBst = new BST([5]);
|
|
2492
|
+
expect(singleBst.higherEntry(5)).toBeUndefined();
|
|
2493
|
+
expect(singleBst.higherEntry(3)?.key).toBe(5);
|
|
2494
|
+
});
|
|
2495
|
+
|
|
2496
|
+
test('single element tree - floor', () => {
|
|
2497
|
+
const singleBst = new BST([5]);
|
|
2498
|
+
expect(singleBst.floorEntry(5)?.key).toBe(5);
|
|
2499
|
+
expect(singleBst.floorEntry(7)?.key).toBe(5);
|
|
2500
|
+
expect(singleBst.floorEntry(3)).toBeUndefined();
|
|
2501
|
+
});
|
|
2502
|
+
|
|
2503
|
+
test('single element tree - lower', () => {
|
|
2504
|
+
const singleBst = new BST([5]);
|
|
2505
|
+
expect(singleBst.lowerEntry(5)).toBeUndefined();
|
|
2506
|
+
expect(singleBst.lowerEntry(7)?.key).toBe(5);
|
|
2507
|
+
});
|
|
2508
|
+
|
|
2509
|
+
test('empty tree handling', () => {
|
|
2510
|
+
const emptyBst = new BST<number, string>();
|
|
2511
|
+
expect(emptyBst.ceilingEntry(5)).toBeUndefined();
|
|
2512
|
+
expect(emptyBst.higherEntry(5)).toBeUndefined();
|
|
2513
|
+
expect(emptyBst.floorEntry(5)).toBeUndefined();
|
|
2514
|
+
expect(emptyBst.lowerEntry(5)).toBeUndefined();
|
|
2515
|
+
});
|
|
2516
|
+
|
|
2517
|
+
test('ceiling and floor of adjacent keys', () => {
|
|
2518
|
+
const ceiling = bst.ceilingEntry(5);
|
|
2519
|
+
const floor = bst.floorEntry(6);
|
|
2520
|
+
expect(ceiling?.key).toBe(5);
|
|
2521
|
+
bst.print()
|
|
2522
|
+
expect(floor?.key).toBe(6);
|
|
2523
|
+
});
|
|
2524
|
+
|
|
2525
|
+
test('higher and lower of adjacent keys', () => {
|
|
2526
|
+
const higher = bst.higherEntry(5);
|
|
2527
|
+
const lower = bst.lowerEntry(6);
|
|
2528
|
+
expect(higher?.key).toBe(6);
|
|
2529
|
+
expect(lower?.key).toBe(5);
|
|
2530
|
+
});
|
|
2531
|
+
});
|
|
2532
|
+
|
|
2533
|
+
describe('Predicate-based search', () => {
|
|
2534
|
+
test('ceiling with predicate function', () => {
|
|
2535
|
+
const result = bst.ceilingEntry((node: BSTNode<number, string>) => node.key >= 10);
|
|
2536
|
+
expect(result).toBeDefined();
|
|
2537
|
+
expect(result?.key).toBeGreaterThanOrEqual(10);
|
|
2538
|
+
});
|
|
2539
|
+
|
|
2540
|
+
test('floor with predicate function', () => {
|
|
2541
|
+
const result = bst.floorEntry((node: BSTNode<number, string>) => node.key <= 15);
|
|
2542
|
+
expect(result).toBeDefined();
|
|
2543
|
+
expect(result?.key).toBeLessThanOrEqual(15);
|
|
2544
|
+
});
|
|
2545
|
+
|
|
2546
|
+
test('higher with predicate function', () => {
|
|
2547
|
+
const result = bst.higherEntry((node: BSTNode<number, string>) => node.key > 10);
|
|
2548
|
+
expect(result).toBeDefined();
|
|
2549
|
+
expect(result?.key).toBeGreaterThan(10);
|
|
2550
|
+
});
|
|
2551
|
+
|
|
2552
|
+
test('lower with predicate function', () => {
|
|
2553
|
+
const result = bst.lowerEntry((node: BSTNode<number, string>) => node.key < 15);
|
|
2554
|
+
expect(result).toBeDefined();
|
|
2555
|
+
expect(result?.key).toBeLessThan(15);
|
|
2556
|
+
});
|
|
2557
|
+
});
|
|
2558
|
+
|
|
2559
|
+
describe('Custom comparator', () => {
|
|
2560
|
+
test('should work with reverse order comparator', () => {
|
|
2561
|
+
const reverseBst = new BST([1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 20], {
|
|
2562
|
+
comparator: (a: number, b: number) => b - a // reverse order
|
|
2563
|
+
});
|
|
2564
|
+
|
|
2565
|
+
// In reverse order tree: keys are stored in descending order
|
|
2566
|
+
// ceiling (>=) should still work correctly
|
|
2567
|
+
const ceiling = reverseBst.ceilingEntry(10);
|
|
2568
|
+
expect(ceiling).toBeDefined();
|
|
2569
|
+
expect(ceiling?.key).toBeLessThanOrEqual(10);
|
|
2570
|
+
});
|
|
2571
|
+
|
|
2572
|
+
test('should work with string comparator', () => {
|
|
2573
|
+
const stringBst = new BST(
|
|
2574
|
+
[
|
|
2575
|
+
{ name: 'Alice', id: 1 },
|
|
2576
|
+
{ name: 'Bob', id: 2 },
|
|
2577
|
+
{ name: 'Charlie', id: 3 },
|
|
2578
|
+
{ name: 'David', id: 4 },
|
|
2579
|
+
{ name: 'Eve', id: 5 }
|
|
2580
|
+
],
|
|
2581
|
+
{
|
|
2582
|
+
comparator: (a, b) => a.name.localeCompare(b.name)
|
|
2583
|
+
}
|
|
2584
|
+
);
|
|
2585
|
+
|
|
2586
|
+
const ceiling = stringBst.ceilingEntry({ name: 'Bob', id: 0 });
|
|
2587
|
+
expect(ceiling).toBeDefined();
|
|
2588
|
+
expect(ceiling?.key.name).toBe('Bob');
|
|
2589
|
+
});
|
|
2590
|
+
});
|
|
2591
|
+
|
|
2592
|
+
describe('Performance and correctness validation', () => {
|
|
2593
|
+
test('all range methods return nodes in order', () => {
|
|
2594
|
+
const ceiling = bst.ceilingEntry(10);
|
|
2595
|
+
const higher = bst.higherEntry(10);
|
|
2596
|
+
const floor = bst.floorEntry(10);
|
|
2597
|
+
const lower = bst.lowerEntry(10);
|
|
2598
|
+
|
|
2599
|
+
expect(floor?.key).toBeLessThanOrEqual(10);
|
|
2600
|
+
expect(ceiling?.key).toBeGreaterThanOrEqual(10);
|
|
2601
|
+
expect(higher?.key).toBeGreaterThan(10);
|
|
2602
|
+
expect(lower?.key).toBeLessThan(10);
|
|
2603
|
+
});
|
|
2604
|
+
|
|
2605
|
+
test('range query iteration with ceiling/higher', () => {
|
|
2606
|
+
const results: number[] = [];
|
|
2607
|
+
let node = bst.ceilingEntry(5);
|
|
2608
|
+
let count = 0;
|
|
2609
|
+
while (node && node.key <= 15 && count < 20) {
|
|
2610
|
+
results.push(node.key);
|
|
2611
|
+
node = bst.higherEntry(node.key);
|
|
2612
|
+
count++;
|
|
2613
|
+
}
|
|
2614
|
+
|
|
2615
|
+
// Should iterate through nodes 5, 6, 7, ..., 15
|
|
2616
|
+
expect(results.length).toBeGreaterThan(0);
|
|
2617
|
+
expect(results[0]).toBeGreaterThanOrEqual(5);
|
|
2618
|
+
expect(results[results.length - 1]).toBeLessThanOrEqual(15);
|
|
2619
|
+
// Verify ascending order
|
|
2620
|
+
for (let i = 1; i < results.length; i++) {
|
|
2621
|
+
expect(results[i]).toBeGreaterThan(results[i - 1]);
|
|
2622
|
+
}
|
|
2623
|
+
});
|
|
2624
|
+
|
|
2625
|
+
test('range query iteration with floor/lower', () => {
|
|
2626
|
+
const results: number[] = [];
|
|
2627
|
+
let node = bst.floorEntry(15);
|
|
2628
|
+
let count = 0;
|
|
2629
|
+
while (node && node.key >= 5 && count < 20) {
|
|
2630
|
+
results.push(node.key);
|
|
2631
|
+
node = bst.lowerEntry(node.key);
|
|
2632
|
+
count++;
|
|
2633
|
+
}
|
|
2634
|
+
|
|
2635
|
+
// Should iterate through nodes 15, 14, 13, ..., 5
|
|
2636
|
+
expect(results.length).toBeGreaterThan(0);
|
|
2637
|
+
expect(results[0]).toBeLessThanOrEqual(15);
|
|
2638
|
+
expect(results[results.length - 1]).toBeGreaterThanOrEqual(5);
|
|
2639
|
+
// Verify descending order
|
|
2640
|
+
for (let i = 1; i < results.length; i++) {
|
|
2641
|
+
expect(results[i]).toBeLessThan(results[i - 1]);
|
|
2642
|
+
}
|
|
2643
|
+
});
|
|
2644
|
+
});
|
|
2645
|
+
|
|
2646
|
+
describe('Boundary value testing', () => {
|
|
2647
|
+
test('boundary: ceiling at min value', () => {
|
|
2648
|
+
const result = bst.ceilingEntry(1);
|
|
2649
|
+
expect(result?.key).toBe(1);
|
|
2650
|
+
});
|
|
2651
|
+
|
|
2652
|
+
test('boundary: floor at max value', () => {
|
|
2653
|
+
const result = bst.floorEntry(20);
|
|
2654
|
+
expect(result?.key).toBe(20);
|
|
2655
|
+
});
|
|
2656
|
+
|
|
2657
|
+
test('boundary: higher at second-last value', () => {
|
|
2658
|
+
const result = bst.higherEntry(19);
|
|
2659
|
+
expect(result?.key).toBe(20);
|
|
2660
|
+
});
|
|
2661
|
+
|
|
2662
|
+
test('boundary: lower at second value', () => {
|
|
2663
|
+
const result = bst.lowerEntry(3);
|
|
2664
|
+
expect(result?.key).toBe(1);
|
|
2665
|
+
});
|
|
2666
|
+
|
|
2667
|
+
test('boundary: ceiling slightly below min', () => {
|
|
2668
|
+
const result = bst.ceilingEntry(0);
|
|
2669
|
+
expect(result?.key).toBe(1);
|
|
2670
|
+
});
|
|
2671
|
+
|
|
2672
|
+
test('boundary: floor slightly above max', () => {
|
|
2673
|
+
const result = bst.floorEntry(21);
|
|
2674
|
+
expect(result?.key).toBe(20);
|
|
2675
|
+
});
|
|
2676
|
+
|
|
2677
|
+
test('boundary: higher at max (should be undefined)', () => {
|
|
2678
|
+
const result = bst.higherEntry(20);
|
|
2679
|
+
expect(result).toBeUndefined();
|
|
2680
|
+
});
|
|
2681
|
+
|
|
2682
|
+
test('boundary: lower at min (should be undefined)', () => {
|
|
2683
|
+
const result = bst.lowerEntry(1);
|
|
2684
|
+
expect(result).toBeUndefined();
|
|
2685
|
+
});
|
|
2686
|
+
});
|
|
2687
|
+
});
|
|
2688
|
+
|
|
2235
2689
|
describe('classic use', () => {
|
|
2236
2690
|
it('@example basic BST creation and add operation', () => {
|
|
2237
2691
|
// Create a simple BST with numeric keys
|
|
@@ -58,7 +58,7 @@ describe('Overall BinaryTree Test', () => {
|
|
|
58
58
|
it('Should clone a BST works fine', () => {
|
|
59
59
|
const bst = new BST<number>([3, 6, 7, 1, 9], {
|
|
60
60
|
iterationType: 'RECURSIVE',
|
|
61
|
-
comparator: (a, b) => b - a
|
|
61
|
+
comparator: (a, b) => b - a
|
|
62
62
|
});
|
|
63
63
|
expect(bst.size).toBe(5);
|
|
64
64
|
expect(bst.root?.key).toBe(6);
|
|
@@ -100,7 +100,7 @@ describe('Overall BinaryTree Test', () => {
|
|
|
100
100
|
it('Should clone a AVLTree works fine', () => {
|
|
101
101
|
const avl = new AVLTree<number>([3, 6, 7, 1, 9], {
|
|
102
102
|
iterationType: 'RECURSIVE',
|
|
103
|
-
comparator: (a, b) => b - a
|
|
103
|
+
comparator: (a, b) => b - a
|
|
104
104
|
});
|
|
105
105
|
expect(avl.size).toBe(5);
|
|
106
106
|
avl.add(2);
|
|
@@ -821,7 +821,7 @@ describe('RedBlackTree - _deleteFixup', () => {
|
|
|
821
821
|
describe('real world data', () => {
|
|
822
822
|
it('cost of living', () => {
|
|
823
823
|
const indexedByRank = new RedBlackTree(costOfLiving, {
|
|
824
|
-
|
|
824
|
+
comparator: (a, b) => a.rank - b.rank,
|
|
825
825
|
toEntryFn: raw => [raw, undefined]
|
|
826
826
|
});
|
|
827
827
|
expect(indexedByRank.size).toBe(7);
|
|
@@ -820,7 +820,7 @@ describe('real world data', () => {
|
|
|
820
820
|
it('cost of living', () => {
|
|
821
821
|
const indexedByRank = new TreeMultiMap(costOfLiving, {
|
|
822
822
|
toEntryFn: raw => [raw, undefined],
|
|
823
|
-
comparator: (a, b) => a.rank - b.rank
|
|
823
|
+
comparator: (a, b) => a.rank - b.rank
|
|
824
824
|
});
|
|
825
825
|
expect(indexedByRank.size).toBe(7);
|
|
826
826
|
expect(indexedByRank.dfs(node => node?.key?.country)).toEqual([
|