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.
@@ -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
- comparator: (a, b) => a.rank - b.rank,
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([