data-structure-typed 2.2.5 → 2.2.7

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.
@@ -492,7 +492,6 @@ describe('BST operations test', () => {
492
492
  it('should search in range', () => {
493
493
  const bst = new BST<number>([10, 5, 15, 3, 7, 12, 18]);
494
494
  expect(bst.rangeSearch([4, 12])).toEqual([5, 7, 10, 12]);
495
- expect(() => bst.rangeSearch([12, 4])).toThrow('low must be less than or equal to high');
496
495
  expect(bst.rangeSearch([12, 12])).toEqual([12]);
497
496
  });
498
497
  });
@@ -1613,7 +1612,7 @@ describe('BST _keyValueNodeOrEntryToNodeAndValue edge', () => {
1613
1612
  });
1614
1613
  });
1615
1614
 
1616
- describe('BST lowerBound and upperBound', () => {
1615
+ describe('BST ceiling and higher', () => {
1617
1616
  let bst: BST<number, string>;
1618
1617
 
1619
1618
  beforeEach(() => {
@@ -1621,184 +1620,184 @@ describe('BST lowerBound and upperBound', () => {
1621
1620
  bst = new BST<number, string>([10, 5, 15, 3, 7, 12, 20, 1, 4, 6, 8, 11, 13, 18, 25]);
1622
1621
  });
1623
1622
 
1624
- describe('lowerBound', () => {
1625
- it('should return the node with exact key match', () => {
1623
+ describe('ceiling', () => {
1624
+ it('should return the key with exact key match', () => {
1626
1625
  // Test for key that exists in tree
1627
- const node = bst.lowerBound(10);
1628
- expect(node).toBeDefined();
1629
- expect(node?.key).toBe(10);
1626
+ const key = bst.ceiling(10);
1627
+ expect(key).toBeDefined();
1628
+ expect(key).toBe(10);
1630
1629
  });
1631
1630
 
1632
- it('should return the smallest node >= key when exact match not found', () => {
1631
+ it('should return the smallest key >= key when exact match not found', () => {
1633
1632
  // Test for key 9 (doesn't exist, should return 10)
1634
- const node = bst.lowerBound(9);
1635
- expect(node).toBeDefined();
1636
- expect(node?.key).toBe(10);
1633
+ const key = bst.ceiling(9);
1634
+ expect(key).toBeDefined();
1635
+ expect(key).toBe(10);
1637
1636
  });
1638
1637
 
1639
- it('should return node with key >= search key from multiple candidates', () => {
1638
+ it('should return key with key >= search key from multiple candidates', () => {
1640
1639
  // Test for key 6 (exists, should return 6)
1641
- const node = bst.lowerBound(6);
1642
- expect(node).toBeDefined();
1643
- expect(node?.key).toBe(6);
1640
+ const key = bst.ceiling(6);
1641
+ expect(key).toBeDefined();
1642
+ expect(key).toBe(6);
1644
1643
 
1645
1644
  // Test for key 7 (exists, should return 7)
1646
- const node2 = bst.lowerBound(7);
1647
- expect(node2).toBeDefined();
1648
- expect(node2?.key).toBe(7);
1645
+ const key2 = bst.ceiling(7);
1646
+ expect(key2).toBeDefined();
1647
+ expect(key2).toBe(7);
1649
1648
  });
1650
1649
 
1651
1650
  it('should return smallest key >= search key for non-existent key in middle range', () => {
1652
1651
  // Test for key 14 (doesn't exist, should return 15)
1653
- const node = bst.lowerBound(14);
1654
- expect(node).toBeDefined();
1655
- expect(node?.key).toBe(15);
1652
+ const key = bst.ceiling(14);
1653
+ expect(key).toBeDefined();
1654
+ expect(key).toBe(15);
1656
1655
 
1657
1656
  // Test for key 11.5 (doesn't exist, should return 12)
1658
- const node2 = bst.lowerBound(11.5);
1659
- expect(node2).toBeDefined();
1660
- expect(node2?.key).toBe(12);
1657
+ const key2 = bst.ceiling(11.5);
1658
+ expect(key2).toBeDefined();
1659
+ expect(key2).toBe(12);
1661
1660
  });
1662
1661
 
1663
1662
  it('should return smallest key when search key is less than minimum', () => {
1664
1663
  // Test for key 0 (should return 1, the minimum)
1665
- const node = bst.lowerBound(0);
1666
- expect(node).toBeDefined();
1667
- expect(node?.key).toBe(1);
1664
+ const key = bst.ceiling(0);
1665
+ expect(key).toBeDefined();
1666
+ expect(key).toBe(1);
1668
1667
 
1669
1668
  // Test for key -100 (should return 1, the minimum)
1670
- const node2 = bst.lowerBound(-100);
1671
- expect(node2).toBeDefined();
1672
- expect(node2?.key).toBe(1);
1669
+ const key2 = bst.ceiling(-100);
1670
+ expect(key2).toBeDefined();
1671
+ expect(key2).toBe(1);
1673
1672
  });
1674
1673
 
1675
1674
  it('should return undefined when search key is greater than maximum', () => {
1676
1675
  // Test for key 100 (no key >= 100, should return undefined)
1677
- const node = bst.lowerBound(100);
1678
- expect(node).toBeUndefined();
1676
+ const key = bst.ceiling(100);
1677
+ expect(key).toBeUndefined();
1679
1678
 
1680
1679
  // Test for key 26 (no key >= 26, should return undefined)
1681
- const node2 = bst.lowerBound(26);
1682
- expect(node2).toBeUndefined();
1680
+ const key2 = bst.ceiling(26);
1681
+ expect(key2).toBeUndefined();
1683
1682
  });
1684
1683
 
1685
- it('should return correct node for edge cases', () => {
1684
+ it('should return correct key for edge cases', () => {
1686
1685
  // Test for key 25 (maximum, should return 25)
1687
- const node = bst.lowerBound(25);
1688
- expect(node).toBeDefined();
1689
- expect(node?.key).toBe(25);
1686
+ const key = bst.ceiling(25);
1687
+ expect(key).toBeDefined();
1688
+ expect(key).toBe(25);
1690
1689
 
1691
1690
  // Test for key 1 (minimum, should return 1)
1692
- const node2 = bst.lowerBound(1);
1693
- expect(node2).toBeDefined();
1694
- expect(node2?.key).toBe(1);
1691
+ const key2 = bst.ceiling(1);
1692
+ expect(key2).toBeDefined();
1693
+ expect(key2).toBe(1);
1695
1694
  });
1696
1695
  });
1697
1696
 
1698
- describe('upperBound', () => {
1697
+ describe('higher', () => {
1699
1698
  it('should return the smallest key > search key', () => {
1700
1699
  // Test for key 10 (exists, should return next key > 10, which is 11)
1701
- const node = bst.upperBound(10);
1702
- expect(node).toBeDefined();
1703
- expect(node?.key).toBe(11);
1700
+ const key = bst.higher(10);
1701
+ expect(key).toBeDefined();
1702
+ expect(key).toBe(11);
1704
1703
  });
1705
1704
 
1706
1705
  it('should return the smallest key > search key for non-existent key', () => {
1707
1706
  // Test for key 9 (doesn't exist, should return 10, the smallest key > 9)
1708
- const node = bst.upperBound(9);
1709
- expect(node).toBeDefined();
1710
- expect(node?.key).toBe(10);
1707
+ const key = bst.higher(9);
1708
+ expect(key).toBeDefined();
1709
+ expect(key).toBe(10);
1711
1710
 
1712
1711
  // Test for key 14 (doesn't exist, should return 15)
1713
- const node2 = bst.upperBound(14);
1714
- expect(node2).toBeDefined();
1715
- expect(node2?.key).toBe(15);
1712
+ const key2 = bst.higher(14);
1713
+ expect(key2).toBeDefined();
1714
+ expect(key2).toBe(15);
1716
1715
  });
1717
1716
 
1718
1717
  it('should skip equal keys and return the next larger key', () => {
1719
1718
  // Test for key 5 (exists, should return 6, the smallest key > 5)
1720
- const node = bst.upperBound(5);
1721
- expect(node).toBeDefined();
1722
- expect(node?.key).toBe(6);
1719
+ const key = bst.higher(5);
1720
+ expect(key).toBeDefined();
1721
+ expect(key).toBe(6);
1723
1722
 
1724
1723
  // Test for key 20 (exists, should return 25)
1725
- const node2 = bst.upperBound(20);
1726
- expect(node2).toBeDefined();
1727
- expect(node2?.key).toBe(25);
1724
+ const key2 = bst.higher(20);
1725
+ expect(key2).toBeDefined();
1726
+ expect(key2).toBe(25);
1728
1727
  });
1729
1728
 
1730
1729
  it('should return smallest key > search key for non-existent key in middle range', () => {
1731
1730
  // Test for key 11.5 (doesn't exist, should return 12)
1732
- const node = bst.upperBound(11.5);
1733
- expect(node).toBeDefined();
1734
- expect(node?.key).toBe(12);
1731
+ const key = bst.higher(11.5);
1732
+ expect(key).toBeDefined();
1733
+ expect(key).toBe(12);
1735
1734
 
1736
1735
  // Test for key 19 (doesn't exist, should return 20)
1737
- const node2 = bst.upperBound(19);
1738
- expect(node2).toBeDefined();
1739
- expect(node2?.key).toBe(20);
1736
+ const key2 = bst.higher(19);
1737
+ expect(key2).toBeDefined();
1738
+ expect(key2).toBe(20);
1740
1739
  });
1741
1740
 
1742
1741
  it('should return smallest key when search key is less than minimum', () => {
1743
1742
  // Test for key 0 (should return 1, the minimum)
1744
- const node = bst.upperBound(0);
1745
- expect(node).toBeDefined();
1746
- expect(node?.key).toBe(1);
1743
+ const key = bst.higher(0);
1744
+ expect(key).toBeDefined();
1745
+ expect(key).toBe(1);
1747
1746
 
1748
1747
  // Test for key -100 (should return 1, the minimum)
1749
- const node2 = bst.upperBound(-100);
1750
- expect(node2).toBeDefined();
1751
- expect(node2?.key).toBe(1);
1748
+ const key2 = bst.higher(-100);
1749
+ expect(key2).toBeDefined();
1750
+ expect(key2).toBe(1);
1752
1751
  });
1753
1752
 
1754
1753
  it('should return undefined when search key is >= maximum', () => {
1755
1754
  // Test for key 100 (no key > 100, should return undefined)
1756
- const node = bst.upperBound(100);
1757
- expect(node).toBeUndefined();
1755
+ const key = bst.higher(100);
1756
+ expect(key).toBeUndefined();
1758
1757
 
1759
1758
  // Test for key 25 (maximum, no key > 25, should return undefined)
1760
- const node2 = bst.upperBound(25);
1761
- expect(node2).toBeUndefined();
1759
+ const key2 = bst.higher(25);
1760
+ expect(key2).toBeUndefined();
1762
1761
 
1763
1762
  // Test for key 26 (no key > 26, should return undefined)
1764
- const node3 = bst.upperBound(26);
1765
- expect(node3).toBeUndefined();
1763
+ const key3 = bst.higher(26);
1764
+ expect(key3).toBeUndefined();
1766
1765
  });
1767
1766
 
1768
- it('should return correct node for edge cases', () => {
1767
+ it('should return correct key for edge cases', () => {
1769
1768
  // Test for key 1 (minimum, should return next key 3)
1770
- const node = bst.upperBound(1);
1771
- expect(node).toBeDefined();
1772
- expect(node?.key).toBe(3);
1769
+ const key = bst.higher(1);
1770
+ expect(key).toBeDefined();
1771
+ expect(key).toBe(3);
1773
1772
 
1774
1773
  // Test for key 24 (doesn't exist, should return 25)
1775
- const node2 = bst.upperBound(24);
1776
- expect(node2).toBeDefined();
1777
- expect(node2?.key).toBe(25);
1774
+ const key2 = bst.higher(24);
1775
+ expect(key2).toBeDefined();
1776
+ expect(key2).toBe(25);
1778
1777
  });
1779
1778
  });
1780
1779
 
1781
- describe('lowerBound vs upperBound comparison', () => {
1782
- it('should demonstrate difference between lowerBound and upperBound', () => {
1780
+ describe('ceiling vs higher comparison', () => {
1781
+ it('should demonstrate difference between ceiling and higher', () => {
1783
1782
  const searchKey = 12;
1784
1783
 
1785
- // lowerBound(12) should return 12 (key >= 12)
1786
- const lower = bst.lowerBound(searchKey);
1787
- expect(lower?.key).toBe(12);
1784
+ // ceiling(12) should return 12 (key >= 12)
1785
+ const lower = bst.ceiling(searchKey);
1786
+ expect(lower).toBe(12);
1788
1787
 
1789
- // upperBound(12) should return 13 (key > 12)
1790
- const upper = bst.upperBound(searchKey);
1791
- expect(upper?.key).toBe(13);
1788
+ // higher(12) should return 13 (key > 12)
1789
+ const upper = bst.higher(searchKey);
1790
+ expect(upper).toBe(13);
1792
1791
  });
1793
1792
 
1794
1793
  it('should return same result for non-existent key in both methods', () => {
1795
1794
  const searchKey = 11.5;
1796
1795
 
1797
- // Both should return 12 (smallest key >= 11.5 for lowerBound, smallest key > 11.5 for upperBound)
1798
- const lower = bst.lowerBound(searchKey);
1799
- const upper = bst.upperBound(searchKey);
1800
- expect(lower?.key).toBe(12);
1801
- expect(upper?.key).toBe(12);
1796
+ // Both should return 12 (smallest key >= 11.5 for ceiling, smallest key > 11.5 for higher)
1797
+ const lower = bst.ceiling(searchKey);
1798
+ const upper = bst.higher(searchKey);
1799
+ expect(lower).toBe(12);
1800
+ expect(upper).toBe(12);
1802
1801
  });
1803
1802
  });
1804
1803
 
@@ -1825,90 +1824,90 @@ describe('BST lowerBound and upperBound', () => {
1825
1824
  keys.forEach(k => bst.add(k, `val-${k}`));
1826
1825
  });
1827
1826
 
1828
- describe('lowerBound (First node >= key)', () => {
1827
+ describe('ceiling (First key >= key)', () => {
1829
1828
  test('should return strict match if key exists', () => {
1830
1829
  // Case: Key exists
1831
- expect(bst.lowerBound(10)?.key).toBe(10);
1832
- expect(bst.lowerBound(6)?.key).toBe(6);
1833
- expect(bst.lowerBound(20)?.key).toBe(20);
1830
+ expect(bst.ceiling(10)).toBe(10);
1831
+ expect(bst.ceiling(6)).toBe(6);
1832
+ expect(bst.ceiling(20)).toBe(20);
1834
1833
  });
1835
1834
 
1836
- test('should return next larger node if key does not exist', () => {
1835
+ test('should return next larger key if key does not exist', () => {
1837
1836
  // Case: Key doesn't exist, but falls within range
1838
- expect(bst.lowerBound(7)?.key).toBe(8); // 7 -> 8
1839
- expect(bst.lowerBound(11)?.key).toBe(12); // 11 -> 12
1840
- expect(bst.lowerBound(3)?.key).toBe(5); // 3 -> 5
1837
+ expect(bst.ceiling(7)).toBe(8); // 7 -> 8
1838
+ expect(bst.ceiling(11)).toBe(12); // 11 -> 12
1839
+ expect(bst.ceiling(3)).toBe(5); // 3 -> 5
1841
1840
  });
1842
1841
 
1843
- test('should return smallest node if key is smaller than min', () => {
1842
+ test('should return smallest key if key is smaller than min', () => {
1844
1843
  // Case: Key is smaller than the minimum value in the tree
1845
- expect(bst.lowerBound(0)?.key).toBe(2);
1846
- expect(bst.lowerBound(-100)?.key).toBe(2);
1844
+ expect(bst.ceiling(0)).toBe(2);
1845
+ expect(bst.ceiling(-100)).toBe(2);
1847
1846
  });
1848
1847
 
1849
1848
  test('should return undefined if key is larger than max', () => {
1850
1849
  // Case: Key is larger than the maximum value in the tree
1851
- expect(bst.lowerBound(21)).toBeUndefined();
1852
- expect(bst.lowerBound(100)).toBeUndefined();
1850
+ expect(bst.ceiling(21)).toBeUndefined();
1851
+ expect(bst.ceiling(100)).toBeUndefined();
1853
1852
  });
1854
1853
 
1855
1854
  test('should work with IterationType.RECURSIVE explicitly', () => {
1856
- expect(bst.lowerBound(7, 'RECURSIVE')?.key).toBe(8);
1857
- expect(bst.lowerBound(10, 'RECURSIVE')?.key).toBe(10);
1858
- expect(bst.lowerBound(21, 'RECURSIVE')).toBeUndefined();
1855
+ expect(bst.ceiling(7)).toBe(8);
1856
+ expect(bst.ceiling(10)).toBe(10);
1857
+ expect(bst.ceiling(21)).toBeUndefined();
1859
1858
  });
1860
1859
 
1861
1860
  test('should work with IterationType.ITERATIVE explicitly', () => {
1862
- expect(bst.lowerBound(7, 'ITERATIVE')?.key).toBe(8);
1863
- expect(bst.lowerBound(10, 'ITERATIVE')?.key).toBe(10);
1864
- expect(bst.lowerBound(21, 'ITERATIVE')).toBeUndefined();
1861
+ expect(bst.ceiling(7)).toBe(8);
1862
+ expect(bst.ceiling(10)).toBe(10);
1863
+ expect(bst.ceiling(21)).toBeUndefined();
1865
1864
  });
1866
1865
  });
1867
1866
 
1868
- describe('upperBound (First node > key)', () => {
1869
- test('should return next larger node even if key exists', () => {
1867
+ describe('higher (First key > key)', () => {
1868
+ test('should return next larger key even if key exists', () => {
1870
1869
  // Case: Key exists, but we want strictly greater
1871
- expect(bst.upperBound(10)?.key).toBe(12); // > 10 is 12
1872
- expect(bst.upperBound(6)?.key).toBe(8); // > 6 is 8
1873
- expect(bst.upperBound(20)).toBeUndefined(); // > 20 is undefined
1870
+ expect(bst.higher(10)).toBe(12); // > 10 is 12
1871
+ expect(bst.higher(6)).toBe(8); // > 6 is 8
1872
+ expect(bst.higher(20)).toBeUndefined(); // > 20 is undefined
1874
1873
  });
1875
1874
 
1876
- test('should return next larger node if key does not exist', () => {
1875
+ test('should return next larger key if key does not exist', () => {
1877
1876
  // Case: Key doesn't exist
1878
- expect(bst.upperBound(7)?.key).toBe(8);
1879
- expect(bst.upperBound(11)?.key).toBe(12);
1877
+ expect(bst.higher(7)).toBe(8);
1878
+ expect(bst.higher(11)).toBe(12);
1880
1879
  });
1881
1880
 
1882
1881
  test('should return undefined if key is larger than or equal to max', () => {
1883
- expect(bst.upperBound(20)).toBeUndefined();
1884
- expect(bst.upperBound(21)).toBeUndefined();
1882
+ expect(bst.higher(20)).toBeUndefined();
1883
+ expect(bst.higher(21)).toBeUndefined();
1885
1884
  });
1886
1885
 
1887
1886
  test('should work with IterationType.RECURSIVE explicitly', () => {
1888
- expect(bst.upperBound(10, 'RECURSIVE')?.key).toBe(12);
1889
- expect(bst.upperBound(20, 'RECURSIVE')).toBeUndefined();
1887
+ expect(bst.higher(10)).toBe(12);
1888
+ expect(bst.higher(20)).toBeUndefined();
1890
1889
  });
1891
1890
  });
1892
1891
 
1893
1892
  describe('Edge Cases', () => {
1894
1893
  test('should handle empty tree', () => {
1895
1894
  const emptyTree = new BST<number, string>();
1896
- expect(emptyTree.lowerBound(10)).toBeUndefined();
1897
- expect(emptyTree.upperBound(10)).toBeUndefined();
1895
+ expect(emptyTree.ceiling(10)).toBeUndefined();
1896
+ expect(emptyTree.higher(10)).toBeUndefined();
1898
1897
  });
1899
1898
 
1900
1899
  test('should handle single node tree', () => {
1901
1900
  const singleNodeTree = new BST<number, string>();
1902
1901
  singleNodeTree.add(10);
1903
1902
 
1904
- // lowerBound
1905
- expect(singleNodeTree.lowerBound(5)?.key).toBe(10);
1906
- expect(singleNodeTree.lowerBound(10)?.key).toBe(10);
1907
- expect(singleNodeTree.lowerBound(15)).toBeUndefined();
1903
+ // ceiling
1904
+ expect(singleNodeTree.ceiling(5)).toBe(10);
1905
+ expect(singleNodeTree.ceiling(10)).toBe(10);
1906
+ expect(singleNodeTree.ceiling(15)).toBeUndefined();
1908
1907
 
1909
- // upperBound
1910
- expect(singleNodeTree.upperBound(5)?.key).toBe(10);
1911
- expect(singleNodeTree.upperBound(10)).toBeUndefined();
1908
+ // higher
1909
+ expect(singleNodeTree.higher(5)).toBe(10);
1910
+ expect(singleNodeTree.higher(10)).toBeUndefined();
1912
1911
  });
1913
1912
  });
1914
1913
 
@@ -1928,9 +1927,9 @@ describe('BST lowerBound and upperBound', () => {
1928
1927
  const testQueries = generateRandomArray(200, 0, 1000);
1929
1928
 
1930
1929
  testQueries.forEach(queryKey => {
1931
- // 1. Verify lowerBound
1932
- const recLower = fuzzTree.lowerBound(queryKey, 'RECURSIVE')?.key;
1933
- const iterLower = fuzzTree.lowerBound(queryKey, 'ITERATIVE')?.key;
1930
+ // 1. Verify ceiling
1931
+ const recLower = fuzzTree.ceiling(queryKey);
1932
+ const iterLower = fuzzTree.ceiling(queryKey);
1934
1933
 
1935
1934
  // Verify consistency between recursive and iterative
1936
1935
  expect(recLower).toBe(iterLower);
@@ -1939,9 +1938,9 @@ describe('BST lowerBound and upperBound', () => {
1939
1938
  const expectedLower = sortedKeys.find(k => k >= queryKey);
1940
1939
  expect(recLower).toBe(expectedLower);
1941
1940
 
1942
- // 2. Verify upperBound
1943
- const recUpper = fuzzTree.upperBound(queryKey, 'RECURSIVE')?.key;
1944
- const iterUpper = fuzzTree.upperBound(queryKey, 'ITERATIVE')?.key;
1941
+ // 2. Verify higher
1942
+ const recUpper = fuzzTree.higher(queryKey);
1943
+ const iterUpper = fuzzTree.higher(queryKey);
1945
1944
 
1946
1945
  // Verify consistency
1947
1946
  expect(recUpper).toBe(iterUpper);
@@ -1959,14 +1958,14 @@ describe('BST lowerBound and upperBound', () => {
1959
1958
  bst = new BST<number, string>();
1960
1959
  });
1961
1960
 
1962
- it('lowerBound should return undefined on empty tree', () => {
1963
- const node = bst.lowerBound(10);
1964
- expect(node).toBeUndefined();
1961
+ it('ceiling should return undefined on empty tree', () => {
1962
+ const key = bst.ceiling(10);
1963
+ expect(key).toBeUndefined();
1965
1964
  });
1966
1965
 
1967
- it('upperBound should return undefined on empty tree', () => {
1968
- const node = bst.upperBound(10);
1969
- expect(node).toBeUndefined();
1966
+ it('higher should return undefined on empty tree', () => {
1967
+ const key = bst.higher(10);
1968
+ expect(key).toBeUndefined();
1970
1969
  });
1971
1970
  });
1972
1971
 
@@ -1976,258 +1975,67 @@ describe('BST lowerBound and upperBound', () => {
1976
1975
  bst.add(10, 'ten');
1977
1976
  });
1978
1977
 
1979
- it('lowerBound should return the node if key matches', () => {
1980
- const node = bst.lowerBound(10);
1981
- expect(node).toBeDefined();
1982
- expect(node?.key).toBe(10);
1978
+ it('ceiling should return the key if key matches', () => {
1979
+ const key = bst.ceiling(10);
1980
+ expect(key).toBeDefined();
1981
+ expect(key).toBe(10);
1983
1982
  });
1984
1983
 
1985
- it('lowerBound should return the node if search key is less', () => {
1986
- const node = bst.lowerBound(5);
1987
- expect(node).toBeDefined();
1988
- expect(node?.key).toBe(10);
1984
+ it('ceiling should return the key if search key is less', () => {
1985
+ const key = bst.ceiling(5);
1986
+ expect(key).toBeDefined();
1987
+ expect(key).toBe(10);
1989
1988
  });
1990
1989
 
1991
- it('lowerBound should return undefined if search key is greater', () => {
1992
- const node = bst.lowerBound(15);
1993
- expect(node).toBeUndefined();
1990
+ it('ceiling should return undefined if search key is greater', () => {
1991
+ const key = bst.ceiling(15);
1992
+ expect(key).toBeUndefined();
1994
1993
  });
1995
1994
 
1996
- it('upperBound should return undefined if key matches', () => {
1997
- const node = bst.upperBound(10);
1998
- expect(node).toBeUndefined();
1995
+ it('higher should return undefined if key matches', () => {
1996
+ const key = bst.higher(10);
1997
+ expect(key).toBeUndefined();
1999
1998
  });
2000
1999
 
2001
- it('upperBound should return the node if search key is less', () => {
2002
- const node = bst.upperBound(5);
2003
- expect(node).toBeDefined();
2004
- expect(node?.key).toBe(10);
2000
+ it('higher should return the key if search key is less', () => {
2001
+ const key = bst.higher(5);
2002
+ expect(key).toBeDefined();
2003
+ expect(key).toBe(10);
2005
2004
  });
2006
2005
 
2007
- it('upperBound should return undefined if search key is greater', () => {
2008
- const node = bst.upperBound(15);
2009
- expect(node).toBeUndefined();
2006
+ it('higher should return undefined if search key is greater', () => {
2007
+ const key = bst.higher(15);
2008
+ expect(key).toBeUndefined();
2010
2009
  });
2011
2010
  });
2012
2011
 
2013
2012
  describe('practical LeetCode use case: Range search', () => {
2014
2013
  it('should find all keys in range [12, 20]', () => {
2015
- // Use lowerBound to find start of range and upperBound to find end
2016
- const start = bst.lowerBound(12);
2014
+ // Use ceiling to find start of range and higher to find end
2015
+ const start = bst.ceiling(12);
2017
2016
 
2018
- // Simple traversal simulation (for test only, real iteration is more complex)
2019
- // We manually add keys we know are in range to verify logic works
2020
- // The lowerBound(12) returns 12. upperBound(20) returns 25 (or null if max).
2021
- // Logic: we want >= 12 and <= 20.
2022
-
2023
- expect(start?.key).toBe(12);
2017
+ expect(start).toBe(12);
2024
2018
 
2025
2019
  // Let's verify we found the correct bounds
2026
- expect(start?.key).toBeGreaterThanOrEqual(12);
2020
+ expect(start).toBeGreaterThanOrEqual(12);
2027
2021
 
2028
2022
  // Check overlap
2029
- const rangeStart = bst.lowerBound(12);
2030
- const rangeEndInclusive = bst.lowerBound(20); // Should be 20
2023
+ const rangeStart = bst.ceiling(12);
2024
+ const rangeEndInclusive = bst.ceiling(20); // Should be 20
2031
2025
 
2032
- expect(rangeStart?.key).toBe(12);
2033
- expect(rangeEndInclusive?.key).toBe(20);
2026
+ expect(rangeStart).toBe(12);
2027
+ expect(rangeEndInclusive).toBe(20);
2034
2028
  });
2035
2029
 
2036
2030
  it('should help identify interval overlaps', () => {
2037
2031
  // Check if interval [14, 19] overlaps with any existing interval
2038
- // Use upperBound to find the first key > 19
2039
- const nextKey = bst.upperBound(19);
2040
- // Use lowerBound to find the first key >= 14
2041
- const firstInRange = bst.lowerBound(14);
2042
-
2043
- expect(firstInRange?.key).toBe(15);
2044
- expect(nextKey?.key).toBe(20);
2045
- });
2046
- });
2047
- });
2048
-
2049
- describe('BST Advanced Bound Methods Tests', () => {
2050
- let bst: BST<number, string>;
2051
-
2052
- // Helper: Generate random number array
2053
- const generateRandomArray = (size: number, min: number, max: number) => {
2054
- return Array.from({ length: size }, () => Math.floor(Math.random() * (max - min + 1)) + min);
2055
- };
2056
-
2057
- beforeEach(() => {
2058
- // Construct a standard test tree
2059
- // Structure:
2060
- // 10
2061
- // / \
2062
- // 5 15
2063
- // / \ / \
2064
- // 2 8 12 20
2065
- // / \
2066
- // 6 9
2067
- bst = new BST<number, string>();
2068
- const keys = [10, 5, 15, 2, 8, 12, 20, 6, 9];
2069
- keys.forEach(k => bst.add(k, `val-${k}`));
2070
- });
2071
-
2072
- describe('Polymorphic Input Support', () => {
2073
- test('should accept raw Key', () => {
2074
- expect(bst.lowerBound(7)?.key).toBe(8);
2075
- expect(bst.upperBound(7)?.key).toBe(8);
2076
- });
2077
-
2078
- test('should accept BSTNode object', () => {
2079
- // Find a node first
2080
- const node5 = bst.getNode(5);
2081
- expect(node5).toBeDefined();
2082
-
2083
- // Use the node as input for lowerBound (should return itself)
2084
- expect(bst.lowerBound(node5)?.key).toBe(5);
2085
-
2086
- // Use the node as input for upperBound (should return next larger)
2087
- expect(bst.upperBound(node5)?.key).toBe(6);
2088
- });
2089
-
2090
- test('should accept Entry tuple [key, value]', () => {
2091
- // Input as [key, value] tuple
2092
- const entry: [number, string] = [7, 'val-7'];
2093
-
2094
- expect(bst.lowerBound(entry)?.key).toBe(8);
2095
- expect(bst.upperBound(entry)?.key).toBe(8);
2096
-
2097
- const existingEntry: [number, string] = [10, 'val-10'];
2098
- expect(bst.lowerBound(existingEntry)?.key).toBe(10);
2099
- expect(bst.upperBound(existingEntry)?.key).toBe(12);
2100
- });
2101
-
2102
- test('should accept Predicate function (Linear Search Fallback)', () => {
2103
- // Predicate: Find first node with key > 11 (Expect 12)
2104
- // Note: Predicate search uses in-order traversal
2105
- const predicate = (node: any) => node.key > 11;
2106
-
2107
- // For predicate, lowerBound and upperBound behave identically
2108
- // (they just return the first match of the predicate)
2109
- expect(bst.lowerBound(predicate)?.key).toBe(12);
2110
- expect(bst.upperBound(predicate)?.key).toBe(12);
2111
-
2112
- // Predicate: Find specific value
2113
- expect(bst.lowerBound(n => n.key === 6)?.key).toBe(6);
2114
- });
2115
- });
2116
-
2117
- describe('Iteration Types with Polymorphic Inputs', () => {
2118
- test('should work recursively with all types', () => {
2119
- const type = 'RECURSIVE';
2120
-
2121
- expect(bst.lowerBound(7, type)?.key).toBe(8);
2122
- expect(bst.lowerBound(bst.getNode(5), type)?.key).toBe(5);
2123
- expect(bst.lowerBound([7, 'val'], type)?.key).toBe(8);
2124
- expect(bst.lowerBound(n => n.key > 11, type)?.key).toBe(12);
2125
- });
2126
-
2127
- test('should work iteratively with all types', () => {
2128
- const type = 'ITERATIVE';
2129
-
2130
- expect(bst.lowerBound(7, type)?.key).toBe(8);
2131
- expect(bst.lowerBound(bst.getNode(5), type)?.key).toBe(5);
2132
- expect(bst.lowerBound([7, 'val'], type)?.key).toBe(8);
2133
- expect(bst.lowerBound(n => n.key > 11, type)?.key).toBe(12);
2134
- });
2135
- });
2136
-
2137
- describe('Complex Edge Cases', () => {
2138
- test('should return undefined for null/undefined input', () => {
2139
- expect(bst.lowerBound(null)).toBeUndefined();
2140
- expect(bst.lowerBound(undefined)).toBeUndefined();
2141
- });
2142
-
2143
- test('should handle predicate returning false for all nodes', () => {
2144
- expect(bst.lowerBound(n => n.key > 100)).toBeUndefined();
2145
- });
2146
- });
2147
-
2148
- describe('Consistency Check (Fuzz Testing)', () => {
2149
- test('All input methods should yield consistent results for Raw Key and Entry', () => {
2150
- const fuzzTree = new BST<number, number>();
2151
- const randomKeys = generateRandomArray(100, 0, 200);
2152
- [...new Set(randomKeys)].forEach(k => fuzzTree.add(k));
2153
-
2154
- const queries = generateRandomArray(50, 0, 200);
2155
-
2156
- queries.forEach(q => {
2157
- // 1. Raw Key
2158
- const resKey = fuzzTree.lowerBound(q);
2159
-
2160
- // 2. Entry
2161
- const resEntry = fuzzTree.lowerBound([q, undefined]);
2162
-
2163
- // Verify consistency between Key and Entry
2164
- expect(resKey?.key).toBe(resEntry?.key);
2165
- });
2166
- });
2167
-
2168
- test('BSTNode input should work correctly', () => {
2169
- const fuzzTree = new BST<number, number>();
2170
- const randomKeys = generateRandomArray(50, 0, 100);
2171
- const uniqueKeys = [...new Set(randomKeys)];
2172
- uniqueKeys.forEach(k => fuzzTree.add(k));
2173
-
2174
- // Test with actual nodes from the tree
2175
- for (const key of uniqueKeys) {
2176
- const node = fuzzTree.getNode(key);
2177
- if (node) {
2178
- // lowerBound with node should return itself (since node.key >= key)
2179
- expect(fuzzTree.lowerBound(node)?.key).toBe(key);
2180
-
2181
- // upperBound with node should return next larger
2182
- const upperRes = fuzzTree.upperBound(node);
2183
- if (upperRes) {
2184
- expect(upperRes.key).toBeGreaterThan(key);
2185
- }
2186
- }
2187
- }
2188
- });
2189
-
2190
- test('Predicate input should find matching nodes', () => {
2191
- const fuzzTree = new BST<number, number>();
2192
- const randomKeys = generateRandomArray(50, 0, 100);
2193
- const uniqueKeys = [...new Set(randomKeys)];
2194
- uniqueKeys.forEach(k => fuzzTree.add(k));
2195
-
2196
- // Test various predicates
2197
- const predicates = [(n: any) => n.key > 50, (n: any) => n.key < 30, (n: any) => n.key >= 25 && n.key <= 75];
2198
-
2199
- predicates.forEach(predicate => {
2200
- const result = fuzzTree.lowerBound(predicate);
2201
- if (result) {
2202
- // Verify the result actually satisfies the predicate
2203
- expect(predicate(result)).toBe(true);
2204
- }
2205
- });
2206
- });
2032
+ // Use higher to find the first key > 19
2033
+ const nextKey = bst.higher(19);
2034
+ // Use ceiling to find the first key >= 14
2035
+ const firstInRange = bst.ceiling(14);
2207
2036
 
2208
- test('Consistency between RECURSIVE and ITERATIVE modes', () => {
2209
- const fuzzTree = new BST<number, number>();
2210
- const randomKeys = generateRandomArray(50, 0, 100);
2211
- [...new Set(randomKeys)].forEach(k => fuzzTree.add(k));
2212
-
2213
- const queries = generateRandomArray(30, 0, 100);
2214
-
2215
- queries.forEach(q => {
2216
- // Test with Key
2217
- const recKey = fuzzTree.lowerBound(q, 'RECURSIVE');
2218
- const iterKey = fuzzTree.lowerBound(q, 'ITERATIVE');
2219
- expect(recKey?.key).toBe(iterKey?.key);
2220
-
2221
- // Test with Entry
2222
- const recEntry = fuzzTree.lowerBound([q, undefined], 'RECURSIVE');
2223
- const iterEntry = fuzzTree.lowerBound([q, undefined], 'ITERATIVE');
2224
- expect(recEntry?.key).toBe(iterEntry?.key);
2225
-
2226
- // Test upperBound too
2227
- const recUpper = fuzzTree.upperBound(q, 'RECURSIVE');
2228
- const iterUpper = fuzzTree.upperBound(q, 'ITERATIVE');
2229
- expect(recUpper?.key).toBe(iterUpper?.key);
2230
- });
2037
+ expect(firstInRange).toBe(15);
2038
+ expect(nextKey).toBe(20);
2231
2039
  });
2232
2040
  });
2233
2041
  });
@@ -2240,319 +2048,318 @@ describe('BST Range Query Methods', () => {
2240
2048
  bst = new BST([10, 5, 15, 3, 7, 13, 17, 1, 4, 6, 9, 11, 14, 16, 19, 20]);
2241
2049
  });
2242
2050
 
2243
- describe('ceilingEntry - finds >= key (minimum value >= target)', () => {
2051
+ describe('ceiling - finds >= key (minimum value >= target)', () => {
2244
2052
  test('should find ceiling when key exists', () => {
2245
- const result = bst.ceilingEntry(10);
2053
+ const result = bst.ceiling(10);
2246
2054
  expect(result).toBeDefined();
2247
- expect(result?.key).toBe(10);
2055
+ expect(result).toBe(10);
2248
2056
  });
2249
2057
 
2250
2058
  test('should find ceiling when key does not exist but higher value exists', () => {
2251
- const result = bst.ceilingEntry(8);
2059
+ const result = bst.ceiling(8);
2252
2060
  expect(result).toBeDefined();
2253
- expect(result?.key).toBe(9);
2061
+ expect(result).toBe(9);
2254
2062
  });
2255
2063
 
2256
2064
  test('should return undefined when no ceiling exists (key greater than all)', () => {
2257
- const result = bst.ceilingEntry(100);
2065
+ const result = bst.ceiling(100);
2258
2066
  expect(result).toBeUndefined();
2259
2067
  });
2260
2068
 
2261
2069
  test('should find minimum element as ceiling for key smaller than all', () => {
2262
- const result = bst.ceilingEntry(-10);
2070
+ const result = bst.ceiling(-10);
2263
2071
  expect(result).toBeDefined();
2264
- expect(result?.key).toBe(1);
2072
+ expect(result).toBe(1);
2265
2073
  });
2266
2074
 
2267
2075
  test('should handle ceiling with node input', () => {
2268
2076
  const targetNode = bst.getNode(7);
2269
2077
  expect(targetNode).toBeDefined();
2270
- const result = bst.ceilingEntry(targetNode!);
2271
- expect(result?.key).toBe(7);
2078
+ const result = bst.ceiling(targetNode!);
2079
+ expect(result).toBe(7);
2272
2080
  });
2273
2081
 
2274
2082
  test('should handle ceiling with entry input', () => {
2275
- const result = bst.ceilingEntry([11, 'test']);
2083
+ const result = bst.ceiling([11, 'test']);
2276
2084
  expect(result).toBeDefined();
2277
- expect(result?.key).toBe(11);
2085
+ expect(result).toBe(11);
2278
2086
  });
2279
2087
 
2280
2088
  test('should handle null/undefined inputs', () => {
2281
- expect(bst.ceilingEntry(null)).toBeUndefined();
2282
- expect(bst.ceilingEntry(undefined)).toBeUndefined();
2089
+ expect(bst.ceiling(null)).toBeUndefined();
2090
+ expect(bst.ceiling(undefined)).toBeUndefined();
2283
2091
  });
2284
2092
 
2285
2093
  test('should work with ITERATIVE mode', () => {
2286
- const result = bst.ceilingEntry(12, 'ITERATIVE');
2094
+ const result = bst.ceiling(12);
2287
2095
  expect(result).toBeDefined();
2288
- expect(result?.key).toBe(13);
2096
+ expect(result).toBe(13);
2289
2097
  });
2290
2098
 
2291
2099
  test('should work with RECURSIVE mode', () => {
2292
- const result = bst.ceilingEntry(12, 'RECURSIVE');
2100
+ const result = bst.ceiling(12);
2293
2101
  expect(result).toBeDefined();
2294
- expect(result?.key).toBe(13);
2102
+ expect(result).toBe(13);
2295
2103
  });
2296
2104
 
2297
2105
  test('should find exact match as ceiling', () => {
2298
- const result = bst.ceilingEntry(15);
2106
+ const result = bst.ceiling(15);
2299
2107
  expect(result).toBeDefined();
2300
- expect(result?.key).toBe(15);
2108
+ expect(result).toBe(15);
2301
2109
  });
2302
2110
  });
2303
2111
 
2304
- describe('higherEntry - finds > key (minimum value > target)', () => {
2112
+ describe('higher - finds > key (minimum value > target)', () => {
2305
2113
  test('should find higher when key exists (exclude exact match)', () => {
2306
- const result = bst.higherEntry(10);
2114
+ const result = bst.higher(10);
2307
2115
  expect(result).toBeDefined();
2308
- expect(result?.key).toBe(11);
2309
- expect(result?.key).not.toBe(10);
2116
+ expect(result).toBe(11);
2117
+ expect(result).not.toBe(10);
2310
2118
  });
2311
2119
 
2312
2120
  test('should find higher when key does not exist', () => {
2313
- const result = bst.higherEntry(8);
2121
+ const result = bst.higher(8);
2314
2122
  expect(result).toBeDefined();
2315
- expect(result?.key).toBe(9);
2123
+ expect(result).toBe(9);
2316
2124
  });
2317
2125
 
2318
2126
  test('should return undefined when no higher exists (key >= all)', () => {
2319
- const result = bst.higherEntry(20);
2127
+ const result = bst.higher(20);
2320
2128
  expect(result).toBeUndefined();
2321
2129
  });
2322
2130
 
2323
2131
  test('should find minimum element as higher for key < all', () => {
2324
- const result = bst.higherEntry(-10);
2132
+ const result = bst.higher(-10);
2325
2133
  expect(result).toBeDefined();
2326
- expect(result?.key).toBe(1);
2134
+ expect(result).toBe(1);
2327
2135
  });
2328
2136
 
2329
2137
  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);
2138
+ const result = bst.higher(7);
2139
+ expect(result).not.toBe(7);
2140
+ expect(result).toBe(9);
2333
2141
  });
2334
2142
 
2335
2143
  test('should handle higher with node input', () => {
2336
2144
  const targetNode = bst.getNode(5);
2337
2145
  expect(targetNode).toBeDefined();
2338
- const result = bst.higherEntry(targetNode!);
2339
- expect(result?.key).toBeGreaterThan(5);
2340
- expect(result?.key).toBe(6);
2146
+ const result = bst.higher(targetNode!);
2147
+ expect(result).toBeGreaterThan(5);
2148
+ expect(result).toBe(6);
2341
2149
  });
2342
2150
 
2343
2151
  test('should work with ITERATIVE mode', () => {
2344
- const result = bst.higherEntry(13, 'ITERATIVE');
2152
+ const result = bst.higher(13);
2345
2153
  expect(result).toBeDefined();
2346
- expect(result?.key).toBe(14);
2154
+ expect(result).toBe(14);
2347
2155
  });
2348
2156
 
2349
2157
  test('should work with RECURSIVE mode', () => {
2350
- const result = bst.higherEntry(13, 'RECURSIVE');
2158
+ const result = bst.higher(13);
2351
2159
  expect(result).toBeDefined();
2352
- expect(result?.key).toBe(14);
2160
+ expect(result).toBe(14);
2353
2161
  });
2354
2162
  });
2355
2163
 
2356
- describe('floorEntry - finds <= key (maximum value <= target)', () => {
2164
+ describe('floor - finds <= key (maximum value <= target)', () => {
2357
2165
  test('should find floor when key exists', () => {
2358
- const result = bst.floorEntry(10);
2166
+ const result = bst.floor(10);
2359
2167
  expect(result).toBeDefined();
2360
- expect(result?.key).toBe(10);
2168
+ expect(result).toBe(10);
2361
2169
  });
2362
2170
 
2363
2171
  test('should find floor when key does not exist but lower value exists', () => {
2364
- const result = bst.floorEntry(12);
2172
+ const result = bst.floor(12);
2365
2173
  expect(result).toBeDefined();
2366
- expect(result?.key).toBe(11);
2174
+ expect(result).toBe(11);
2367
2175
  });
2368
2176
 
2369
2177
  test('should return undefined when no floor exists (key less than all)', () => {
2370
- const result = bst.floorEntry(-10);
2178
+ const result = bst.floor(-10);
2371
2179
  expect(result).toBeUndefined();
2372
2180
  });
2373
2181
 
2374
2182
  test('should find maximum element as floor for key greater than all', () => {
2375
- const result = bst.floorEntry(100);
2183
+ const result = bst.floor(100);
2376
2184
  expect(result).toBeDefined();
2377
- expect(result?.key).toBe(20);
2185
+ expect(result).toBe(20);
2378
2186
  });
2379
2187
 
2380
2188
  test('should handle floor with node input', () => {
2381
2189
  const targetNode = bst.getNode(13);
2382
2190
  expect(targetNode).toBeDefined();
2383
- const result = bst.floorEntry(targetNode!);
2384
- expect(result?.key).toBe(13);
2191
+ const result = bst.floor(targetNode!);
2192
+ expect(result).toBe(13);
2385
2193
  });
2386
2194
 
2387
2195
  test('should handle floor with entry input', () => {
2388
- const result = bst.floorEntry([16, 'test']);
2196
+ const result = bst.floor([16, 'test']);
2389
2197
  expect(result).toBeDefined();
2390
- expect(result?.key).toBe(16);
2198
+ expect(result).toBe(16);
2391
2199
  });
2392
2200
 
2393
2201
  test('should handle null/undefined inputs', () => {
2394
- expect(bst.floorEntry(null)).toBeUndefined();
2395
- expect(bst.floorEntry(undefined)).toBeUndefined();
2202
+ expect(bst.floor(null)).toBeUndefined();
2203
+ expect(bst.floor(undefined)).toBeUndefined();
2396
2204
  });
2397
2205
 
2398
2206
  test('should work with ITERATIVE mode', () => {
2399
- const result = bst.floorEntry(12, 'ITERATIVE');
2207
+ const result = bst.floor(12);
2400
2208
  expect(result).toBeDefined();
2401
- expect(result?.key).toBe(11);
2209
+ expect(result).toBe(11);
2402
2210
  });
2403
2211
 
2404
2212
  test('should work with RECURSIVE mode', () => {
2405
- const result = bst.floorEntry(12, 'RECURSIVE');
2213
+ const result = bst.floor(12);
2406
2214
  expect(result).toBeDefined();
2407
- expect(result?.key).toBe(11);
2215
+ expect(result).toBe(11);
2408
2216
  });
2409
2217
 
2410
2218
  test('should find exact match as floor', () => {
2411
- const result = bst.floorEntry(15);
2219
+ const result = bst.floor(15);
2412
2220
  expect(result).toBeDefined();
2413
- expect(result?.key).toBe(15);
2221
+ expect(result).toBe(15);
2414
2222
  });
2415
2223
 
2416
2224
  test('should correctly find floor between two keys', () => {
2417
- const result = bst.floorEntry(8);
2225
+ const result = bst.floor(8);
2418
2226
  expect(result).toBeDefined();
2419
- expect(result?.key).toBe(7);
2420
- expect(result?.key).toBeLessThan(8);
2227
+ expect(result).toBe(7);
2228
+ expect(result).toBeLessThan(8);
2421
2229
  });
2422
2230
  });
2423
2231
 
2424
- describe('lowerEntry - finds < key (maximum value < target)', () => {
2232
+ describe('lower - finds < key (maximum value < target)', () => {
2425
2233
  test('should find lower when key exists (exclude exact match)', () => {
2426
- const result = bst.lowerEntry(10);
2234
+ const result = bst.lower(10);
2427
2235
  expect(result).toBeDefined();
2428
- expect(result?.key).toBe(9);
2429
- expect(result?.key).not.toBe(10);
2236
+ expect(result).toBe(9);
2237
+ expect(result).not.toBe(10);
2430
2238
  });
2431
2239
 
2432
2240
  test('should find lower when key does not exist', () => {
2433
- const result = bst.lowerEntry(12);
2241
+ const result = bst.lower(12);
2434
2242
  expect(result).toBeDefined();
2435
- expect(result?.key).toBe(11);
2243
+ expect(result).toBe(11);
2436
2244
  });
2437
2245
 
2438
2246
  test('should return undefined when no lower exists (key <= all)', () => {
2439
- const result = bst.lowerEntry(1);
2247
+ const result = bst.lower(1);
2440
2248
  expect(result).toBeUndefined();
2441
2249
  });
2442
2250
 
2443
2251
  test('should find maximum element as lower for key > all', () => {
2444
- const result = bst.lowerEntry(100);
2252
+ const result = bst.lower(100);
2445
2253
  expect(result).toBeDefined();
2446
- expect(result?.key).toBe(20);
2254
+ expect(result).toBe(20);
2447
2255
  });
2448
2256
 
2449
2257
  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);
2258
+ const result = bst.lower(15);
2259
+ expect(result).not.toBe(15);
2260
+ expect(result).toBe(14);
2453
2261
  });
2454
2262
 
2455
2263
  test('should handle lower with node input', () => {
2456
2264
  const targetNode = bst.getNode(13);
2457
2265
  expect(targetNode).toBeDefined();
2458
- const result = bst.lowerEntry(targetNode!);
2459
- expect(result?.key).toBeLessThan(13);
2460
- expect(result?.key).toBe(11);
2266
+ const result = bst.lower(targetNode!);
2267
+ expect(result).toBeLessThan(13);
2268
+ expect(result).toBe(11);
2461
2269
  });
2462
2270
 
2463
2271
  test('should handle lower with entry input', () => {
2464
- const result = bst.lowerEntry([17, 'test']);
2272
+ const result = bst.lower([17, 'test']);
2465
2273
  expect(result).toBeDefined();
2466
- expect(result?.key).toBe(16);
2274
+ expect(result).toBe(16);
2467
2275
  });
2468
2276
 
2469
2277
  test('should work with ITERATIVE mode', () => {
2470
- const result = bst.lowerEntry(14, 'ITERATIVE');
2278
+ const result = bst.lower(14);
2471
2279
  expect(result).toBeDefined();
2472
- expect(result?.key).toBe(13);
2280
+ expect(result).toBe(13);
2473
2281
  });
2474
2282
 
2475
2283
  test('should work with RECURSIVE mode', () => {
2476
- const result = bst.lowerEntry(14, 'RECURSIVE');
2284
+ const result = bst.lower(14);
2477
2285
  expect(result).toBeDefined();
2478
- expect(result?.key).toBe(13);
2286
+ expect(result).toBe(13);
2479
2287
  });
2480
2288
  });
2481
2289
 
2482
2290
  describe('Edge cases and special scenarios', () => {
2483
2291
  test('single element tree - ceiling', () => {
2484
2292
  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();
2293
+ expect(singleBst.ceiling(5)).toBe(5);
2294
+ expect(singleBst.ceiling(3)).toBe(5);
2295
+ expect(singleBst.ceiling(7)).toBeUndefined();
2488
2296
  });
2489
2297
 
2490
2298
  test('single element tree - higher', () => {
2491
2299
  const singleBst = new BST([5]);
2492
- expect(singleBst.higherEntry(5)).toBeUndefined();
2493
- expect(singleBst.higherEntry(3)?.key).toBe(5);
2300
+ expect(singleBst.higher(5)).toBeUndefined();
2301
+ expect(singleBst.higher(3)).toBe(5);
2494
2302
  });
2495
2303
 
2496
2304
  test('single element tree - floor', () => {
2497
2305
  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();
2306
+ expect(singleBst.floor(5)).toBe(5);
2307
+ expect(singleBst.floor(7)).toBe(5);
2308
+ expect(singleBst.floor(3)).toBeUndefined();
2501
2309
  });
2502
2310
 
2503
2311
  test('single element tree - lower', () => {
2504
2312
  const singleBst = new BST([5]);
2505
- expect(singleBst.lowerEntry(5)).toBeUndefined();
2506
- expect(singleBst.lowerEntry(7)?.key).toBe(5);
2313
+ expect(singleBst.lower(5)).toBeUndefined();
2314
+ expect(singleBst.lower(7)).toBe(5);
2507
2315
  });
2508
2316
 
2509
2317
  test('empty tree handling', () => {
2510
2318
  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();
2319
+ expect(emptyBst.ceiling(5)).toBeUndefined();
2320
+ expect(emptyBst.higher(5)).toBeUndefined();
2321
+ expect(emptyBst.floor(5)).toBeUndefined();
2322
+ expect(emptyBst.lower(5)).toBeUndefined();
2515
2323
  });
2516
2324
 
2517
2325
  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);
2326
+ const ceiling = bst.ceiling(5);
2327
+ const floor = bst.floor(6);
2328
+ expect(ceiling).toBe(5);
2329
+ expect(floor).toBe(6);
2523
2330
  });
2524
2331
 
2525
2332
  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);
2333
+ const higher = bst.higher(5);
2334
+ const lower = bst.lower(6);
2335
+ expect(higher).toBe(6);
2336
+ expect(lower).toBe(5);
2530
2337
  });
2531
2338
  });
2532
2339
 
2533
2340
  describe('Predicate-based search', () => {
2534
2341
  test('ceiling with predicate function', () => {
2535
- const result = bst.ceilingEntry((node: BSTNode<number, string>) => node.key >= 10);
2342
+ const result = bst.ceiling((node: BSTNode<number, string>) => node.key >= 10);
2536
2343
  expect(result).toBeDefined();
2537
- expect(result?.key).toBeGreaterThanOrEqual(10);
2344
+ expect(result).toBeGreaterThanOrEqual(10);
2538
2345
  });
2539
2346
 
2540
2347
  test('floor with predicate function', () => {
2541
- const result = bst.floorEntry((node: BSTNode<number, string>) => node.key <= 15);
2348
+ const result = bst.floor((node: BSTNode<number, string>) => node.key <= 15);
2542
2349
  expect(result).toBeDefined();
2543
- expect(result?.key).toBeLessThanOrEqual(15);
2350
+ expect(result).toBeLessThanOrEqual(15);
2544
2351
  });
2545
2352
 
2546
2353
  test('higher with predicate function', () => {
2547
- const result = bst.higherEntry((node: BSTNode<number, string>) => node.key > 10);
2354
+ const result = bst.higher((node: BSTNode<number, string>) => node.key > 10);
2548
2355
  expect(result).toBeDefined();
2549
- expect(result?.key).toBeGreaterThan(10);
2356
+ expect(result).toBeGreaterThan(10);
2550
2357
  });
2551
2358
 
2552
2359
  test('lower with predicate function', () => {
2553
- const result = bst.lowerEntry((node: BSTNode<number, string>) => node.key < 15);
2360
+ const result = bst.lower((node: BSTNode<number, string>) => node.key < 15);
2554
2361
  expect(result).toBeDefined();
2555
- expect(result?.key).toBeLessThan(15);
2362
+ expect(result).toBeLessThan(15);
2556
2363
  });
2557
2364
  });
2558
2365
 
@@ -2564,9 +2371,9 @@ describe('BST Range Query Methods', () => {
2564
2371
 
2565
2372
  // In reverse order tree: keys are stored in descending order
2566
2373
  // ceiling (>=) should still work correctly
2567
- const ceiling = reverseBst.ceilingEntry(10);
2374
+ const ceiling = reverseBst.ceiling(10);
2568
2375
  expect(ceiling).toBeDefined();
2569
- expect(ceiling?.key).toBeLessThanOrEqual(10);
2376
+ expect(ceiling).toBeLessThanOrEqual(10);
2570
2377
  });
2571
2378
 
2572
2379
  test('should work with string comparator', () => {
@@ -2583,36 +2390,36 @@ describe('BST Range Query Methods', () => {
2583
2390
  }
2584
2391
  );
2585
2392
 
2586
- const ceiling = stringBst.ceilingEntry({ name: 'Bob', id: 0 });
2393
+ const ceiling = stringBst.ceiling({ name: 'Bob', id: 0 });
2587
2394
  expect(ceiling).toBeDefined();
2588
- expect(ceiling?.key.name).toBe('Bob');
2395
+ expect(ceiling?.name).toBe('Bob');
2589
2396
  });
2590
2397
  });
2591
2398
 
2592
2399
  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);
2400
+ test('all range methods return keys in order', () => {
2401
+ const ceiling = bst.ceiling(10);
2402
+ const higher = bst.higher(10);
2403
+ const floor = bst.floor(10);
2404
+ const lower = bst.lower(10);
2598
2405
 
2599
- expect(floor?.key).toBeLessThanOrEqual(10);
2600
- expect(ceiling?.key).toBeGreaterThanOrEqual(10);
2601
- expect(higher?.key).toBeGreaterThan(10);
2602
- expect(lower?.key).toBeLessThan(10);
2406
+ expect(floor).toBeLessThanOrEqual(10);
2407
+ expect(ceiling).toBeGreaterThanOrEqual(10);
2408
+ expect(higher).toBeGreaterThan(10);
2409
+ expect(lower).toBeLessThan(10);
2603
2410
  });
2604
2411
 
2605
2412
  test('range query iteration with ceiling/higher', () => {
2606
2413
  const results: number[] = [];
2607
- let node = bst.ceilingEntry(5);
2414
+ let key = bst.ceiling(5);
2608
2415
  let count = 0;
2609
- while (node && node.key <= 15 && count < 20) {
2610
- results.push(node.key);
2611
- node = bst.higherEntry(node.key);
2416
+ while (key && key <= 15 && count < 20) {
2417
+ results.push(key);
2418
+ key = bst.higher(key);
2612
2419
  count++;
2613
2420
  }
2614
2421
 
2615
- // Should iterate through nodes 5, 6, 7, ..., 15
2422
+ // Should iterate through keys 5, 6, 7, ..., 15
2616
2423
  expect(results.length).toBeGreaterThan(0);
2617
2424
  expect(results[0]).toBeGreaterThanOrEqual(5);
2618
2425
  expect(results[results.length - 1]).toBeLessThanOrEqual(15);
@@ -2624,15 +2431,15 @@ describe('BST Range Query Methods', () => {
2624
2431
 
2625
2432
  test('range query iteration with floor/lower', () => {
2626
2433
  const results: number[] = [];
2627
- let node = bst.floorEntry(15);
2434
+ let key = bst.floor(15);
2628
2435
  let count = 0;
2629
- while (node && node.key >= 5 && count < 20) {
2630
- results.push(node.key);
2631
- node = bst.lowerEntry(node.key);
2436
+ while (key && key >= 5 && count < 20) {
2437
+ results.push(key);
2438
+ key = bst.lower(key);
2632
2439
  count++;
2633
2440
  }
2634
2441
 
2635
- // Should iterate through nodes 15, 14, 13, ..., 5
2442
+ // Should iterate through keys 15, 14, 13, ..., 5
2636
2443
  expect(results.length).toBeGreaterThan(0);
2637
2444
  expect(results[0]).toBeLessThanOrEqual(15);
2638
2445
  expect(results[results.length - 1]).toBeGreaterThanOrEqual(5);
@@ -2645,47 +2452,853 @@ describe('BST Range Query Methods', () => {
2645
2452
 
2646
2453
  describe('Boundary value testing', () => {
2647
2454
  test('boundary: ceiling at min value', () => {
2648
- const result = bst.ceilingEntry(1);
2649
- expect(result?.key).toBe(1);
2455
+ const result = bst.ceiling(1);
2456
+ expect(result).toBe(1);
2650
2457
  });
2651
2458
 
2652
2459
  test('boundary: floor at max value', () => {
2653
- const result = bst.floorEntry(20);
2654
- expect(result?.key).toBe(20);
2460
+ const result = bst.floor(20);
2461
+ expect(result).toBe(20);
2655
2462
  });
2656
2463
 
2657
2464
  test('boundary: higher at second-last value', () => {
2658
- const result = bst.higherEntry(19);
2659
- expect(result?.key).toBe(20);
2465
+ const result = bst.higher(19);
2466
+ expect(result).toBe(20);
2660
2467
  });
2661
2468
 
2662
2469
  test('boundary: lower at second value', () => {
2663
- const result = bst.lowerEntry(3);
2664
- expect(result?.key).toBe(1);
2470
+ const result = bst.lower(3);
2471
+ expect(result).toBe(1);
2665
2472
  });
2666
2473
 
2667
2474
  test('boundary: ceiling slightly below min', () => {
2668
- const result = bst.ceilingEntry(0);
2669
- expect(result?.key).toBe(1);
2475
+ const result = bst.ceiling(0);
2476
+ expect(result).toBe(1);
2670
2477
  });
2671
2478
 
2672
2479
  test('boundary: floor slightly above max', () => {
2673
- const result = bst.floorEntry(21);
2674
- expect(result?.key).toBe(20);
2480
+ const result = bst.floor(21);
2481
+ expect(result).toBe(20);
2675
2482
  });
2676
2483
 
2677
2484
  test('boundary: higher at max (should be undefined)', () => {
2678
- const result = bst.higherEntry(20);
2485
+ const result = bst.higher(20);
2679
2486
  expect(result).toBeUndefined();
2680
2487
  });
2681
2488
 
2682
2489
  test('boundary: lower at min (should be undefined)', () => {
2683
- const result = bst.lowerEntry(1);
2490
+ const result = bst.lower(1);
2684
2491
  expect(result).toBeUndefined();
2685
2492
  });
2686
2493
  });
2687
2494
  });
2688
2495
 
2496
+ describe('BST Comparator Tests', () => {
2497
+ describe('Default Comparator with Primitive Types', () => {
2498
+ let bst: BST<number>;
2499
+
2500
+ beforeEach(() => {
2501
+ bst = new BST<number>();
2502
+ });
2503
+
2504
+ it('should compare two numbers correctly - a > b', () => {
2505
+ const result = bst['_compare'](5, 3);
2506
+ expect(result).toBe(1);
2507
+ });
2508
+
2509
+ it('should compare two numbers correctly - a < b', () => {
2510
+ const result = bst['_compare'](2, 8);
2511
+ expect(result).toBe(-1);
2512
+ });
2513
+
2514
+ it('should compare two numbers correctly - a === b', () => {
2515
+ const result = bst['_compare'](5, 5);
2516
+ expect(result).toBe(0);
2517
+ });
2518
+
2519
+ it('should compare negative numbers correctly', () => {
2520
+ const result1 = bst['_compare'](-5, -3);
2521
+ const result2 = bst['_compare'](-10, 0);
2522
+ expect(result1).toBe(-1);
2523
+ expect(result2).toBe(-1);
2524
+ });
2525
+
2526
+ it('should compare zero correctly', () => {
2527
+ const result1 = bst['_compare'](0, 5);
2528
+ const result2 = bst['_compare'](0, 0);
2529
+ const result3 = bst['_compare'](-5, 0);
2530
+ expect(result1).toBe(-1);
2531
+ expect(result2).toBe(0);
2532
+ expect(result3).toBe(-1);
2533
+ });
2534
+
2535
+ it('should compare decimal numbers correctly', () => {
2536
+ const result1 = bst['_compare'](3.14, 3.15);
2537
+ const result2 = bst['_compare'](2.5, 2.5);
2538
+ expect(result1).toBe(-1);
2539
+ expect(result2).toBe(0);
2540
+ });
2541
+
2542
+ it('should compare very large numbers correctly', () => {
2543
+ const result1 = bst['_compare'](Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER - 1);
2544
+ const result2 = bst['_compare'](1e10, 1e9);
2545
+ expect(result1).toBe(1);
2546
+ expect(result2).toBe(1);
2547
+ });
2548
+ });
2549
+
2550
+ describe('Default Comparator with String Types', () => {
2551
+ let bst: BST<string>;
2552
+
2553
+ beforeEach(() => {
2554
+ bst = new BST<string>();
2555
+ });
2556
+
2557
+ it('should compare strings alphabetically - a > b', () => {
2558
+ const result = bst['_compare']('zebra', 'apple');
2559
+ expect(result).toBe(1);
2560
+ });
2561
+
2562
+ it('should compare strings alphabetically - a < b', () => {
2563
+ const result = bst['_compare']('apple', 'zebra');
2564
+ expect(result).toBe(-1);
2565
+ });
2566
+
2567
+ it('should compare identical strings', () => {
2568
+ const result = bst['_compare']('hello', 'hello');
2569
+ expect(result).toBe(0);
2570
+ });
2571
+
2572
+ it('should compare string prefixes correctly', () => {
2573
+ const result1 = bst['_compare']('app', 'apple');
2574
+ const result2 = bst['_compare']('apple', 'app');
2575
+ expect(result1).toBe(-1);
2576
+ expect(result2).toBe(1);
2577
+ });
2578
+
2579
+ it('should compare case-sensitive strings', () => {
2580
+ const result1 = bst['_compare']('Apple', 'apple');
2581
+ const result2 = bst['_compare']('apple', 'Apple');
2582
+ expect(result1).toBe(-1);
2583
+ expect(result2).toBe(1);
2584
+ });
2585
+
2586
+ it('should compare empty strings', () => {
2587
+ const result1 = bst['_compare']('', '');
2588
+ const result2 = bst['_compare']('', 'a');
2589
+ const result3 = bst['_compare']('a', '');
2590
+ expect(result1).toBe(0);
2591
+ expect(result2).toBe(-1);
2592
+ expect(result3).toBe(1);
2593
+ });
2594
+
2595
+ it('should compare special characters in strings', () => {
2596
+ const result1 = bst['_compare']('!', 'a');
2597
+ const result2 = bst['_compare']('a', '1');
2598
+ expect(result1).toBe(-1);
2599
+ expect(result2).toBe(1);
2600
+ });
2601
+ });
2602
+
2603
+ describe('Custom Comparator', () => {
2604
+ interface Person {
2605
+ name: string;
2606
+ age: number;
2607
+ }
2608
+
2609
+ it('should accept custom comparator for objects - compare by age', () => {
2610
+ const comparator = (a: Person, b: Person): number => {
2611
+ if (a.age > b.age) return 1;
2612
+ if (a.age < b.age) return -1;
2613
+ return 0;
2614
+ };
2615
+
2616
+ const bst = new BST<Person>([], { comparator });
2617
+
2618
+ const p1 = { name: 'Alice', age: 30 };
2619
+ const p2 = { name: 'Bob', age: 25 };
2620
+ const p3 = { name: 'Charlie', age: 30 };
2621
+
2622
+ expect(bst['_compare'](p1, p2)).toBe(1);
2623
+ expect(bst['_compare'](p2, p1)).toBe(-1);
2624
+ expect(bst['_compare'](p1, p3)).toBe(0);
2625
+ });
2626
+
2627
+ it('should accept custom comparator - compare by name length', () => {
2628
+ const comparator = (a: string, b: string): number => {
2629
+ if (a.length > b.length) return 1;
2630
+ if (a.length < b.length) return -1;
2631
+ return 0;
2632
+ };
2633
+
2634
+ const bst = new BST<string>([], { comparator });
2635
+
2636
+ expect(bst['_compare']('hello', 'hi')).toBe(1);
2637
+ expect(bst['_compare']('hi', 'hello')).toBe(-1);
2638
+ expect(bst['_compare']('abc', 'def')).toBe(0);
2639
+ });
2640
+
2641
+ it('should accept custom comparator - reverse order', () => {
2642
+ const comparator = (a: number, b: number): number => {
2643
+ if (a < b) return 1;
2644
+ if (a > b) return -1;
2645
+ return 0;
2646
+ };
2647
+
2648
+ const bst = new BST<number>([], { comparator });
2649
+
2650
+ expect(bst['_compare'](5, 3)).toBe(-1);
2651
+ expect(bst['_compare'](2, 8)).toBe(1);
2652
+ expect(bst['_compare'](5, 5)).toBe(0);
2653
+ });
2654
+
2655
+ it('should throw error when comparing object types without custom comparator', () => {
2656
+ const bst = new BST<{ value: number }>();
2657
+
2658
+ expect(() => {
2659
+ bst['_compare']({ value: 1 }, { value: 2 });
2660
+ }).toThrow("When comparing object type keys, a custom comparator must be provided in the constructor's options!");
2661
+ });
2662
+ });
2663
+
2664
+ describe('Comparator Usage in BST Operations', () => {
2665
+ let bst: BST<number>;
2666
+
2667
+ beforeEach(() => {
2668
+ bst = new BST<number>();
2669
+ });
2670
+
2671
+ it('should correctly insert elements based on comparator', () => {
2672
+ bst.add(10);
2673
+ bst.add(5);
2674
+ bst.add(15);
2675
+ bst.add(3);
2676
+ bst.add(7);
2677
+
2678
+ expect(bst.has(10)).toBe(true);
2679
+ expect(bst.has(5)).toBe(true);
2680
+ expect(bst.has(15)).toBe(true);
2681
+ expect(bst.has(3)).toBe(true);
2682
+ expect(bst.has(7)).toBe(true);
2683
+ expect(bst.size).toBe(5);
2684
+ });
2685
+
2686
+ it('should maintain BST property with in-order traversal', () => {
2687
+ bst.addMany([11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]);
2688
+
2689
+ const inOrder: (number | undefined)[] = bst.dfs(node => node?.key);
2690
+
2691
+ for (let i = 1; i < inOrder.length; i++) {
2692
+ expect(inOrder[i]! >= inOrder[i - 1]!).toBe(true);
2693
+ }
2694
+ });
2695
+
2696
+ it('should correctly find min and max using comparator', () => {
2697
+ bst.addMany([15, 10, 20, 8, 12, 18, 25]);
2698
+
2699
+ const arr = Array.from(bst.keys());
2700
+ const min = Math.min(...arr);
2701
+ const max = Math.max(...arr);
2702
+
2703
+ expect(bst.has(min)).toBe(true);
2704
+ expect(bst.has(max)).toBe(true);
2705
+ });
2706
+
2707
+ it('should correctly delete elements maintaining BST property', () => {
2708
+ bst.addMany([10, 5, 15, 3, 7, 12, 18]);
2709
+ bst.delete(10);
2710
+
2711
+ expect(bst.has(10)).toBe(false);
2712
+ const inOrder: (number | undefined)[] = bst.dfs(node => node?.key);
2713
+
2714
+ for (let i = 1; i < inOrder.length; i++) {
2715
+ expect(inOrder[i]! >= inOrder[i - 1]!).toBe(true);
2716
+ }
2717
+ });
2718
+
2719
+ it('should correctly search using comparator', () => {
2720
+ bst.addMany([20, 10, 30, 5, 15, 25, 35]);
2721
+
2722
+ const result = bst.search(15);
2723
+ expect(result.length).toBeGreaterThan(0);
2724
+ expect(result[0]).toBe(15);
2725
+ });
2726
+ });
2727
+
2728
+ describe('Comparator Edge Cases', () => {
2729
+ describe('with numbers', () => {
2730
+ let bst: BST<number>;
2731
+
2732
+ beforeEach(() => {
2733
+ bst = new BST<number>();
2734
+ });
2735
+
2736
+ it('should handle Infinity correctly', () => {
2737
+ const result1 = bst['_compare'](Infinity, 100);
2738
+ const result2 = bst['_compare'](100, Infinity);
2739
+ expect(result1).toBe(1);
2740
+ expect(result2).toBe(-1);
2741
+ });
2742
+
2743
+ it('should handle -Infinity correctly', () => {
2744
+ const result1 = bst['_compare'](-Infinity, -100);
2745
+ const result2 = bst['_compare'](-100, -Infinity);
2746
+ expect(result1).toBe(-1);
2747
+ expect(result2).toBe(1);
2748
+ });
2749
+
2750
+ it('should handle NaN correctly', () => {
2751
+ const result1 = bst['_compare'](NaN, 5);
2752
+ const result2 = bst['_compare'](5, NaN);
2753
+ expect(result1).toBe(0);
2754
+ expect(result2).toBe(0);
2755
+ });
2756
+ });
2757
+
2758
+ describe('with strings', () => {
2759
+ let bst: BST<string>;
2760
+
2761
+ beforeEach(() => {
2762
+ bst = new BST<string>();
2763
+ });
2764
+
2765
+ it('should handle Unicode characters', () => {
2766
+ const result1 = bst['_compare']('😀', 'abc');
2767
+ const result2 = bst['_compare']('中文', 'English');
2768
+ expect(typeof result1).toBe('number');
2769
+ expect(typeof result2).toBe('number');
2770
+ });
2771
+
2772
+ it('should handle whitespace strings', () => {
2773
+ const result1 = bst['_compare'](' ', ' ');
2774
+ const result2 = bst['_compare']('\n', '\t');
2775
+ expect(typeof result1).toBe('number');
2776
+ expect(typeof result2).toBe('number');
2777
+ });
2778
+
2779
+ it('should maintain consistency with multiple comparisons', () => {
2780
+ const a = 'apple';
2781
+ const b = 'banana';
2782
+ const c = 'cherry';
2783
+
2784
+ const ab = bst['_compare'](a, b);
2785
+ const bc = bst['_compare'](b, c);
2786
+ const ac = bst['_compare'](a, c);
2787
+
2788
+ if (ab < 0 && bc < 0) {
2789
+ expect(ac).toBeLessThan(0);
2790
+ }
2791
+ });
2792
+ });
2793
+ });
2794
+
2795
+ describe('Comparator with BST Bound Operations', () => {
2796
+ let bst: BST<number>;
2797
+
2798
+ beforeEach(() => {
2799
+ bst = new BST<number>();
2800
+ bst.addMany([10, 5, 15, 3, 7, 12, 18, 1, 4, 6, 8, 11, 13, 16, 20]);
2801
+ });
2802
+
2803
+ it('should find ceiling using comparator', () => {
2804
+ const result = bst.ceiling(7);
2805
+ expect(result).toBe(7);
2806
+
2807
+ const result2 = bst.ceiling(7.5);
2808
+ expect(result2).toBeGreaterThanOrEqual(7.5);
2809
+ });
2810
+
2811
+ it('should find floor using comparator', () => {
2812
+ const result = bst.floor(7);
2813
+ expect(result).toBe(7);
2814
+
2815
+ const result2 = bst.floor(7.5);
2816
+ expect(result2!).toBeLessThanOrEqual(7.5);
2817
+ });
2818
+
2819
+ it('should find higher using comparator', () => {
2820
+ const result = bst.higher(7);
2821
+ expect(result).toBeGreaterThan(7);
2822
+ });
2823
+
2824
+ it('should find lower using comparator', () => {
2825
+ const result = bst.lower(7);
2826
+ expect(result).toBeLessThan(7);
2827
+ });
2828
+ });
2829
+
2830
+ describe('Comparator Consistency', () => {
2831
+ let bst: BST<number>;
2832
+
2833
+ beforeEach(() => {
2834
+ bst = new BST<number>();
2835
+ });
2836
+
2837
+ it('should satisfy reflexivity: a compared with itself returns 0', () => {
2838
+ const values = [0, 1, -1, 100, -100, 0.5];
2839
+
2840
+ for (const val of values) {
2841
+ expect(bst['_compare'](val, val)).toBe(0);
2842
+ }
2843
+ });
2844
+
2845
+ it('should satisfy antisymmetry: if a > b then b < a', () => {
2846
+ const pairs = [
2847
+ [5, 3],
2848
+ [10, 2],
2849
+ [100, 1]
2850
+ ];
2851
+
2852
+ for (const [a, b] of pairs) {
2853
+ const cmp1 = bst['_compare'](a, b);
2854
+ const cmp2 = bst['_compare'](b, a);
2855
+ expect(Math.sign(cmp1)).toBe(-Math.sign(cmp2));
2856
+ }
2857
+ });
2858
+
2859
+ it('should satisfy transitivity: if a < b and b < c then a < c', () => {
2860
+ const a = 1;
2861
+ const b = 5;
2862
+ const c = 10;
2863
+
2864
+ const cmpAB = bst['_compare'](a, b);
2865
+ const cmpBC = bst['_compare'](b, c);
2866
+ const cmpAC = bst['_compare'](a, c);
2867
+
2868
+ if (cmpAB < 0 && cmpBC < 0) {
2869
+ expect(cmpAC).toBeLessThan(0);
2870
+ }
2871
+ });
2872
+ });
2873
+
2874
+ describe('Custom Comparator with BST Operations', () => {
2875
+ interface Student {
2876
+ name: string;
2877
+ grade: number;
2878
+ }
2879
+
2880
+ it('should work with custom comparator for complex operations', () => {
2881
+ const comparator = (a: Student, b: Student): number => {
2882
+ if (a.grade !== b.grade) {
2883
+ return a.grade > b.grade ? 1 : -1;
2884
+ }
2885
+ return a.name.localeCompare(b.name);
2886
+ };
2887
+
2888
+ const bst = new BST<Student>([], { comparator });
2889
+
2890
+ const students: Student[] = [
2891
+ { name: 'Alice', grade: 85 },
2892
+ { name: 'Bob', grade: 90 },
2893
+ { name: 'Charlie', grade: 85 },
2894
+ { name: 'David', grade: 95 }
2895
+ ];
2896
+
2897
+ students.forEach(s => bst.add(s));
2898
+
2899
+ expect(bst.size).toBe(4);
2900
+ expect(bst.has(students[0])).toBe(true);
2901
+ });
2902
+
2903
+ it('should handle custom comparator with add and search', () => {
2904
+ const comparator = (a: number[], b: number[]): number => {
2905
+ const sumA = a.reduce((acc, val) => acc + val, 0);
2906
+ const sumB = b.reduce((acc, val) => acc + val, 0);
2907
+ if (sumA > sumB) return 1;
2908
+ if (sumA < sumB) return -1;
2909
+ return 0;
2910
+ };
2911
+
2912
+ const bst = new BST<number[]>([], { comparator });
2913
+
2914
+ bst.add([1, 2, 3]);
2915
+ bst.add([2, 2, 2]);
2916
+ bst.add([1, 1, 1]);
2917
+
2918
+ expect(bst.size).toBeGreaterThan(0);
2919
+ });
2920
+ });
2921
+
2922
+ describe('Composite Key Comparator Tests', () => {
2923
+ interface CompositeKey {
2924
+ departmentId: number;
2925
+ employeeId: number;
2926
+ }
2927
+
2928
+ it('should compare composite keys by multiple fields - primary then secondary', () => {
2929
+ const comparator = (a: CompositeKey, b: CompositeKey): number => {
2930
+ if (a.departmentId !== b.departmentId) {
2931
+ return a.departmentId > b.departmentId ? 1 : -1;
2932
+ }
2933
+ if (a.employeeId !== b.employeeId) {
2934
+ return a.employeeId > b.employeeId ? 1 : -1;
2935
+ }
2936
+ return 0;
2937
+ };
2938
+
2939
+ const bst = new BST<CompositeKey>([], { comparator });
2940
+
2941
+ const key1 = { departmentId: 1, employeeId: 101 };
2942
+ const key2 = { departmentId: 1, employeeId: 102 };
2943
+ const key3 = { departmentId: 2, employeeId: 101 };
2944
+
2945
+ expect(bst['_compare'](key1, key2)).toBe(-1);
2946
+ expect(bst['_compare'](key2, key3)).toBe(-1);
2947
+ expect(bst['_compare'](key1, key1)).toBe(0);
2948
+ });
2949
+
2950
+ it('should maintain BST property with composite keys', () => {
2951
+ const comparator = (a: CompositeKey, b: CompositeKey): number => {
2952
+ if (a.departmentId !== b.departmentId) {
2953
+ return a.departmentId > b.departmentId ? 1 : -1;
2954
+ }
2955
+ return a.employeeId > b.employeeId ? 1 : a.employeeId < b.employeeId ? -1 : 0;
2956
+ };
2957
+
2958
+ const bst = new BST<CompositeKey>([], { comparator });
2959
+
2960
+ const keys = [
2961
+ { departmentId: 2, employeeId: 105 },
2962
+ { departmentId: 1, employeeId: 101 },
2963
+ { departmentId: 1, employeeId: 103 },
2964
+ { departmentId: 2, employeeId: 102 },
2965
+ { departmentId: 1, employeeId: 102 }
2966
+ ];
2967
+
2968
+ keys.forEach(k => bst.add(k));
2969
+
2970
+ expect(bst.size).toBe(5);
2971
+ const inOrder = bst.dfs(node => node?.key);
2972
+
2973
+ for (let i = 1; i < inOrder.length; i++) {
2974
+ const cmp = comparator(inOrder[i - 1]!, inOrder[i]!);
2975
+ expect(cmp).toBeLessThanOrEqual(0);
2976
+ }
2977
+ });
2978
+
2979
+ it('should search with composite keys', () => {
2980
+ const comparator = (a: CompositeKey, b: CompositeKey): number => {
2981
+ if (a.departmentId !== b.departmentId) {
2982
+ return a.departmentId > b.departmentId ? 1 : -1;
2983
+ }
2984
+ return a.employeeId > b.employeeId ? 1 : a.employeeId < b.employeeId ? -1 : 0;
2985
+ };
2986
+
2987
+ const bst = new BST<CompositeKey>([], { comparator });
2988
+
2989
+ const keys = [
2990
+ { departmentId: 1, employeeId: 101 },
2991
+ { departmentId: 1, employeeId: 103 },
2992
+ { departmentId: 2, employeeId: 102 }
2993
+ ];
2994
+
2995
+ keys.forEach(k => bst.add(k));
2996
+
2997
+ const searchKey = keys[1];
2998
+ const result = bst.search(searchKey);
2999
+
3000
+ expect(result.length).toBeGreaterThan(0);
3001
+ expect(result[0]).toEqual(searchKey);
3002
+ });
3003
+
3004
+ it('should handle deletion with composite keys', () => {
3005
+ const comparator = (a: CompositeKey, b: CompositeKey): number => {
3006
+ if (a.departmentId !== b.departmentId) {
3007
+ return a.departmentId > b.departmentId ? 1 : -1;
3008
+ }
3009
+ return a.employeeId > b.employeeId ? 1 : a.employeeId < b.employeeId ? -1 : 0;
3010
+ };
3011
+
3012
+ const bst = new BST<CompositeKey>([], { comparator });
3013
+
3014
+ const keys = [
3015
+ { departmentId: 1, employeeId: 101 },
3016
+ { departmentId: 1, employeeId: 103 },
3017
+ { departmentId: 2, employeeId: 102 }
3018
+ ];
3019
+
3020
+ keys.forEach(k => bst.add(k));
3021
+
3022
+ const keyToDelete = keys[1];
3023
+ const deleted = bst.delete(keyToDelete);
3024
+
3025
+ expect(deleted.length).toBeGreaterThan(0);
3026
+ expect(bst.has(keyToDelete)).toBe(false);
3027
+ expect(bst.size).toBe(2);
3028
+ });
3029
+
3030
+ it('should find ceiling/floor with composite keys', () => {
3031
+ const comparator = (a: CompositeKey, b: CompositeKey): number => {
3032
+ if (a.departmentId !== b.departmentId) {
3033
+ return a.departmentId > b.departmentId ? 1 : -1;
3034
+ }
3035
+ return a.employeeId > b.employeeId ? 1 : a.employeeId < b.employeeId ? -1 : 0;
3036
+ };
3037
+
3038
+ const bst = new BST<CompositeKey>([], { comparator });
3039
+
3040
+ const keys = [
3041
+ { departmentId: 1, employeeId: 101 },
3042
+ { departmentId: 1, employeeId: 105 },
3043
+ { departmentId: 2, employeeId: 102 }
3044
+ ];
3045
+
3046
+ keys.forEach(k => bst.add(k));
3047
+
3048
+ const searchKey = { departmentId: 1, employeeId: 103 };
3049
+ const ceiling = bst.ceiling(searchKey);
3050
+ const floor = bst.floor(searchKey);
3051
+
3052
+ expect(ceiling).toBeDefined();
3053
+ expect(floor).toBeDefined();
3054
+ });
3055
+ });
3056
+
3057
+ describe('Key-Value Storage with Comparator', () => {
3058
+ interface PersonKey {
3059
+ id: number;
3060
+ country: string;
3061
+ }
3062
+
3063
+ interface PersonValue {
3064
+ name: string;
3065
+ email: string;
3066
+ age: number;
3067
+ }
3068
+
3069
+ it('should store and retrieve key-value pairs with composite keys', () => {
3070
+ const comparator = (a: PersonKey, b: PersonKey): number => {
3071
+ const countryCompare = a.country.localeCompare(b.country);
3072
+ if (countryCompare !== 0) return countryCompare;
3073
+ return a.id > b.id ? 1 : a.id < b.id ? -1 : 0;
3074
+ };
3075
+
3076
+ const bst = new BST<PersonKey, PersonValue>([], { comparator, isMapMode: true });
3077
+
3078
+ const key1: PersonKey = { id: 1, country: 'USA' };
3079
+ const value1: PersonValue = { name: 'Alice', email: 'alice@example.com', age: 30 };
3080
+
3081
+ const key2: PersonKey = { id: 2, country: 'Canada' };
3082
+ const value2: PersonValue = { name: 'Bob', email: 'bob@example.com', age: 25 };
3083
+
3084
+ bst.add([key1, value1]);
3085
+ bst.add([key2, value2]);
3086
+
3087
+ expect(bst.size).toBe(2);
3088
+ expect(bst.get(key1)).toEqual(value1);
3089
+ expect(bst.get(key2)).toEqual(value2);
3090
+ });
3091
+
3092
+ it('should update values when adding duplicate keys', () => {
3093
+ const comparator = (a: PersonKey, b: PersonKey): number => {
3094
+ const countryCompare = a.country.localeCompare(b.country);
3095
+ if (countryCompare !== 0) return countryCompare;
3096
+ return a.id > b.id ? 1 : a.id < b.id ? -1 : 0;
3097
+ };
3098
+
3099
+ const bst = new BST<PersonKey, PersonValue>([], { comparator, isMapMode: true });
3100
+
3101
+ const key: PersonKey = { id: 1, country: 'USA' };
3102
+ const value1: PersonValue = { name: 'Alice', email: 'alice@example.com', age: 30 };
3103
+ const value2: PersonValue = { name: 'Alice Updated', email: 'alice.new@example.com', age: 31 };
3104
+
3105
+ bst.add([key, value1]);
3106
+ expect(bst.get(key)).toEqual(value1);
3107
+
3108
+ bst.add([key, value2]);
3109
+ expect(bst.size).toBe(1);
3110
+ expect(bst.get(key)).toEqual(value2);
3111
+ });
3112
+
3113
+ it('should retrieve all entries in sorted order by key', () => {
3114
+ const comparator = (a: PersonKey, b: PersonKey): number => {
3115
+ const countryCompare = a.country.localeCompare(b.country);
3116
+ if (countryCompare !== 0) return countryCompare;
3117
+ return a.id > b.id ? 1 : a.id < b.id ? -1 : 0;
3118
+ };
3119
+
3120
+ const bst = new BST<PersonKey, PersonValue>([], { comparator, isMapMode: true });
3121
+
3122
+ const entries: Array<[PersonKey, PersonValue]> = [
3123
+ [
3124
+ { id: 1, country: 'USA' },
3125
+ { name: 'Alice', email: 'alice@usa.com', age: 30 }
3126
+ ],
3127
+ [
3128
+ { id: 2, country: 'Canada' },
3129
+ { name: 'Bob', email: 'bob@ca.com', age: 25 }
3130
+ ],
3131
+ [
3132
+ { id: 1, country: 'Canada' },
3133
+ { name: 'Charlie', email: 'charlie@ca.com', age: 28 }
3134
+ ]
3135
+ ];
3136
+
3137
+ entries.forEach(([key, value]) => bst.add([key, value]));
3138
+
3139
+ expect(bst.size).toBe(3);
3140
+
3141
+ const values: (PersonValue | undefined)[] = [];
3142
+ for (const [key] of entries) {
3143
+ const value = bst.get(key);
3144
+ if (value) values.push(value);
3145
+ }
3146
+
3147
+ expect(values.length).toBeGreaterThan(0);
3148
+ });
3149
+
3150
+ it('should delete key-value pairs correctly', () => {
3151
+ const comparator = (a: PersonKey, b: PersonKey): number => {
3152
+ const countryCompare = a.country.localeCompare(b.country);
3153
+ if (countryCompare !== 0) return countryCompare;
3154
+ return a.id > b.id ? 1 : a.id < b.id ? -1 : 0;
3155
+ };
3156
+
3157
+ const bst = new BST<PersonKey, PersonValue>([], { comparator, isMapMode: true });
3158
+
3159
+ const key1: PersonKey = { id: 1, country: 'USA' };
3160
+ const value1: PersonValue = { name: 'Alice', email: 'alice@example.com', age: 30 };
3161
+
3162
+ const key2: PersonKey = { id: 2, country: 'Canada' };
3163
+ const value2: PersonValue = { name: 'Bob', email: 'bob@example.com', age: 25 };
3164
+
3165
+ bst.add([key1, value1]);
3166
+ bst.add([key2, value2]);
3167
+
3168
+ bst.delete(key1);
3169
+
3170
+ expect(bst.has(key1)).toBe(false);
3171
+ expect(bst.has(key2)).toBe(true);
3172
+ expect(bst.size).toBe(1);
3173
+ expect(bst.get(key1)).toBeUndefined();
3174
+ });
3175
+
3176
+ it('should search and retrieve values with composite keys', () => {
3177
+ const comparator = (a: PersonKey, b: PersonKey): number => {
3178
+ const countryCompare = a.country.localeCompare(b.country);
3179
+ if (countryCompare !== 0) return countryCompare;
3180
+ return a.id > b.id ? 1 : a.id < b.id ? -1 : 0;
3181
+ };
3182
+
3183
+ const bst = new BST<PersonKey, PersonValue>([], { comparator, isMapMode: true });
3184
+
3185
+ const entries: Array<[PersonKey, PersonValue]> = [
3186
+ [
3187
+ { id: 1, country: 'USA' },
3188
+ { name: 'Alice', email: 'alice@usa.com', age: 30 }
3189
+ ],
3190
+ [
3191
+ { id: 2, country: 'USA' },
3192
+ { name: 'Amy', email: 'amy@usa.com', age: 28 }
3193
+ ],
3194
+ [
3195
+ { id: 1, country: 'Canada' },
3196
+ { name: 'Bob', email: 'bob@ca.com', age: 25 }
3197
+ ]
3198
+ ];
3199
+
3200
+ entries.forEach(([key, value]) => bst.add([key, value]));
3201
+
3202
+ const searchKey: PersonKey = entries[1][0];
3203
+ const value = bst.get(searchKey);
3204
+
3205
+ expect(value).toEqual({ name: 'Amy', email: 'amy@usa.com', age: 28 });
3206
+ });
3207
+
3208
+ it('should map over key-value pairs maintaining comparator order', () => {
3209
+ const comparator = (a: PersonKey, b: PersonKey): number => {
3210
+ const countryCompare = a.country.localeCompare(b.country);
3211
+ if (countryCompare !== 0) return countryCompare;
3212
+ return a.id > b.id ? 1 : a.id < b.id ? -1 : 0;
3213
+ };
3214
+
3215
+ const bst = new BST<PersonKey, PersonValue>([], { comparator, isMapMode: true });
3216
+
3217
+ const entries: Array<[PersonKey, PersonValue]> = [
3218
+ [
3219
+ { id: 1, country: 'USA' },
3220
+ { name: 'Alice', email: 'alice@usa.com', age: 30 }
3221
+ ],
3222
+ [
3223
+ { id: 2, country: 'Canada' },
3224
+ { name: 'Bob', email: 'bob@ca.com', age: 25 }
3225
+ ]
3226
+ ];
3227
+
3228
+ entries.forEach(([key, value]) => bst.add([key, value]));
3229
+
3230
+ const mapped = bst.map((value, key) => [key, value?.name], { comparator, isMapMode: false });
3231
+
3232
+ expect(mapped.size).toBe(2);
3233
+ const names = Array.from(mapped.values());
3234
+ expect(names).toContain('Alice');
3235
+ expect(names).toContain('Bob');
3236
+ });
3237
+
3238
+ it('should perform range search on key-value pairs', () => {
3239
+ const comparator = (a: number, b: number): number => {
3240
+ return a > b ? 1 : a < b ? -1 : 0;
3241
+ };
3242
+
3243
+ const bst = new BST<number, string>([], { comparator, isMapMode: true });
3244
+
3245
+ for (let i = 1; i <= 10; i++) {
3246
+ bst.add([i, `value-${i}`]);
3247
+ }
3248
+
3249
+ const result = bst.rangeSearch([3, 7]);
3250
+
3251
+ expect(result.length).toBeGreaterThan(0);
3252
+ result.forEach(key => {
3253
+ expect(key).toBeGreaterThanOrEqual(3);
3254
+ expect(key).toBeLessThanOrEqual(7);
3255
+ });
3256
+ });
3257
+
3258
+ it('should maintain sorted iteration over key-value pairs', () => {
3259
+ const comparator = (a: { priority: number; id: number }, b: { priority: number; id: number }): number => {
3260
+ if (a.priority !== b.priority) {
3261
+ return a.priority > b.priority ? 1 : -1;
3262
+ }
3263
+ return a.id > b.id ? 1 : a.id < b.id ? -1 : 0;
3264
+ };
3265
+
3266
+ type TaskKey = { priority: number; id: number };
3267
+ type TaskValue = { title: string; completed: boolean };
3268
+
3269
+ const bst = new BST<TaskKey, TaskValue>([], { comparator, isMapMode: true });
3270
+
3271
+ const tasks: Array<[TaskKey, TaskValue]> = [
3272
+ [
3273
+ { priority: 2, id: 1 },
3274
+ { title: 'Task 1', completed: false }
3275
+ ],
3276
+ [
3277
+ { priority: 1, id: 2 },
3278
+ { title: 'Task 2', completed: false }
3279
+ ],
3280
+ [
3281
+ { priority: 3, id: 3 },
3282
+ { title: 'Task 3', completed: true }
3283
+ ],
3284
+ [
3285
+ { priority: 1, id: 1 },
3286
+ { title: 'Task 4', completed: false }
3287
+ ]
3288
+ ];
3289
+
3290
+ tasks.forEach(([key, value]) => bst.add([key, value]));
3291
+
3292
+ expect(bst.size).toBe(4);
3293
+
3294
+ const inOrder = bst.dfs(node => node?.key.priority);
3295
+ for (let i = 1; i < inOrder.length; i++) {
3296
+ expect(inOrder[i]! >= inOrder[i - 1]!).toBe(true);
3297
+ }
3298
+ });
3299
+ });
3300
+ });
3301
+
2689
3302
  describe('classic use', () => {
2690
3303
  it('@example basic BST creation and add operation', () => {
2691
3304
  // Create a simple BST with numeric keys
@@ -2823,7 +3436,7 @@ describe('classic use', () => {
2823
3436
  return findFirstCommon(path1, path2);
2824
3437
  };
2825
3438
 
2826
- function findFirstCommon(arr1: number[], arr2: number[]): number | undefined {
3439
+ function findFirstCommon(arr1: (number | undefined)[], arr2: (number | undefined)[]): number | undefined {
2827
3440
  for (const num of arr1) {
2828
3441
  if (arr2.indexOf(num) !== -1) {
2829
3442
  return num;