data-structure-typed 2.2.2 → 2.2.3

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.
Files changed (83) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/README.md +311 -1687
  3. package/README_CN.md +509 -0
  4. package/SECURITY.md +962 -11
  5. package/SECURITY.zh-CN.md +966 -0
  6. package/SPECIFICATION.md +689 -30
  7. package/SPECIFICATION.zh-CN.md +715 -0
  8. package/SPONSOR.zh-CN.md +62 -0
  9. package/SPONSOR_POLISHED.md +62 -0
  10. package/benchmark/report.html +1 -1
  11. package/benchmark/report.json +215 -172
  12. package/dist/cjs/index.cjs +163 -0
  13. package/dist/cjs/index.cjs.map +1 -1
  14. package/dist/cjs-legacy/index.cjs +164 -0
  15. package/dist/cjs-legacy/index.cjs.map +1 -1
  16. package/dist/esm/index.mjs +163 -0
  17. package/dist/esm/index.mjs.map +1 -1
  18. package/dist/esm-legacy/index.mjs +164 -0
  19. package/dist/esm-legacy/index.mjs.map +1 -1
  20. package/dist/types/data-structures/binary-tree/avl-tree.d.ts +96 -2
  21. package/dist/types/data-structures/binary-tree/binary-tree.d.ts +103 -7
  22. package/dist/types/data-structures/binary-tree/bst.d.ts +156 -13
  23. package/dist/types/data-structures/binary-tree/red-black-tree.d.ts +84 -35
  24. package/dist/types/data-structures/binary-tree/tree-multi-map.d.ts +2 -2
  25. package/dist/types/data-structures/graph/directed-graph.d.ts +126 -1
  26. package/dist/types/data-structures/graph/undirected-graph.d.ts +160 -1
  27. package/dist/types/data-structures/hash/hash-map.d.ts +110 -27
  28. package/dist/types/data-structures/heap/heap.d.ts +107 -58
  29. package/dist/types/data-structures/linked-list/doubly-linked-list.d.ts +72 -404
  30. package/dist/types/data-structures/linked-list/singly-linked-list.d.ts +121 -5
  31. package/dist/types/data-structures/queue/deque.d.ts +95 -67
  32. package/dist/types/data-structures/queue/queue.d.ts +90 -34
  33. package/dist/types/data-structures/stack/stack.d.ts +58 -40
  34. package/dist/types/data-structures/trie/trie.d.ts +109 -47
  35. package/dist/types/interfaces/binary-tree.d.ts +1 -0
  36. package/dist/umd/data-structure-typed.js +164 -0
  37. package/dist/umd/data-structure-typed.js.map +1 -1
  38. package/dist/umd/data-structure-typed.min.js +3 -3
  39. package/dist/umd/data-structure-typed.min.js.map +1 -1
  40. package/package.json +3 -2
  41. package/src/data-structures/binary-tree/avl-tree.ts +96 -2
  42. package/src/data-structures/binary-tree/binary-tree.ts +117 -7
  43. package/src/data-structures/binary-tree/bst.ts +322 -13
  44. package/src/data-structures/binary-tree/red-black-tree.ts +84 -35
  45. package/src/data-structures/binary-tree/tree-multi-map.ts +2 -2
  46. package/src/data-structures/graph/directed-graph.ts +126 -1
  47. package/src/data-structures/graph/undirected-graph.ts +160 -1
  48. package/src/data-structures/hash/hash-map.ts +110 -27
  49. package/src/data-structures/heap/heap.ts +107 -58
  50. package/src/data-structures/linked-list/doubly-linked-list.ts +72 -404
  51. package/src/data-structures/linked-list/singly-linked-list.ts +121 -5
  52. package/src/data-structures/queue/deque.ts +95 -67
  53. package/src/data-structures/queue/queue.ts +90 -34
  54. package/src/data-structures/stack/stack.ts +58 -40
  55. package/src/data-structures/trie/trie.ts +109 -47
  56. package/src/interfaces/binary-tree.ts +2 -0
  57. package/test/performance/benchmark-runner.ts +14 -11
  58. package/test/performance/data-structures/binary-tree/avl-tree.test.ts +8 -8
  59. package/test/performance/data-structures/binary-tree/binary-tree-overall.test.ts +8 -8
  60. package/test/performance/data-structures/binary-tree/binary-tree.test.ts +6 -6
  61. package/test/performance/data-structures/binary-tree/bst.test.ts +5 -5
  62. package/test/performance/data-structures/binary-tree/red-black-tree.test.ts +10 -10
  63. package/test/performance/reportor.ts +2 -1
  64. package/test/performance/single-suite-runner.ts +7 -4
  65. package/test/unit/data-structures/binary-tree/avl-tree.test.ts +117 -0
  66. package/test/unit/data-structures/binary-tree/binary-tree.test.ts +166 -0
  67. package/test/unit/data-structures/binary-tree/bst.test.ts +766 -8
  68. package/test/unit/data-structures/binary-tree/red-black-tree.test.ts +89 -37
  69. package/test/unit/data-structures/graph/directed-graph.test.ts +133 -0
  70. package/test/unit/data-structures/graph/undirected-graph.test.ts +167 -0
  71. package/test/unit/data-structures/hash/hash-map.test.ts +149 -3
  72. package/test/unit/data-structures/heap/heap.test.ts +182 -47
  73. package/test/unit/data-structures/linked-list/doubly-linked-list.test.ts +118 -14
  74. package/test/unit/data-structures/linked-list/singly-linked-list.test.ts +121 -0
  75. package/test/unit/data-structures/queue/deque.test.ts +98 -67
  76. package/test/unit/data-structures/queue/queue.test.ts +85 -51
  77. package/test/unit/data-structures/stack/stack.test.ts +142 -33
  78. package/test/unit/data-structures/trie/trie.test.ts +135 -39
  79. package/tsup.leetcode.config.js +99 -0
  80. package/typedoc.json +2 -1
  81. package/POSTS_zh-CN.md +0 -54
  82. package/README_zh-CN.md +0 -1208
  83. package/SPECIFICATION_zh-CN.md +0 -81
