data-structure-typed 2.2.2 → 2.2.4

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 (94) hide show
  1. package/CHANGELOG.md +3 -1
  2. package/README.md +355 -1672
  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 +245 -72
  13. package/dist/cjs/index.cjs.map +1 -1
  14. package/dist/cjs-legacy/index.cjs +246 -72
  15. package/dist/cjs-legacy/index.cjs.map +1 -1
  16. package/dist/esm/index.mjs +245 -72
  17. package/dist/esm/index.mjs.map +1 -1
  18. package/dist/esm-legacy/index.mjs +246 -72
  19. package/dist/esm-legacy/index.mjs.map +1 -1
  20. package/dist/types/data-structures/binary-tree/avl-tree-counter.d.ts +2 -2
  21. package/dist/types/data-structures/binary-tree/avl-tree-multi-map.d.ts +5 -5
  22. package/dist/types/data-structures/binary-tree/avl-tree.d.ts +98 -5
  23. package/dist/types/data-structures/binary-tree/binary-tree.d.ts +103 -7
  24. package/dist/types/data-structures/binary-tree/bst.d.ts +202 -39
  25. package/dist/types/data-structures/binary-tree/red-black-tree.d.ts +86 -37
  26. package/dist/types/data-structures/binary-tree/tree-counter.d.ts +4 -5
  27. package/dist/types/data-structures/binary-tree/tree-multi-map.d.ts +7 -7
  28. package/dist/types/data-structures/graph/directed-graph.d.ts +126 -1
  29. package/dist/types/data-structures/graph/undirected-graph.d.ts +160 -1
  30. package/dist/types/data-structures/hash/hash-map.d.ts +110 -27
  31. package/dist/types/data-structures/heap/heap.d.ts +107 -58
  32. package/dist/types/data-structures/linked-list/doubly-linked-list.d.ts +72 -404
  33. package/dist/types/data-structures/linked-list/singly-linked-list.d.ts +121 -5
  34. package/dist/types/data-structures/queue/deque.d.ts +95 -67
  35. package/dist/types/data-structures/queue/queue.d.ts +90 -34
  36. package/dist/types/data-structures/stack/stack.d.ts +58 -40
  37. package/dist/types/data-structures/trie/trie.d.ts +109 -47
  38. package/dist/types/interfaces/binary-tree.d.ts +1 -0
  39. package/dist/types/types/data-structures/binary-tree/bst.d.ts +5 -5
  40. package/dist/umd/data-structure-typed.js +246 -72
  41. package/dist/umd/data-structure-typed.js.map +1 -1
  42. package/dist/umd/data-structure-typed.min.js +3 -3
  43. package/dist/umd/data-structure-typed.min.js.map +1 -1
  44. package/package.json +3 -2
  45. package/src/data-structures/binary-tree/avl-tree-counter.ts +1 -2
  46. package/src/data-structures/binary-tree/avl-tree-multi-map.ts +7 -8
  47. package/src/data-structures/binary-tree/avl-tree.ts +100 -7
  48. package/src/data-structures/binary-tree/binary-tree.ts +117 -7
  49. package/src/data-structures/binary-tree/bst.ts +431 -93
  50. package/src/data-structures/binary-tree/red-black-tree.ts +85 -37
  51. package/src/data-structures/binary-tree/tree-counter.ts +5 -7
  52. package/src/data-structures/binary-tree/tree-multi-map.ts +9 -10
  53. package/src/data-structures/graph/directed-graph.ts +126 -1
  54. package/src/data-structures/graph/undirected-graph.ts +160 -1
  55. package/src/data-structures/hash/hash-map.ts +110 -27
  56. package/src/data-structures/heap/heap.ts +107 -58
  57. package/src/data-structures/linked-list/doubly-linked-list.ts +72 -404
  58. package/src/data-structures/linked-list/singly-linked-list.ts +121 -5
  59. package/src/data-structures/queue/deque.ts +95 -67
  60. package/src/data-structures/queue/queue.ts +90 -34
  61. package/src/data-structures/stack/stack.ts +58 -40
  62. package/src/data-structures/trie/trie.ts +109 -47
  63. package/src/interfaces/binary-tree.ts +2 -0
  64. package/src/types/data-structures/binary-tree/bst.ts +5 -5
  65. package/test/performance/benchmark-runner.ts +14 -11
  66. package/test/performance/data-structures/binary-tree/avl-tree.test.ts +8 -8
  67. package/test/performance/data-structures/binary-tree/binary-tree-overall.test.ts +8 -8
  68. package/test/performance/data-structures/binary-tree/binary-tree.test.ts +6 -6
  69. package/test/performance/data-structures/binary-tree/bst.test.ts +5 -5
  70. package/test/performance/data-structures/binary-tree/red-black-tree.test.ts +10 -10
  71. package/test/performance/reportor.ts +2 -1
  72. package/test/performance/single-suite-runner.ts +7 -4
  73. package/test/unit/data-structures/binary-tree/avl-tree-counter.test.ts +2 -2
  74. package/test/unit/data-structures/binary-tree/avl-tree.test.ts +117 -0
  75. package/test/unit/data-structures/binary-tree/binary-tree.test.ts +166 -0
  76. package/test/unit/data-structures/binary-tree/bst.test.ts +771 -16
  77. package/test/unit/data-structures/binary-tree/overall.test.ts +2 -2
  78. package/test/unit/data-structures/binary-tree/red-black-tree.test.ts +90 -38
  79. package/test/unit/data-structures/binary-tree/tree-multi-map.test.ts +2 -2
  80. package/test/unit/data-structures/graph/directed-graph.test.ts +133 -0
  81. package/test/unit/data-structures/graph/undirected-graph.test.ts +167 -0
  82. package/test/unit/data-structures/hash/hash-map.test.ts +149 -3
  83. package/test/unit/data-structures/heap/heap.test.ts +182 -47
  84. package/test/unit/data-structures/linked-list/doubly-linked-list.test.ts +118 -14
  85. package/test/unit/data-structures/linked-list/singly-linked-list.test.ts +121 -0
  86. package/test/unit/data-structures/queue/deque.test.ts +98 -67
  87. package/test/unit/data-structures/queue/queue.test.ts +85 -51
  88. package/test/unit/data-structures/stack/stack.test.ts +142 -33
  89. package/test/unit/data-structures/trie/trie.test.ts +135 -39
  90. package/tsup.leetcode.config.js +99 -0
  91. package/typedoc.json +2 -1
  92. package/POSTS_zh-CN.md +0 -54
  93. package/README_zh-CN.md +0 -1208
  94. package/SPECIFICATION_zh-CN.md +0 -81