@@ -1616,7 +1616,677 @@ describe('BST _keyValueNodeOrEntryToNodeAndValue edge', () => {
1616
1616
  });
1617
1617
  });
1618
1618
 
1619
+ describe('BST lowerBound and upperBound', () => {
1620
+ let bst: BST<number, string>;
1621
+
1622
+ beforeEach(() => {
1623
+ // Create a BST with keys: [10, 5, 15, 3, 7, 12, 20, 1, 4, 6, 8, 11, 13, 18, 25]
1624
+ bst = new BST<number, string>([10, 5, 15, 3, 7, 12, 20, 1, 4, 6, 8, 11, 13, 18, 25]);
1625
+ });
1626
+
1627
+ describe('lowerBound', () => {
1628
+ it('should return the node with exact key match', () => {
1629
+ // Test for key that exists in tree
1630
+ const node = bst.lowerBound(10);
1631
+ expect(node).toBeDefined();
1632
+ expect(node?.key).toBe(10);
1633
+ });
1634
+
1635
+ it('should return the smallest node >= key when exact match not found', () => {
1636
+ // Test for key 9 (doesn't exist, should return 10)
1637
+ const node = bst.lowerBound(9);
1638
+ expect(node).toBeDefined();
1639
+ expect(node?.key).toBe(10);
1640
+ });
1641
+
1642
+ it('should return node with key >= search key from multiple candidates', () => {
1643
+ // Test for key 6 (exists, should return 6)
1644
+ const node = bst.lowerBound(6);
1645
+ expect(node).toBeDefined();
1646
+ expect(node?.key).toBe(6);
1647
+
1648
+ // Test for key 7 (exists, should return 7)
1649
+ const node2 = bst.lowerBound(7);
1650
+ expect(node2).toBeDefined();
1651
+ expect(node2?.key).toBe(7);
1652
+ });
1653
+
1654
+ it('should return smallest key >= search key for non-existent key in middle range', () => {
1655
+ // Test for key 14 (doesn't exist, should return 15)
1656
+ const node = bst.lowerBound(14);
1657
+ expect(node).toBeDefined();
1658
+ expect(node?.key).toBe(15);
1659
+
1660
+ // Test for key 11.5 (doesn't exist, should return 12)
1661
+ const node2 = bst.lowerBound(11.5);
1662
+ expect(node2).toBeDefined();
1663
+ expect(node2?.key).toBe(12);
1664
+ });
1665
+
1666
+ it('should return smallest key when search key is less than minimum', () => {
1667
+ // Test for key 0 (should return 1, the minimum)
1668
+ const node = bst.lowerBound(0);
1669
+ expect(node).toBeDefined();
1670
+ expect(node?.key).toBe(1);
1671
+
1672
+ // Test for key -100 (should return 1, the minimum)
1673
+ const node2 = bst.lowerBound(-100);
1674
+ expect(node2).toBeDefined();
1675
+ expect(node2?.key).toBe(1);
1676
+ });
1677
+
1678
+ it('should return undefined when search key is greater than maximum', () => {
1679
+ // Test for key 100 (no key >= 100, should return undefined)
1680
+ const node = bst.lowerBound(100);
1681
+ expect(node).toBeUndefined();
1682
+
1683
+ // Test for key 26 (no key >= 26, should return undefined)
1684
+ const node2 = bst.lowerBound(26);
1685
+ expect(node2).toBeUndefined();
1686
+ });
1687
+
1688
+ it('should return correct node for edge cases', () => {
1689
+ // Test for key 25 (maximum, should return 25)
1690
+ const node = bst.lowerBound(25);
1691
+ expect(node).toBeDefined();
1692
+ expect(node?.key).toBe(25);
1693
+
1694
+ // Test for key 1 (minimum, should return 1)
1695
+ const node2 = bst.lowerBound(1);
1696
+ expect(node2).toBeDefined();
1697
+ expect(node2?.key).toBe(1);
1698
+ });
1699
+ });
1700
+
1701
+ describe('upperBound', () => {
1702
+ it('should return the smallest key > search key', () => {
1703
+ // Test for key 10 (exists, should return next key > 10, which is 11)
1704
+ const node = bst.upperBound(10);
1705
+ expect(node).toBeDefined();
1706
+ expect(node?.key).toBe(11);
1707
+ });
1708
+
1709
+ it('should return the smallest key > search key for non-existent key', () => {
1710
+ // Test for key 9 (doesn't exist, should return 10, the smallest key > 9)
1711
+ const node = bst.upperBound(9);
1712
+ expect(node).toBeDefined();
1713
+ expect(node?.key).toBe(10);
1714
+
1715
+ // Test for key 14 (doesn't exist, should return 15)
1716
+ const node2 = bst.upperBound(14);
1717
+ expect(node2).toBeDefined();
1718
+ expect(node2?.key).toBe(15);
1719
+ });
1720
+
1721
+ it('should skip equal keys and return the next larger key', () => {
1722
+ // Test for key 5 (exists, should return 6, the smallest key > 5)
1723
+ const node = bst.upperBound(5);
1724
+ expect(node).toBeDefined();
1725
+ expect(node?.key).toBe(6);
1726
+
1727
+ // Test for key 20 (exists, should return 25)
1728
+ const node2 = bst.upperBound(20);
1729
+ expect(node2).toBeDefined();
1730
+ expect(node2?.key).toBe(25);
1731
+ });
1732
+
1733
+ it('should return smallest key > search key for non-existent key in middle range', () => {
1734
+ // Test for key 11.5 (doesn't exist, should return 12)
1735
+ const node = bst.upperBound(11.5);
1736
+ expect(node).toBeDefined();
1737
+ expect(node?.key).toBe(12);
1738
+
1739
+ // Test for key 19 (doesn't exist, should return 20)
1740
+ const node2 = bst.upperBound(19);
1741
+ expect(node2).toBeDefined();
1742
+ expect(node2?.key).toBe(20);
1743
+ });
1744
+
1745
+ it('should return smallest key when search key is less than minimum', () => {
1746
+ // Test for key 0 (should return 1, the minimum)
1747
+ const node = bst.upperBound(0);
1748
+ expect(node).toBeDefined();
1749
+ expect(node?.key).toBe(1);
1750
+
1751
+ // Test for key -100 (should return 1, the minimum)
1752
+ const node2 = bst.upperBound(-100);
1753
+ expect(node2).toBeDefined();
1754
+ expect(node2?.key).toBe(1);
1755
+ });
1756
+
1757
+ it('should return undefined when search key is >= maximum', () => {
1758
+ // Test for key 100 (no key > 100, should return undefined)
1759
+ const node = bst.upperBound(100);
1760
+ expect(node).toBeUndefined();
1761
+
1762
+ // Test for key 25 (maximum, no key > 25, should return undefined)
1763
+ const node2 = bst.upperBound(25);
1764
+ expect(node2).toBeUndefined();
1765
+
1766
+ // Test for key 26 (no key > 26, should return undefined)
1767
+ const node3 = bst.upperBound(26);
1768
+ expect(node3).toBeUndefined();
1769
+ });
1770
+
1771
+ it('should return correct node for edge cases', () => {
1772
+ // Test for key 1 (minimum, should return next key 3)
1773
+ const node = bst.upperBound(1);
1774
+ expect(node).toBeDefined();
1775
+ expect(node?.key).toBe(3);
1776
+
1777
+ // Test for key 24 (doesn't exist, should return 25)
1778
+ const node2 = bst.upperBound(24);
1779
+ expect(node2).toBeDefined();
1780
+ expect(node2?.key).toBe(25);
1781
+ });
1782
+ });
1783
+
1784
+ describe('lowerBound vs upperBound comparison', () => {
1785
+ it('should demonstrate difference between lowerBound and upperBound', () => {
1786
+ const searchKey = 12;
1787
+
1788
+ // lowerBound(12) should return 12 (key >= 12)
1789
+ const lower = bst.lowerBound(searchKey);
1790
+ expect(lower?.key).toBe(12);
1791
+
1792
+ // upperBound(12) should return 13 (key > 12)
1793
+ const upper = bst.upperBound(searchKey);
1794
+ expect(upper?.key).toBe(13);
1795
+ });
1796
+
1797
+ it('should return same result for non-existent key in both methods', () => {
1798
+ const searchKey = 11.5;
1799
+
1800
+ // Both should return 12 (smallest key >= 11.5 for lowerBound, smallest key > 11.5 for upperBound)
1801
+ const lower = bst.lowerBound(searchKey);
1802
+ const upper = bst.upperBound(searchKey);
1803
+ expect(lower?.key).toBe(12);
1804
+ expect(upper?.key).toBe(12);
1805
+ });
1806
+ });
1807
+
1808
+ describe('BST Bound Methods Comprehensive Tests', () => {
1809
+ let bst: BST<number, string>;
1810
+
1811
+ // Helper: Generate random number array
1812
+ const generateRandomArray = (size: number, min: number, max: number) => {
1813
+ return Array.from({ length: size }, () => Math.floor(Math.random() * (max - min + 1)) + min);
1814
+ };
1815
+
1816
+ beforeEach(() => {
1817
+ // Construct a standard test tree
1818
+ // Structure:
1819
+ // 10
1820
+ // / \
1821
+ // 5 15
1822
+ // / \ / \
1823
+ // 2 8 12 20
1824
+ // / \
1825
+ // 6 9
1826
+ bst = new BST<number, string>();
1827
+ const keys = [10, 5, 15, 2, 8, 12, 20, 6, 9];
1828
+ keys.forEach(k => bst.add(k, `val-${k}`));
1829
+ });
1830
+
1831
+ describe('lowerBound (First node >= key)', () => {
1832
+ test('should return strict match if key exists', () => {
1833
+ // Case: Key exists
1834
+ expect(bst.lowerBound(10)?.key).toBe(10);
1835
+ expect(bst.lowerBound(6)?.key).toBe(6);
1836
+ expect(bst.lowerBound(20)?.key).toBe(20);
1837
+ });
1838
+
1839
+ test('should return next larger node if key does not exist', () => {
1840
+ // Case: Key doesn't exist, but falls within range
1841
+ expect(bst.lowerBound(7)?.key).toBe(8); // 7 -> 8
1842
+ expect(bst.lowerBound(11)?.key).toBe(12); // 11 -> 12
1843
+ expect(bst.lowerBound(3)?.key).toBe(5); // 3 -> 5
1844
+ });
1845
+
1846
+ test('should return smallest node if key is smaller than min', () => {
1847
+ // Case: Key is smaller than the minimum value in the tree
1848
+ expect(bst.lowerBound(0)?.key).toBe(2);
1849
+ expect(bst.lowerBound(-100)?.key).toBe(2);
1850
+ });
1851
+
1852
+ test('should return undefined if key is larger than max', () => {
1853
+ // Case: Key is larger than the maximum value in the tree
1854
+ expect(bst.lowerBound(21)).toBeUndefined();
1855
+ expect(bst.lowerBound(100)).toBeUndefined();
1856
+ });
1857
+
1858
+ test('should work with IterationType.RECURSIVE explicitly', () => {
1859
+ expect(bst.lowerBound(7, 'RECURSIVE')?.key).toBe(8);
1860
+ expect(bst.lowerBound(10, 'RECURSIVE')?.key).toBe(10);
1861
+ expect(bst.lowerBound(21, 'RECURSIVE')).toBeUndefined();
1862
+ });
1863
+
1864
+ test('should work with IterationType.ITERATIVE explicitly', () => {
1865
+ expect(bst.lowerBound(7, 'ITERATIVE')?.key).toBe(8);
1866
+ expect(bst.lowerBound(10, 'ITERATIVE')?.key).toBe(10);
1867
+ expect(bst.lowerBound(21, 'ITERATIVE')).toBeUndefined();
1868
+ });
1869
+ });
1870
+
1871
+ describe('upperBound (First node > key)', () => {
1872
+ test('should return next larger node even if key exists', () => {
1873
+ // Case: Key exists, but we want strictly greater
1874
+ expect(bst.upperBound(10)?.key).toBe(12); // > 10 is 12
1875
+ expect(bst.upperBound(6)?.key).toBe(8); // > 6 is 8
1876
+ expect(bst.upperBound(20)).toBeUndefined(); // > 20 is undefined
1877
+ });
1878
+
1879
+ test('should return next larger node if key does not exist', () => {
1880
+ // Case: Key doesn't exist
1881
+ expect(bst.upperBound(7)?.key).toBe(8);
1882
+ expect(bst.upperBound(11)?.key).toBe(12);
1883
+ });
1884
+
1885
+ test('should return undefined if key is larger than or equal to max', () => {
1886
+ expect(bst.upperBound(20)).toBeUndefined();
1887
+ expect(bst.upperBound(21)).toBeUndefined();
1888
+ });
1889
+
1890
+ test('should work with IterationType.RECURSIVE explicitly', () => {
1891
+ expect(bst.upperBound(10, 'RECURSIVE')?.key).toBe(12);
1892
+ expect(bst.upperBound(20, 'RECURSIVE')).toBeUndefined();
1893
+ });
1894
+ });
1895
+
1896
+ describe('Edge Cases', () => {
1897
+ test('should handle empty tree', () => {
1898
+ const emptyTree = new BST<number, string>();
1899
+ expect(emptyTree.lowerBound(10)).toBeUndefined();
1900
+ expect(emptyTree.upperBound(10)).toBeUndefined();
1901
+ });
1902
+
1903
+ test('should handle single node tree', () => {
1904
+ const singleNodeTree = new BST<number, string>();
1905
+ singleNodeTree.add(10);
1906
+
1907
+ // lowerBound
1908
+ expect(singleNodeTree.lowerBound(5)?.key).toBe(10);
1909
+ expect(singleNodeTree.lowerBound(10)?.key).toBe(10);
1910
+ expect(singleNodeTree.lowerBound(15)).toBeUndefined();
1911
+
1912
+ // upperBound
1913
+ expect(singleNodeTree.upperBound(5)?.key).toBe(10);
1914
+ expect(singleNodeTree.upperBound(10)).toBeUndefined();
1915
+ });
1916
+ });
1917
+
1918
+ describe('Consistency & Fuzz Testing', () => {
1919
+ test('Recursive and Iterative implementations should match on random data', () => {
1920
+ const fuzzTree = new BST<number, number>();
1921
+ // Generate 500 random numbers between 0-1000
1922
+ const randomKeys = generateRandomArray(500, 0, 1000);
1923
+
1924
+ // Insert unique keys
1925
+ [...new Set(randomKeys)].forEach(k => fuzzTree.add(k));
1926
+
1927
+ // Sort for verification (Ground Truth)
1928
+ const sortedKeys = Array.from(fuzzTree.keys()).sort((a, b) => a - b);
1929
+
1930
+ // Test with 200 random queries (including existing and non-existing keys)
1931
+ const testQueries = generateRandomArray(200, 0, 1000);
1932
+
1933
+ testQueries.forEach(queryKey => {
1934
+ // 1. Verify lowerBound
1935
+ const recLower = fuzzTree.lowerBound(queryKey, 'RECURSIVE')?.key;
1936
+ const iterLower = fuzzTree.lowerBound(queryKey, 'ITERATIVE')?.key;
1937
+
1938
+ // Verify consistency between recursive and iterative
1939
+ expect(recLower).toBe(iterLower);
1940
+
1941
+ // Verify logic correctness (compare with Array.find)
1942
+ const expectedLower = sortedKeys.find(k => k >= queryKey);
1943
+ expect(recLower).toBe(expectedLower);
1944
+
1945
+ // 2. Verify upperBound
1946
+ const recUpper = fuzzTree.upperBound(queryKey, 'RECURSIVE')?.key;
1947
+ const iterUpper = fuzzTree.upperBound(queryKey, 'ITERATIVE')?.key;
1948
+
1949
+ // Verify consistency
1950
+ expect(recUpper).toBe(iterUpper);
1951
+
1952
+ // Verify logic correctness
1953
+ const expectedUpper = sortedKeys.find(k => k > queryKey);
1954
+ expect(recUpper).toBe(expectedUpper);
1955
+ });
1956
+ });
1957
+ });
1958
+ });
1959
+
1960
+ describe('empty tree', () => {
1961
+ beforeEach(() => {
1962
+ bst = new BST<number, string>();
1963
+ });
1964
+
1965
+ it('lowerBound should return undefined on empty tree', () => {
1966
+ const node = bst.lowerBound(10);
1967
+ expect(node).toBeUndefined();
1968
+ });
1969
+
1970
+ it('upperBound should return undefined on empty tree', () => {
1971
+ const node = bst.upperBound(10);
1972
+ expect(node).toBeUndefined();
1973
+ });
1974
+ });
1975
+
1976
+ describe('single node tree', () => {
1977
+ beforeEach(() => {
1978
+ bst = new BST<number, string>();
1979
+ bst.add(10, 'ten');
1980
+ });
1981
+
1982
+ it('lowerBound should return the node if key matches', () => {
1983
+ const node = bst.lowerBound(10);
1984
+ expect(node).toBeDefined();
1985
+ expect(node?.key).toBe(10);
1986
+ });
1987
+
1988
+ it('lowerBound should return the node if search key is less', () => {
1989
+ const node = bst.lowerBound(5);
1990
+ expect(node).toBeDefined();
1991
+ expect(node?.key).toBe(10);
1992
+ });
1993
+
1994
+ it('lowerBound should return undefined if search key is greater', () => {
1995
+ const node = bst.lowerBound(15);
1996
+ expect(node).toBeUndefined();
1997
+ });
1998
+
1999
+ it('upperBound should return undefined if key matches', () => {
2000
+ const node = bst.upperBound(10);
2001
+ expect(node).toBeUndefined();
2002
+ });
2003
+
2004
+ it('upperBound should return the node if search key is less', () => {
2005
+ const node = bst.upperBound(5);
2006
+ expect(node).toBeDefined();
2007
+ expect(node?.key).toBe(10);
2008
+ });
2009
+
2010
+ it('upperBound should return undefined if search key is greater', () => {
2011
+ const node = bst.upperBound(15);
2012
+ expect(node).toBeUndefined();
2013
+ });
2014
+ });
2015
+
2016
+ describe('practical LeetCode use case: Range search', () => {
2017
+ it('should find all keys in range [12, 20]', () => {
2018
+ // Use lowerBound to find start of range and upperBound to find end
2019
+ const start = bst.lowerBound(12);
2020
+
2021
+ // Simple traversal simulation (for test only, real iteration is more complex)
2022
+ // We manually add keys we know are in range to verify logic works
2023
+ // The lowerBound(12) returns 12. upperBound(20) returns 25 (or null if max).
2024
+ // Logic: we want >= 12 and <= 20.
2025
+
2026
+ expect(start?.key).toBe(12);
2027
+
2028
+ // Let's verify we found the correct bounds
2029
+ expect(start?.key).toBeGreaterThanOrEqual(12);
2030
+
2031
+ // Check overlap
2032
+ const rangeStart = bst.lowerBound(12);
2033
+ const rangeEndInclusive = bst.lowerBound(20); // Should be 20
2034
+
2035
+ expect(rangeStart?.key).toBe(12);
2036
+ expect(rangeEndInclusive?.key).toBe(20);
2037
+ });
2038
+
2039
+ it('should help identify interval overlaps', () => {
2040
+ // Check if interval [14, 19] overlaps with any existing interval
2041
+ // Use upperBound to find the first key > 19
2042
+ const nextKey = bst.upperBound(19);
2043
+ // Use lowerBound to find the first key >= 14
2044
+ const firstInRange = bst.lowerBound(14);
2045
+
2046
+ expect(firstInRange?.key).toBe(15);
2047
+ expect(nextKey?.key).toBe(20);
2048
+ });
2049
+ });
2050
+ });
2051
+
2052
+ describe('BST Advanced Bound Methods Tests', () => {
2053
+ let bst: BST<number, string>;
2054
+
2055
+ // Helper: Generate random number array
2056
+ const generateRandomArray = (size: number, min: number, max: number) => {
2057
+ return Array.from({ length: size }, () => Math.floor(Math.random() * (max - min + 1)) + min);
2058
+ };
2059
+
2060
+ beforeEach(() => {
2061
+ // Construct a standard test tree
2062
+ // Structure:
2063
+ // 10
2064
+ // / \
2065
+ // 5 15
2066
+ // / \ / \
2067
+ // 2 8 12 20
2068
+ // / \
2069
+ // 6 9
2070
+ bst = new BST<number, string>();
2071
+ const keys = [10, 5, 15, 2, 8, 12, 20, 6, 9];
2072
+ keys.forEach(k => bst.add(k, `val-${k}`));
2073
+ });
2074
+
2075
+ describe('Polymorphic Input Support', () => {
2076
+ test('should accept raw Key', () => {
2077
+ expect(bst.lowerBound(7)?.key).toBe(8);
2078
+ expect(bst.upperBound(7)?.key).toBe(8);
2079
+ });
2080
+
2081
+ test('should accept BSTNode object', () => {
2082
+ // Find a node first
2083
+ const node5 = bst.getNode(5);
2084
+ expect(node5).toBeDefined();
2085
+
2086
+ // Use the node as input for lowerBound (should return itself)
2087
+ expect(bst.lowerBound(node5)?.key).toBe(5);
2088
+
2089
+ // Use the node as input for upperBound (should return next larger)
2090
+ expect(bst.upperBound(node5)?.key).toBe(6);
2091
+ });
2092
+
2093
+ test('should accept Entry tuple [key, value]', () => {
2094
+ // Input as [key, value] tuple
2095
+ const entry: [number, string] = [7, 'val-7'];
2096
+
2097
+ expect(bst.lowerBound(entry)?.key).toBe(8);
2098
+ expect(bst.upperBound(entry)?.key).toBe(8);
2099
+
2100
+ const existingEntry: [number, string] = [10, 'val-10'];
2101
+ expect(bst.lowerBound(existingEntry)?.key).toBe(10);
2102
+ expect(bst.upperBound(existingEntry)?.key).toBe(12);
2103
+ });
2104
+
2105
+ test('should accept Predicate function (Linear Search Fallback)', () => {
2106
+ // Predicate: Find first node with key > 11 (Expect 12)
2107
+ // Note: Predicate search uses in-order traversal
2108
+ const predicate = (node: any) => node.key > 11;
2109
+
2110
+ // For predicate, lowerBound and upperBound behave identically
2111
+ // (they just return the first match of the predicate)
2112
+ expect(bst.lowerBound(predicate)?.key).toBe(12);
2113
+ expect(bst.upperBound(predicate)?.key).toBe(12);
2114
+
2115
+ // Predicate: Find specific value
2116
+ expect(bst.lowerBound(n => n.key === 6)?.key).toBe(6);
2117
+ });
2118
+ });
2119
+
2120
+ describe('Iteration Types with Polymorphic Inputs', () => {
2121
+ test('should work recursively with all types', () => {
2122
+ const type = 'RECURSIVE';
2123
+
2124
+ expect(bst.lowerBound(7, type)?.key).toBe(8);
2125
+ expect(bst.lowerBound(bst.getNode(5), type)?.key).toBe(5);
2126
+ expect(bst.lowerBound([7, 'val'], type)?.key).toBe(8);
2127
+ expect(bst.lowerBound(n => n.key > 11, type)?.key).toBe(12);
2128
+ });
2129
+
2130
+ test('should work iteratively with all types', () => {
2131
+ const type = 'ITERATIVE';
2132
+
2133
+ expect(bst.lowerBound(7, type)?.key).toBe(8);
2134
+ expect(bst.lowerBound(bst.getNode(5), type)?.key).toBe(5);
2135
+ expect(bst.lowerBound([7, 'val'], type)?.key).toBe(8);
2136
+ expect(bst.lowerBound(n => n.key > 11, type)?.key).toBe(12);
2137
+ });
2138
+ });
2139
+
2140
+ describe('Complex Edge Cases', () => {
2141
+ test('should return undefined for null/undefined input', () => {
2142
+ expect(bst.lowerBound(null)).toBeUndefined();
2143
+ expect(bst.lowerBound(undefined)).toBeUndefined();
2144
+ });
2145
+
2146
+ test('should handle predicate returning false for all nodes', () => {
2147
+ expect(bst.lowerBound(n => n.key > 100)).toBeUndefined();
2148
+ });
2149
+ });
2150
+
2151
+ describe('Consistency Check (Fuzz Testing)', () => {
2152
+ test('All input methods should yield consistent results for Raw Key and Entry', () => {
2153
+ const fuzzTree = new BST<number, number>();
2154
+ const randomKeys = generateRandomArray(100, 0, 200);
2155
+ [...new Set(randomKeys)].forEach(k => fuzzTree.add(k));
2156
+
2157
+ const queries = generateRandomArray(50, 0, 200);
2158
+
2159
+ queries.forEach(q => {
2160
+ // 1. Raw Key
2161
+ const resKey = fuzzTree.lowerBound(q);
2162
+
2163
+ // 2. Entry
2164
+ const resEntry = fuzzTree.lowerBound([q, undefined]);
2165
+
2166
+ // Verify consistency between Key and Entry
2167
+ expect(resKey?.key).toBe(resEntry?.key);
2168
+ });
2169
+ });
2170
+
2171
+ test('BSTNode input should work correctly', () => {
2172
+ const fuzzTree = new BST<number, number>();
2173
+ const randomKeys = generateRandomArray(50, 0, 100);
2174
+ const uniqueKeys = [...new Set(randomKeys)];
2175
+ uniqueKeys.forEach(k => fuzzTree.add(k));
2176
+
2177
+ // Test with actual nodes from the tree
2178
+ for (const key of uniqueKeys) {
2179
+ const node = fuzzTree.getNode(key);
2180
+ if (node) {
2181
+ // lowerBound with node should return itself (since node.key >= key)
2182
+ expect(fuzzTree.lowerBound(node)?.key).toBe(key);
2183
+
2184
+ // upperBound with node should return next larger
2185
+ const upperRes = fuzzTree.upperBound(node);
2186
+ if (upperRes) {
2187
+ expect(upperRes.key).toBeGreaterThan(key);
2188
+ }
2189
+ }
2190
+ }
2191
+ });
2192
+
2193
+ test('Predicate input should find matching nodes', () => {
2194
+ const fuzzTree = new BST<number, number>();
2195
+ const randomKeys = generateRandomArray(50, 0, 100);
2196
+ const uniqueKeys = [...new Set(randomKeys)];
2197
+ uniqueKeys.forEach(k => fuzzTree.add(k));
2198
+
2199
+ // Test various predicates
2200
+ const predicates = [(n: any) => n.key > 50, (n: any) => n.key < 30, (n: any) => n.key >= 25 && n.key <= 75];
2201
+
2202
+ predicates.forEach(predicate => {
2203
+ const result = fuzzTree.lowerBound(predicate);
2204
+ if (result) {
2205
+ // Verify the result actually satisfies the predicate
2206
+ expect(predicate(result)).toBe(true);
2207
+ }
2208
+ });
2209
+ });
2210
+
2211
+ test('Consistency between RECURSIVE and ITERATIVE modes', () => {
2212
+ const fuzzTree = new BST<number, number>();
2213
+ const randomKeys = generateRandomArray(50, 0, 100);
2214
+ [...new Set(randomKeys)].forEach(k => fuzzTree.add(k));
2215
+
2216
+ const queries = generateRandomArray(30, 0, 100);
2217
+
2218
+ queries.forEach(q => {
2219
+ // Test with Key
2220
+ const recKey = fuzzTree.lowerBound(q, 'RECURSIVE');
2221
+ const iterKey = fuzzTree.lowerBound(q, 'ITERATIVE');
2222
+ expect(recKey?.key).toBe(iterKey?.key);
2223
+
2224
+ // Test with Entry
2225
+ const recEntry = fuzzTree.lowerBound([q, undefined], 'RECURSIVE');
2226
+ const iterEntry = fuzzTree.lowerBound([q, undefined], 'ITERATIVE');
2227
+ expect(recEntry?.key).toBe(iterEntry?.key);
2228
+
2229
+ // Test upperBound too
2230
+ const recUpper = fuzzTree.upperBound(q, 'RECURSIVE');
2231
+ const iterUpper = fuzzTree.upperBound(q, 'ITERATIVE');
2232
+ expect(recUpper?.key).toBe(iterUpper?.key);
2233
+ });
2234
+ });
2235
+ });
2236
+ });
2237
+
1619
2238
  describe('classic use', () => {
2239
+ it('@example basic BST creation and add operation', () => {
2240
+ // Create a simple BST with numeric keys
2241
+ const bst = new BST<number>([11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]);
2242
+
2243
+ bst.print();
2244
+ // _______8__________
2245
+ // / \
2246
+ // ___4___ ____12_____
2247
+ // / \ / \
2248
+ // _2_ _6_ _10__ _14__
2249
+ // / \ / \ / \ / \
2250
+ // 1 3 5 7 9 11 13 15__
2251
+ // \
2252
+ // 16
2253
+
2254
+ // Verify size
2255
+ expect(bst.size).toBe(16);
2256
+
2257
+ // Add new elements
2258
+ bst.add(17);
2259
+ bst.add(0);
2260
+ expect(bst.size).toBe(18);
2261
+
2262
+ // Verify keys are searchable
2263
+ expect(bst.has(11)).toBe(true);
2264
+ expect(bst.has(100)).toBe(false);
2265
+ });
2266
+
2267
+ it('@example BST delete and search after deletion', () => {
2268
+ const bst = new BST<number>([11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]);
2269
+
2270
+ // Delete a leaf node
2271
+ bst.delete(1);
2272
+ expect(bst.has(1)).toBe(false);
2273
+
2274
+ // Delete a node with one child
2275
+ bst.delete(2);
2276
+ expect(bst.has(2)).toBe(false);
2277
+
2278
+ // Delete a node with two children
2279
+ bst.delete(3);
2280
+ expect(bst.has(3)).toBe(false);
2281
+
2282
+ // Size decreases with each deletion
2283
+ expect(bst.size).toBe(13);
2284
+
2285
+ // Other nodes remain searchable
2286
+ expect(bst.has(11)).toBe(true);
2287
+ expect(bst.has(15)).toBe(true);
2288
+ });
2289
+
1620
2290
  it('@example Merge 3 sorted datasets', () => {
1621
2291
  const dataset1 = new BST<number, string>([
1622
2292
  [1, 'A'],
@@ -1641,14 +2311,53 @@ describe('classic use', () => {
1641
2311
  expect([...merged.values()]).toEqual(['A', 'B', 'C', 'D', 'E', 'F', 'G']);
1642
2312
  });
1643
2313
 
1644
- // Test case for finding elements in a given range
1645
- it('@example Find elements in a range', () => {
1646
- const bst = new BST<number>([10, 5, 15, 3, 7, 12, 18]);
1647
- expect(bst.search(new Range(5, 10))).toEqual([5, 7, 10]);
1648
- expect(bst.rangeSearch([4, 12], node => node.key.toString())).toEqual(['5', '7', '10', '12']);
1649
- expect(bst.search(new Range(4, 12, true, false))).toEqual([5, 7, 10]);
1650
- expect(bst.rangeSearch([15, 20])).toEqual([15, 18]);
1651
- expect(bst.search(new Range(15, 20, false))).toEqual([18]);
2314
+ it('@example BST with custom objects for expression evaluation', () => {
2315
+ interface Expression {
2316
+ id: number;
2317
+ operator: string;
2318
+ precedence: number;
2319
+ }
2320
+
2321
+ // BST efficiently stores and retrieves operators by precedence
2322
+ const operatorTree = new BST<number, Expression>(
2323
+ [
2324
+ [1, { id: 1, operator: '+', precedence: 1 }],
2325
+ [2, { id: 2, operator: '*', precedence: 2 }],
2326
+ [3, { id: 3, operator: '/', precedence: 2 }],
2327
+ [4, { id: 4, operator: '-', precedence: 1 }],
2328
+ [5, { id: 5, operator: '^', precedence: 3 }]
2329
+ ],
2330
+ { isMapMode: false }
2331
+ );
2332
+
2333
+ expect(operatorTree.size).toBe(5);
2334
+
2335
+ // Quick lookup of operators
2336
+ const mult = operatorTree.get(2);
2337
+ expect(mult?.operator).toBe('*');
2338
+ expect(mult?.precedence).toBe(2);
2339
+
2340
+ // Check if operator exists
2341
+ expect(operatorTree.has(5)).toBe(true);
2342
+ expect(operatorTree.has(99)).toBe(false);
2343
+
2344
+ // Retrieve operator by precedence level
2345
+ const expNode = operatorTree.getNode(3);
2346
+ expect(expNode?.key).toBe(3);
2347
+ expect(expNode?.value?.precedence).toBe(2);
2348
+
2349
+ // Delete operator and verify
2350
+ operatorTree.delete(1);
2351
+ expect(operatorTree.has(1)).toBe(false);
2352
+ expect(operatorTree.size).toBe(4);
2353
+
2354
+ // Get tree height for optimization analysis
2355
+ const treeHeight = operatorTree.getHeight();
2356
+ expect(treeHeight).toBeGreaterThan(0);
2357
+
2358
+ // Remaining operators are still accessible
2359
+ const remaining = operatorTree.get(2);
2360
+ expect(remaining).toBeDefined();
1652
2361
  });
1653
2362
 
1654
2363
  // Test case for Lowest Common Ancestor (LCA)
@@ -1677,4 +2386,53 @@ describe('classic use', () => {
1677
2386
  expect(findLCA(5, 35)).toBe(15);
1678
2387
  expect(findLCA(20, 30)).toBe(25);
1679
2388
  });
2389
+
2390
+ // Test case for finding elements in a given range
2391
+ it('Find elements in a range', () => {
2392
+ const bst = new BST<number>([10, 5, 15, 3, 7, 12, 18]);
2393
+ expect(bst.search(new Range(5, 10))).toEqual([5, 7, 10]);
2394
+ expect(bst.rangeSearch([4, 12], node => node.key.toString())).toEqual(['5', '7', '10', '12']);
2395
+ expect(bst.search(new Range(4, 12, true, false))).toEqual([5, 7, 10]);
2396
+ expect(bst.rangeSearch([15, 20])).toEqual([15, 18]);
2397
+ expect(bst.search(new Range(15, 20, false))).toEqual([18]);
2398
+ });
2399
+
2400
+ it('BST get and getNode operations', () => {
2401
+ const bst = new BST<number>([5, 3, 7, 1, 4, 6, 8]);
2402
+
2403
+ // Get value by key
2404
+ const value = bst.get(5);
2405
+ expect(value).toBe(undefined);
2406
+
2407
+ // Get node returns the actual node object
2408
+ const node = bst.getNode(3);
2409
+ expect(node?.key).toBe(3);
2410
+ expect(node?.left).toBeDefined();
2411
+ expect(node?.right).toBeDefined();
2412
+
2413
+ // Get from non-existent key returns undefined
2414
+ expect(bst.get(100)).toBeUndefined();
2415
+ expect(bst.getNode(100)).toBeUndefined();
2416
+ });
2417
+
2418
+ it('BST getHeight and tree structure queries', () => {
2419
+ const bst = new BST<number>([11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]);
2420
+
2421
+ // Get overall tree height
2422
+ const treeHeight = bst.getHeight();
2423
+ expect(typeof treeHeight).toBe('number');
2424
+ expect(treeHeight).toBeGreaterThan(0);
2425
+
2426
+ // Get height of specific node
2427
+ const heightOf3 = bst.getHeight(3);
2428
+ expect(typeof heightOf3).toBe('number');
2429
+
2430
+ // Root node should have the maximum height
2431
+ const heightOf11 = bst.getHeight(11);
2432
+ expect(heightOf11).toBe(0);
2433
+
2434
+ // Leaf nodes have height 0
2435
+ const heightOf2 = bst.getHeight(2);
2436
+ expect(heightOf2).toBe(1);
2437
+ });
1680
2438
  });