@@ -58,7 +58,7 @@ describe('Overall BinaryTree Test', () => {
58
58
  it('Should clone a BST works fine', () => {
59
59
  const bst = new BST<number>([3, 6, 7, 1, 9], {
60
60
  iterationType: 'RECURSIVE',
61
- isReverse: true
61
+ comparator: (a, b) => b - a,
62
62
  });
63
63
  expect(bst.size).toBe(5);
64
64
  expect(bst.root?.key).toBe(6);
@@ -100,7 +100,7 @@ describe('Overall BinaryTree Test', () => {
100
100
  it('Should clone a AVLTree works fine', () => {
101
101
  const avl = new AVLTree<number>([3, 6, 7, 1, 9], {
102
102
  iterationType: 'RECURSIVE',
103
- isReverse: true
103
+ comparator: (a, b) => b - a,
104
104
  });
105
105
  expect(avl.size).toBe(5);
106
106
  avl.add(2);
@@ -821,7 +821,7 @@ describe('RedBlackTree - _deleteFixup', () => {
821
821
  describe('real world data', () => {
822
822
  it('cost of living', () => {
823
823
  const indexedByRank = new RedBlackTree(costOfLiving, {
824
- specifyComparable: node => node.rank,
824
+ comparator: (a, b) => a.rank - b.rank,
825
825
  toEntryFn: raw => [raw, undefined]
826
826
  });
827
827
  expect(indexedByRank.size).toBe(7);
@@ -838,47 +838,99 @@ describe('real world data', () => {
838
838
  });
839
839
 
840
840
  describe('classic use', () => {
841
- it('@example using Red-Black Tree as a price-based index for stock data', () => {
842
- // Define the structure of individual stock records
843
- interface StockRecord {
844
- price: number; // Stock price (key for indexing)
845
- symbol: string; // Stock ticker symbol
846
- volume: number; // Trade volume
841
+ it('@example basic Red-Black Tree with simple number keys', () => {
842
+ // Create a simple Red-Black Tree with numeric keys
843
+ const tree = new RedBlackTree([5, 2, 8, 1, 9]);
844
+
845
+ tree.print();
846
+ // _2___
847
+ // / \
848
+ // 1 _8_
849
+ // / \
850
+ // 5 9
851
+
852
+ // Verify the tree maintains sorted order
853
+ expect([...tree.keys()]).toEqual([1, 2, 5, 8, 9]);
854
+
855
+ // Check size
856
+ expect(tree.size).toBe(5);
857
+ });
858
+
859
+ it('@example Red-Black Tree with key-value pairs for lookups', () => {
860
+ interface Employee {
861
+ id: number;
862
+ name: string;
863
+ }
864
+
865
+ // Create tree with employee data
866
+ const employees = new RedBlackTree<number, Employee>([
867
+ [1, { id: 1, name: 'Alice' }],
868
+ [3, { id: 3, name: 'Charlie' }],
869
+ [2, { id: 2, name: 'Bob' }]
870
+ ]);
871
+
872
+ // Retrieve employee by ID
873
+ const alice = employees.get(1);
874
+ expect(alice?.name).toBe('Alice');
875
+
876
+ // Verify sorted order by ID
877
+ expect([...employees.keys()]).toEqual([1, 2, 3]);
878
+ });
879
+
880
+ it('@example Red-Black Tree range search for filtering', () => {
881
+ interface Product {
882
+ name: string;
883
+ price: number;
847
884
  }
848
885
 
849
- // Simulate stock market data as it might come from an external feed
850
- const marketStockData: StockRecord[] = [
851
- { price: 142.5, symbol: 'AAPL', volume: 1000000 },
852
- { price: 335.2, symbol: 'MSFT', volume: 800000 },
853
- { price: 3285.04, symbol: 'AMZN', volume: 500000 },
854
- { price: 267.98, symbol: 'META', volume: 750000 },
855
- { price: 234.57, symbol: 'GOOGL', volume: 900000 }
856
- ];
857
-
858
- // Extend the stock record type to include metadata for database usage
859
- type StockTableRecord = StockRecord & { lastUpdated: Date };
860
-
861
- // Create a Red-Black Tree to index stock records by price
862
- // Simulates a database index with stock price as the key for quick lookups
863
- const priceIndex = new RedBlackTree<number, StockTableRecord, StockRecord>(marketStockData, {
864
- toEntryFn: stockRecord => [
865
- stockRecord.price, // Use stock price as the key
866
- {
867
- ...stockRecord,
868
- lastUpdated: new Date() // Add a timestamp for when the record was indexed
869
- }
870
- ]
886
+ const products = new RedBlackTree<number, Product>([
887
+ [10, { name: 'Item A', price: 10 }],
888
+ [25, { name: 'Item B', price: 25 }],
889
+ [40, { name: 'Item C', price: 40 }],
890
+ [50, { name: 'Item D', price: 50 }]
891
+ ]);
892
+
893
+ // Find products in price range [20, 45]
894
+ const pricesInRange = products.rangeSearch([20, 45], node => {
895
+ return products.get(node)?.name;
871
896
  });
872
897
 
873
- // Query the stock with the highest price
874
- const highestPricedStock = priceIndex.getRightMost();
875
- expect(priceIndex.get(highestPricedStock)?.symbol).toBe('AMZN'); // Amazon has the highest price
898
+ expect(pricesInRange).toEqual(['Item B', 'Item C']);
899
+ });
900
+
901
+ it('@example Red-Black Tree as database index for stock market data', () => {
902
+ interface StockPrice {
903
+ symbol: string;
904
+ volume: number;
905
+ timestamp: Date;
906
+ }
876
907
 
877
- // Query stocks within a specific price range (200 to 400)
878
- const stocksInRange = priceIndex.rangeSearch(
879
- [200, 400], // Price range
880
- node => priceIndex.get(node)?.symbol // Extract stock symbols for the result
881
- );
882
- expect(stocksInRange).toEqual(['GOOGL', 'META', 'MSFT']); // Verify stocks in the range
908
+ // Simulate real-time stock price index
909
+ const priceIndex = new RedBlackTree<number, StockPrice>([
910
+ [142.5, { symbol: 'AAPL', volume: 1000000, timestamp: new Date() }],
911
+ [335.2, { symbol: 'MSFT', volume: 800000, timestamp: new Date() }],
912
+ [3285.04, { symbol: 'AMZN', volume: 500000, timestamp: new Date() }],
913
+ [267.98, { symbol: 'META', volume: 750000, timestamp: new Date() }],
914
+ [234.57, { symbol: 'GOOGL', volume: 900000, timestamp: new Date() }]
915
+ ]);
916
+
917
+ // Find highest-priced stock
918
+ const maxPrice = priceIndex.getRightMost();
919
+ expect(priceIndex.get(maxPrice)?.symbol).toBe('AMZN');
920
+
921
+ // Find stocks in price range [200, 400] for portfolio balancing
922
+ const stocksInRange = priceIndex.rangeSearch([200, 400], node => {
923
+ const stock = priceIndex.get(node);
924
+ return {
925
+ symbol: stock?.symbol,
926
+ price: node,
927
+ volume: stock?.volume
928
+ };
929
+ });
930
+
931
+ expect(stocksInRange.length).toBe(3);
932
+ expect(stocksInRange.some((s: any) => s.symbol === 'GOOGL')).toBe(true);
933
+ expect(stocksInRange.some((s: any) => s.symbol === 'META')).toBe(true);
934
+ expect(stocksInRange.some((s: any) => s.symbol === 'MSFT')).toBe(true);
883
935
  });
884
936
  });
@@ -819,8 +819,8 @@ describe('TreeMultiMap - _deleteFixup', () => {
819
819
  describe('real world data', () => {
820
820
  it('cost of living', () => {
821
821
  const indexedByRank = new TreeMultiMap(costOfLiving, {
822
- specifyComparable: node => node.rank,
823
- toEntryFn: raw => [raw, undefined]
822
+ toEntryFn: raw => [raw, undefined],
823
+ comparator: (a, b) => a.rank - b.rank,
824
824
  });
825
825
  expect(indexedByRank.size).toBe(7);
826
826
  expect(indexedByRank.dfs(node => node?.key?.country)).toEqual([
@@ -1050,3 +1050,136 @@ describe('delete', () => {
1050
1050
  //
1051
1051
  // })
1052
1052
  });
1053
+
1054
+ describe('classic use', () => {
1055
+ it('@example basic DirectedGraph vertex and edge creation', () => {
1056
+ // Create a simple directed graph
1057
+ const graph = new DirectedGraph<string>();
1058
+
1059
+ // Add vertices
1060
+ graph.addVertex('A');
1061
+ graph.addVertex('B');
1062
+ graph.addVertex('C');
1063
+
1064
+ // Verify vertices exist
1065
+ expect(graph.hasVertex('A')).toBe(true);
1066
+ expect(graph.hasVertex('B')).toBe(true);
1067
+ expect(graph.hasVertex('C')).toBe(true);
1068
+ expect(graph.hasVertex('D')).toBe(false);
1069
+
1070
+ // Check vertex count
1071
+ expect(graph.size).toBe(3);
1072
+ });
1073
+
1074
+ it('@example DirectedGraph edge operations', () => {
1075
+ const graph = new DirectedGraph<string>();
1076
+
1077
+ // Add vertices
1078
+ graph.addVertex('A');
1079
+ graph.addVertex('B');
1080
+ graph.addVertex('C');
1081
+
1082
+ // Add directed edges
1083
+ graph.addEdge('A', 'B', 1);
1084
+ graph.addEdge('B', 'C', 2);
1085
+ graph.addEdge('A', 'C', 3);
1086
+
1087
+ // Verify edges exist
1088
+ expect(graph.hasEdge('A', 'B')).toBe(true);
1089
+ expect(graph.hasEdge('B', 'C')).toBe(true);
1090
+ expect(graph.hasEdge('C', 'B')).toBe(false); // Graph is directed
1091
+
1092
+ // Get neighbors of A
1093
+ const neighborsA = graph.getNeighbors('A');
1094
+ expect(neighborsA[0].key).toBe('B');
1095
+ expect(neighborsA[1].key).toBe('C');
1096
+ });
1097
+
1098
+ it('@example DirectedGraph deleteEdge and vertex operations', () => {
1099
+ const graph = new DirectedGraph<string>();
1100
+
1101
+ // Build a small graph
1102
+ graph.addVertex('X');
1103
+ graph.addVertex('Y');
1104
+ graph.addVertex('Z');
1105
+ graph.addEdge('X', 'Y', 1);
1106
+ graph.addEdge('Y', 'Z', 2);
1107
+
1108
+ // Delete an edge
1109
+ graph.deleteEdgeSrcToDest('X', 'Y');
1110
+ expect(graph.hasEdge('X', 'Y')).toBe(false);
1111
+
1112
+ // Edge in other direction should not exist
1113
+ expect(graph.hasEdge('Y', 'X')).toBe(false);
1114
+
1115
+ // Other edges should remain
1116
+ expect(graph.hasEdge('Y', 'Z')).toBe(true);
1117
+
1118
+ // Delete a vertex
1119
+ graph.deleteVertex('Y');
1120
+ expect(graph.hasVertex('Y')).toBe(false);
1121
+ expect(graph.size).toBe(2);
1122
+ });
1123
+
1124
+ it('@example DirectedGraph topologicalSort for task scheduling', () => {
1125
+ const graph = new DirectedGraph<string>();
1126
+
1127
+ // Build a DAG (Directed Acyclic Graph) for task dependencies
1128
+ graph.addVertex('Design');
1129
+ graph.addVertex('Implement');
1130
+ graph.addVertex('Test');
1131
+ graph.addVertex('Deploy');
1132
+
1133
+ // Add dependency edges
1134
+ graph.addEdge('Design', 'Implement', 1); // Design must come before Implement
1135
+ graph.addEdge('Implement', 'Test', 1); // Implement must come before Test
1136
+ graph.addEdge('Test', 'Deploy', 1); // Test must come before Deploy
1137
+
1138
+ // Topological sort gives valid execution order
1139
+ const executionOrder = graph.topologicalSort();
1140
+ expect(executionOrder).toBeDefined();
1141
+ expect(executionOrder).toEqual(['Design', 'Implement', 'Test', 'Deploy']);
1142
+
1143
+ // All vertices should be included
1144
+ expect(executionOrder?.length).toBe(4);
1145
+ });
1146
+
1147
+ it('@example DirectedGraph dijkstra shortest path for network routing', () => {
1148
+ // Build a weighted directed graph representing network nodes and costs
1149
+ const network = new DirectedGraph<string>();
1150
+
1151
+ // Add network nodes
1152
+ network.addVertex('Router-A');
1153
+ network.addVertex('Router-B');
1154
+ network.addVertex('Router-C');
1155
+ network.addVertex('Router-D');
1156
+ network.addVertex('Router-E');
1157
+
1158
+ // Add weighted edges (network latency costs)
1159
+ network.addEdge('Router-A', 'Router-B', 5);
1160
+ network.addEdge('Router-A', 'Router-C', 10);
1161
+ network.addEdge('Router-B', 'Router-D', 3);
1162
+ network.addEdge('Router-C', 'Router-D', 2);
1163
+ network.addEdge('Router-D', 'Router-E', 4);
1164
+ network.addEdge('Router-B', 'Router-E', 12);
1165
+
1166
+ // Find shortest path from Router-A to Router-E
1167
+ const { minDist, minPath } = network.dijkstra('Router-A', 'Router-E', true, true) || {
1168
+ minDist: undefined,
1169
+ minPath: undefined
1170
+ };
1171
+
1172
+ // Verify shortest path is found
1173
+ expect(minDist).toBeDefined();
1174
+ expect(minPath).toBeDefined();
1175
+
1176
+ // Shortest path should be A -> B -> D -> E with cost 5+3+4=12
1177
+ // Or A -> C -> D -> E with cost 10+2+4=16
1178
+ // So the minimum is 12
1179
+ expect(minDist).toBeLessThanOrEqual(16);
1180
+
1181
+ // Verify path is valid (includes start and end)
1182
+ expect(minPath?.[0].key).toBe('Router-A');
1183
+ expect(minPath?.[minPath.length - 1].key).toBe('Router-E');
1184
+ });
1185
+ });
@@ -613,3 +613,170 @@ describe('UndirectedGraph tarjan', () => {
613
613
  // expect(getAsVerticesArrays(ccs)).toEqual([["K", "J", "I", "H", "D", "C", "B"], ["G", "F", "E"], ["A"]]);
614
614
  // });
615
615
  });
616
+
617
+ describe('classic use', () => {
618
+ it('@example basic UndirectedGraph vertex and edge creation', () => {
619
+ // Create a simple undirected graph
620
+ const graph = new UndirectedGraph<string>();
621
+
622
+ // Add vertices
623
+ graph.addVertex('A');
624
+ graph.addVertex('B');
625
+ graph.addVertex('C');
626
+ graph.addVertex('D');
627
+
628
+ // Verify vertices exist
629
+ expect(graph.hasVertex('A')).toBe(true);
630
+ expect(graph.hasVertex('B')).toBe(true);
631
+ expect(graph.hasVertex('E')).toBe(false);
632
+
633
+ // Check vertex count
634
+ expect(graph.size).toBe(4);
635
+ });
636
+
637
+ it('@example UndirectedGraph edge operations (bidirectional)', () => {
638
+ const graph = new UndirectedGraph<string>();
639
+
640
+ // Add vertices
641
+ graph.addVertex('A');
642
+ graph.addVertex('B');
643
+ graph.addVertex('C');
644
+
645
+ // Add undirected edges (both directions automatically)
646
+ graph.addEdge('A', 'B', 1);
647
+ graph.addEdge('B', 'C', 2);
648
+ graph.addEdge('A', 'C', 3);
649
+
650
+ // Verify edges exist in both directions
651
+ expect(graph.hasEdge('A', 'B')).toBe(true);
652
+ expect(graph.hasEdge('B', 'A')).toBe(true); // Bidirectional!
653
+
654
+ expect(graph.hasEdge('C', 'B')).toBe(true);
655
+ expect(graph.hasEdge('B', 'C')).toBe(true); // Bidirectional!
656
+
657
+ // Get neighbors of A
658
+ const neighborsA = graph.getNeighbors('A');
659
+ expect(neighborsA[0].key).toBe('B');
660
+ expect(neighborsA[1].key).toBe('C');
661
+ });
662
+
663
+ it('@example UndirectedGraph deleteEdge and vertex operations', () => {
664
+ const graph = new UndirectedGraph<string>();
665
+
666
+ // Build a simple undirected graph
667
+ graph.addVertex('X');
668
+ graph.addVertex('Y');
669
+ graph.addVertex('Z');
670
+ graph.addEdge('X', 'Y', 1);
671
+ graph.addEdge('Y', 'Z', 2);
672
+ graph.addEdge('X', 'Z', 3);
673
+
674
+ // Delete an edge
675
+ graph.deleteEdge('X', 'Y');
676
+ expect(graph.hasEdge('X', 'Y')).toBe(false);
677
+
678
+ // Bidirectional deletion confirmed
679
+ expect(graph.hasEdge('Y', 'X')).toBe(false);
680
+
681
+ // Other edges should remain
682
+ expect(graph.hasEdge('Y', 'Z')).toBe(true);
683
+ expect(graph.hasEdge('Z', 'Y')).toBe(true);
684
+
685
+ // Delete a vertex
686
+ graph.deleteVertex('Y');
687
+ expect(graph.hasVertex('Y')).toBe(false);
688
+ expect(graph.size).toBe(2);
689
+ });
690
+
691
+ it('@example UndirectedGraph connectivity and neighbors', () => {
692
+ const graph = new UndirectedGraph<string>();
693
+
694
+ // Build a friendship network
695
+ const people = ['Alice', 'Bob', 'Charlie', 'Diana', 'Eve'];
696
+ for (const person of people) {
697
+ graph.addVertex(person);
698
+ }
699
+
700
+ // Add friendships (undirected edges)
701
+ graph.addEdge('Alice', 'Bob', 1);
702
+ graph.addEdge('Alice', 'Charlie', 1);
703
+ graph.addEdge('Bob', 'Diana', 1);
704
+ graph.addEdge('Charlie', 'Eve', 1);
705
+ graph.addEdge('Diana', 'Eve', 1);
706
+
707
+ // Get friends of each person
708
+ const aliceFriends = graph.getNeighbors('Alice');
709
+ expect(aliceFriends[0].key).toBe('Bob');
710
+ expect(aliceFriends[1].key).toBe('Charlie');
711
+ expect(aliceFriends.length).toBe(2);
712
+
713
+ const dianaFriends = graph.getNeighbors('Diana');
714
+ expect(dianaFriends[0].key).toBe('Bob');
715
+ expect(dianaFriends[1].key).toBe('Eve');
716
+ expect(dianaFriends.length).toBe(2);
717
+
718
+ // Verify bidirectional friendship
719
+ const bobFriends = graph.getNeighbors('Bob');
720
+ expect(bobFriends[0].key).toBe('Alice'); // Alice -> Bob -> Alice ✓
721
+ expect(bobFriends[1].key).toBe('Diana');
722
+ });
723
+
724
+ it('@example UndirectedGraph for social network connectivity analysis', () => {
725
+ interface Person {
726
+ id: number;
727
+ name: string;
728
+ location: string;
729
+ }
730
+
731
+ // UndirectedGraph is perfect for modeling symmetric relationships
732
+ // (friendships, collaborations, partnerships)
733
+ const socialNetwork = new UndirectedGraph<number, Person>();
734
+
735
+ // Add people as vertices
736
+ const people: [number, Person][] = [
737
+ [1, { id: 1, name: 'Alice', location: 'New York' }],
738
+ [2, { id: 2, name: 'Bob', location: 'San Francisco' }],
739
+ [3, { id: 3, name: 'Charlie', location: 'Boston' }],
740
+ [4, { id: 4, name: 'Diana', location: 'New York' }],
741
+ [5, { id: 5, name: 'Eve', location: 'Seattle' }]
742
+ ];
743
+
744
+ for (const [id] of people) {
745
+ socialNetwork.addVertex(id);
746
+ }
747
+
748
+ // Add friendships (automatically bidirectional)
749
+ socialNetwork.addEdge(1, 2, 1); // Alice <-> Bob
750
+ socialNetwork.addEdge(1, 3, 1); // Alice <-> Charlie
751
+ socialNetwork.addEdge(2, 4, 1); // Bob <-> Diana
752
+ socialNetwork.addEdge(3, 5, 1); // Charlie <-> Eve
753
+ socialNetwork.addEdge(4, 5, 1); // Diana <-> Eve
754
+
755
+ expect(socialNetwork.size).toBe(5);
756
+
757
+ // Find direct connections for Alice
758
+ const aliceConnections = socialNetwork.getNeighbors(1);
759
+ expect(aliceConnections[0].key).toBe(2);
760
+ expect(aliceConnections[1].key).toBe(3);
761
+ expect(aliceConnections.length).toBe(2);
762
+
763
+ // Verify bidirectional connections
764
+ expect(socialNetwork.hasEdge(1, 2)).toBe(true);
765
+ expect(socialNetwork.hasEdge(2, 1)).toBe(true); // Friendship works both ways!
766
+
767
+ // Remove a person from network
768
+ socialNetwork.deleteVertex(2); // Bob leaves
769
+ expect(socialNetwork.hasVertex(2)).toBe(false);
770
+ expect(socialNetwork.size).toBe(4);
771
+
772
+ // Alice loses Bob as a friend
773
+ const updatedAliceConnections = socialNetwork.getNeighbors(1);
774
+ expect(updatedAliceConnections[0].key).toBe(3);
775
+ expect(updatedAliceConnections[1]).toBe(undefined);
776
+
777
+ // Diana loses Bob as a friend
778
+ const dianaConnections = socialNetwork.getNeighbors(4);
779
+ expect(dianaConnections[0].key).toBe(5);
780
+ expect(dianaConnections[1]).toBe(undefined);
781
+ });
782
+ });
@@ -918,7 +918,127 @@ describe('classic uses', () => {
918
918
  });
919
919
 
920
920
  describe('classic uses', () => {
921
- it('@example fast lookup of values by key', () => {
921
+ it('@example basic HashMap creation and set operation', () => {
922
+ // Create a simple HashMap with key-value pairs
923
+ const map = new HashMap<number, string>([
924
+ [1, 'one'],
925
+ [2, 'two'],
926
+ [3, 'three']
927
+ ]);
928
+
929
+ // Verify size
930
+ expect(map.size).toBe(3);
931
+
932
+ // Set a new key-value pair
933
+ map.set(4, 'four');
934
+ expect(map.size).toBe(4);
935
+
936
+ // Verify entries
937
+ expect([...map.entries()]).toHaveLength(4);
938
+ });
939
+
940
+ it('@example HashMap get and has operations', () => {
941
+ const map = new HashMap<string, number>([
942
+ ['apple', 1],
943
+ ['banana', 2],
944
+ ['cherry', 3]
945
+ ]);
946
+
947
+ // Check if key exists
948
+ expect(map.has('apple')).toBe(true);
949
+ expect(map.has('date')).toBe(false);
950
+
951
+ // Get value by key
952
+ expect(map.get('banana')).toBe(2);
953
+ expect(map.get('grape')).toBeUndefined();
954
+
955
+ // Get all keys and values
956
+ const keys = [...map.keys()];
957
+ const values = [...map.values()];
958
+ expect(keys).toContain('apple');
959
+ expect(values).toContain(3);
960
+ });
961
+
962
+ it('@example HashMap iteration and filter operations', () => {
963
+ const map = new HashMap<number, string>([
964
+ [1, 'Alice'],
965
+ [2, 'Bob'],
966
+ [3, 'Charlie'],
967
+ [4, 'Diana'],
968
+ [5, 'Eve']
969
+ ]);
970
+
971
+ // Iterate through entries
972
+ const entries: [number, string][] = [];
973
+ for (const [key, value] of map) {
974
+ entries.push([key, value]);
975
+ }
976
+ expect(entries).toHaveLength(5);
977
+
978
+ // Filter operation (for iteration with collection methods)
979
+ const filtered = [...map].filter(([key]) => key > 2);
980
+ expect(filtered.length).toBe(3);
981
+
982
+ // Map operation
983
+ const values = [...map.values()].map(v => v.length);
984
+ expect(values).toContain(3); // 'Bob', 'Eve'
985
+ expect(values).toContain(7); // 'Charlie'
986
+ });
987
+
988
+ it('@example HashMap for user session caching O(1) performance', () => {
989
+ interface UserSession {
990
+ userId: number;
991
+ username: string;
992
+ loginTime: number;
993
+ lastActivity: number;
994
+ }
995
+
996
+ // HashMap provides O(1) average-case performance for set/get/delete
997
+ // Perfect for session management with fast lookups
998
+ const sessionCache = new HashMap<string, UserSession>();
999
+
1000
+ // Simulate user sessions
1001
+ const sessions: [string, UserSession][] = [
1002
+ ['session_001', { userId: 1, username: 'alice', loginTime: 1000, lastActivity: 1050 }],
1003
+ ['session_002', { userId: 2, username: 'bob', loginTime: 1100, lastActivity: 1150 }],
1004
+ ['session_003', { userId: 3, username: 'charlie', loginTime: 1200, lastActivity: 1250 }]
1005
+ ];
1006
+
1007
+ // Store sessions with O(1) insertion
1008
+ for (const [token, session] of sessions) {
1009
+ sessionCache.set(token, session);
1010
+ }
1011
+
1012
+ expect(sessionCache.size).toBe(3);
1013
+
1014
+ // Retrieve session with O(1) lookup
1015
+ const userSession = sessionCache.get('session_001');
1016
+ expect(userSession?.username).toBe('alice');
1017
+ expect(userSession?.userId).toBe(1);
1018
+
1019
+ // Update session with O(1) operation
1020
+ if (userSession) {
1021
+ userSession.lastActivity = 2000;
1022
+ sessionCache.set('session_001', userSession);
1023
+ }
1024
+
1025
+ // Check updated value
1026
+ const updated = sessionCache.get('session_001');
1027
+ expect(updated?.lastActivity).toBe(2000);
1028
+
1029
+ // Cleanup: delete expired sessions
1030
+ sessionCache.delete('session_002');
1031
+ expect(sessionCache.has('session_002')).toBe(false);
1032
+
1033
+ // Verify remaining sessions
1034
+ expect(sessionCache.size).toBe(2);
1035
+
1036
+ // Get all active sessions
1037
+ const activeCount = [...sessionCache.values()].length;
1038
+ expect(activeCount).toBe(2);
1039
+ });
1040
+
1041
+ it('Fast lookup of values by key', () => {
922
1042
  const hashMap = new HashMap<number, string>();
923
1043
  hashMap.set(1, 'A');
924
1044
  hashMap.set(2, 'B');
@@ -930,7 +1050,7 @@ describe('classic uses', () => {
930
1050
  expect(hashMap.get(99)).toBeUndefined(); // Key not present
931
1051
  });
932
1052
 
933
- it('@example remove duplicates when adding multiple entries', () => {
1053
+ it('Remove duplicates when adding multiple entries', () => {
934
1054
  const hashMap = new HashMap<number, string>();
935
1055
  hashMap.set(1, 'A');
936
1056
  hashMap.set(2, 'B');
@@ -941,7 +1061,7 @@ describe('classic uses', () => {
941
1061
  expect(hashMap.get(2)).toBe('B');
942
1062
  });
943
1063
 
944
- it('@example count occurrences of keys', () => {
1064
+ it('Count occurrences of keys', () => {
945
1065
  const data = [1, 2, 1, 3, 2, 1];
946
1066
 
947
1067
  const countMap = new HashMap<number, number>();
@@ -976,4 +1096,30 @@ describe('classic uses', () => {
976
1096
  expect(groupedMap.get('A')).toEqual([1, 3]);
977
1097
  expect(groupedMap.get('B')).toEqual([2, 4]);
978
1098
  });
1099
+
1100
+ it('HashMap delete and clear operations', () => {
1101
+ const map = new HashMap<string, number>([
1102
+ ['a', 10],
1103
+ ['b', 20],
1104
+ ['c', 30],
1105
+ ['d', 40]
1106
+ ]);
1107
+
1108
+ // Delete a key
1109
+ map.delete('b');
1110
+ expect(map.has('b')).toBe(false);
1111
+ expect(map.size).toBe(3);
1112
+
1113
+ // Value for deleted key is undefined
1114
+ expect(map.get('b')).toBeUndefined();
1115
+
1116
+ // Other entries remain
1117
+ expect(map.get('a')).toBe(10);
1118
+ expect(map.get('c')).toBe(30);
1119
+
1120
+ // Clear all entries
1121
+ map.clear();
1122
+ expect(map.size).toBe(0);
1123
+ expect(map.has('a')).toBe(false);
1124
+ });
979
1125
  });