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
@@ -813,93 +813,124 @@ describe('Deque', () => {
813
813
  });
814
814
 
815
815
  describe('classic uses', () => {
816
- it('@example prize roulette', () => {
817
- class PrizeRoulette {
818
- private deque: Deque<string>;
816
+ it('@example basic Deque creation and push/pop operations', () => {
817
+ // Create a simple Deque with initial values
818
+ const deque = new Deque([1, 2, 3, 4, 5]);
819
819
 
820
- constructor(prizes: string[]) {
821
- // Initialize the deque with prizes
822
- this.deque = new Deque<string>(prizes);
823
- }
820
+ // Verify the deque maintains insertion order
821
+ expect([...deque]).toEqual([1, 2, 3, 4, 5]);
824
822
 
825
- // Rotate clockwise to the right (forward)
826
- rotateClockwise(steps: number): void {
827
- const n = this.deque.length;
828
- if (n === 0) return;
823
+ // Check length
824
+ expect(deque.length).toBe(5);
829
825
 
830
- for (let i = 0; i < steps; i++) {
831
- const last = this.deque.pop(); // Remove the last element
832
- this.deque.unshift(last!); // Add it to the front
833
- }
834
- }
826
+ // Push to the end
827
+ deque.push(6);
828
+ expect(deque.length).toBe(6);
835
829
 
836
- // Rotate counterclockwise to the left (backward)
837
- rotateCounterClockwise(steps: number): void {
838
- const n = this.deque.length;
839
- if (n === 0) return;
830
+ // Pop from the end
831
+ const last = deque.pop();
832
+ expect(last).toBe(6);
833
+ });
840
834
 
841
- for (let i = 0; i < steps; i++) {
842
- const first = this.deque.shift(); // Remove the first element
843
- this.deque.push(first!); // Add it to the back
844
- }
845
- }
835
+ it('@example Deque shift and unshift operations', () => {
836
+ const deque = new Deque<number>([20, 30, 40]);
846
837
 
847
- // Display the current prize at the head
848
- display() {
849
- return this.deque.first;
850
- }
851
- }
838
+ // Unshift adds to the front
839
+ deque.unshift(10);
840
+ expect([...deque]).toEqual([10, 20, 30, 40]);
841
+
842
+ // Shift removes from the front (O(1) complexity!)
843
+ const first = deque.shift();
844
+ expect(first).toBe(10);
845
+
846
+ // Verify remaining elements
847
+ expect([...deque]).toEqual([20, 30, 40]);
848
+ expect(deque.length).toBe(3);
849
+ });
852
850
 
853
- // Example usage
854
- const prizes = ['Car', 'Bike', 'Laptop', 'Phone', 'Watch', 'Headphones']; // Initialize the prize list
855
- const roulette = new PrizeRoulette(prizes);
851
+ it('@example Deque peek at both ends', () => {
852
+ const deque = new Deque<number>([10, 20, 30, 40, 50]);
856
853
 
857
- // Display the initial state
858
- expect(roulette.display()).toBe('Car'); // Car
854
+ // Get first element without removing
855
+ const first = deque.at(0);
856
+ expect(first).toBe(10);
859
857
 
860
- // Rotate clockwise by 3 steps
861
- roulette.rotateClockwise(3);
862
- expect(roulette.display()).toBe('Phone'); // Phone
858
+ // Get last element without removing
859
+ const last = deque.at(deque.length - 1);
860
+ expect(last).toBe(50);
863
861
 
864
- // Rotate counterclockwise by 2 steps
865
- roulette.rotateCounterClockwise(2);
866
- expect(roulette.display()).toBe('Headphones'); // Headphones
862
+ // Length unchanged
863
+ expect(deque.length).toBe(5);
867
864
  });
868
865
 
869
- it('@example sliding window', () => {
870
- // Maximum function of sliding window
871
- function maxSlidingWindow(nums: number[], k: number): number[] {
872
- const n = nums.length;
873
- if (n * k === 0) return [];
866
+ it('@example Deque for...of iteration and reverse', () => {
867
+ const deque = new Deque<string>(['A', 'B', 'C', 'D']);
874
868
 
875
- const deq = new Deque<number>();
876
- const result: number[] = [];
869
+ // Iterate forward
870
+ const forward: string[] = [];
871
+ for (const item of deque) {
872
+ forward.push(item);
873
+ }
874
+ expect(forward).toEqual(['A', 'B', 'C', 'D']);
877
875
 
878
- for (let i = 0; i < n; i++) {
879
- // Delete indexes in the queue that are not within the window range
880
- if (deq.length > 0 && deq.first! === i - k) {
881
- deq.shift();
882
- }
876
+ // Reverse the deque
877
+ deque.reverse();
878
+ const backward: string[] = [];
879
+ for (const item of deque) {
880
+ backward.push(item);
881
+ }
882
+ expect(backward).toEqual(['D', 'C', 'B', 'A']);
883
+ });
883
884
 
884
- // Remove all indices less than the current value from the tail of the queue
885
- while (deq.length > 0 && nums[deq.last!] < nums[i]) {
886
- deq.pop();
887
- }
885
+ it('@example Deque as sliding window for stream processing', () => {
886
+ interface DataPoint {
887
+ timestamp: number;
888
+ value: number;
889
+ sensor: string;
890
+ }
888
891
 
889
- // Add the current index to the end of the queue
890
- deq.push(i);
892
+ // Create a deque-based sliding window for real-time data aggregation
893
+ const windowSize = 3;
894
+ const dataWindow = new Deque<DataPoint>();
891
895
 
892
- // Add the maximum value of the window to the results
893
- if (i >= k - 1) {
894
- result.push(nums[deq.first!]);
895
- }
896
+ // Simulate incoming sensor data stream
897
+ const incomingData: DataPoint[] = [
898
+ { timestamp: 1000, value: 25.5, sensor: 'temp-01' },
899
+ { timestamp: 1100, value: 26.2, sensor: 'temp-01' },
900
+ { timestamp: 1200, value: 25.8, sensor: 'temp-01' },
901
+ { timestamp: 1300, value: 27.1, sensor: 'temp-01' },
902
+ { timestamp: 1400, value: 26.9, sensor: 'temp-01' }
903
+ ];
904
+
905
+ const windowResults: Array<{ avgValue: number; windowSize: number }> = [];
906
+
907
+ for (const dataPoint of incomingData) {
908
+ // Add new data to the end
909
+ dataWindow.push(dataPoint);
910
+
911
+ // Remove oldest data when window exceeds size (O(1) from front)
912
+ if (dataWindow.length > windowSize) {
913
+ dataWindow.shift();
914
+ }
915
+
916
+ // Calculate average of current window
917
+ let sum = 0;
918
+ for (const point of dataWindow) {
919
+ sum += point.value;
896
920
  }
921
+ const avg = sum / dataWindow.length;
897
922
 
898
- return result;
923
+ windowResults.push({
924
+ avgValue: Math.round(avg * 10) / 10,
925
+ windowSize: dataWindow.length
926
+ });
899
927
  }
900
928
 
901
- const nums = [1, 3, -1, -3, 5, 3, 6, 7];
902
- const k = 3;
903
- expect(maxSlidingWindow(nums, k)).toEqual([3, 3, 5, 5, 6, 7]); // Output: [3, 3, 5, 5, 6, 7]
929
+ // Verify sliding window behavior
930
+ expect(windowResults.length).toBe(5);
931
+ expect(windowResults[0].windowSize).toBe(1); // First window has 1 element
932
+ expect(windowResults[2].windowSize).toBe(3); // Windows are at max size from 3rd onwards
933
+ expect(windowResults[4].windowSize).toBe(3); // Last window still has 3 elements
934
+ expect(dataWindow.length).toBe(3); // Final window contains last 3 elements
904
935
  });
905
936
  });
@@ -594,76 +594,110 @@ describe('Queue', () => {
594
594
  });
595
595
 
596
596
  describe('classic uses', () => {
597
- it('@example Sliding Window using Queue', () => {
598
- const nums = [2, 3, 4, 1, 5];
599
- const k = 2;
600
- const queue = new Queue<number>();
597
+ it('@example basic Queue creation and push operation', () => {
598
+ // Create a simple Queue with initial values
599
+ const queue = new Queue([1, 2, 3, 4, 5]);
601
600
 
602
- let maxSum = 0;
603
- let currentSum = 0;
601
+ // Verify the queue maintains insertion order
602
+ expect([...queue]).toEqual([1, 2, 3, 4, 5]);
604
603
 
605
- nums.forEach(num => {
606
- queue.push(num);
607
- currentSum += num;
604
+ // Check length
605
+ expect(queue.length).toBe(5);
606
+ });
608
607
 
609
- if (queue.length > k) {
610
- currentSum -= queue.shift()!;
611
- }
608
+ it('@example Queue shift and peek operations', () => {
609
+ const queue = new Queue<number>([10, 20, 30, 40]);
612
610
 
613
- if (queue.length === k) {
614
- maxSum = Math.max(maxSum, currentSum);
615
- }
616
- });
611
+ // Peek at the front element without removing it
612
+ expect(queue.first).toBe(10);
613
+
614
+ // Remove and get the first element (FIFO)
615
+ const first = queue.shift();
616
+ expect(first).toBe(10);
617
617
 
618
- expect(maxSum).toBe(7); // Maximum sum is from subarray [3, 4].
618
+ // Verify remaining elements and length decreased
619
+ expect([...queue]).toEqual([20, 30, 40]);
620
+ expect(queue.length).toBe(3);
619
621
  });
620
622
 
621
- it('@example Breadth-First Search (BFS) using Queue', () => {
622
- const graph: { [key in number]: number[] } = {
623
- 1: [2, 3],
624
- 2: [4, 5],
625
- 3: [],
626
- 4: [],
627
- 5: []
628
- };
623
+ it('@example Queue for...of iteration and isEmpty check', () => {
624
+ const queue = new Queue<string>(['A', 'B', 'C', 'D']);
629
625
 
630
- const queue = new Queue<number>();
631
- const visited: number[] = [];
626
+ const elements: string[] = [];
627
+ for (const item of queue) {
628
+ elements.push(item);
629
+ }
632
630
 
633
- queue.push(1);
631
+ // Verify all elements are iterated in order
632
+ expect(elements).toEqual(['A', 'B', 'C', 'D']);
634
633
 
635
- while (!queue.isEmpty()) {
636
- const node = queue.shift()!;
637
- if (!visited.includes(node)) {
638
- visited.push(node);
639
- graph[node].forEach(neighbor => queue.push(neighbor));
640
- }
634
+ // Process all elements
635
+ while (queue.length > 0) {
636
+ queue.shift();
641
637
  }
642
638
 
643
- expect(visited).toEqual([1, 2, 3, 4, 5]); // Expected BFS traversal order.
639
+ expect(queue.length).toBe(0);
644
640
  });
645
641
 
646
- it('Task Scheduling using Queue', () => {
647
- const tasks = ['A', 'A', 'A', 'B', 'B', 'B'];
648
- const cooldown = 2;
649
-
650
- const taskQueue = new Queue<string>();
651
- const cooldownQueue = new Queue<string>();
642
+ it('@example Queue as message broker for event processing', () => {
643
+ interface Message {
644
+ id: string;
645
+ type: 'email' | 'sms' | 'push';
646
+ recipient: string;
647
+ content: string;
648
+ timestamp: Date;
649
+ }
652
650
 
653
- for (const task of tasks) {
654
- while (!cooldownQueue.isEmpty() && cooldownQueue.first === task) {
655
- cooldownQueue.shift();
656
- taskQueue.push('idle');
651
+ // Create a message queue for real-time event processing
652
+ const messageQueue = new Queue<Message>([
653
+ {
654
+ id: 'msg-001',
655
+ type: 'email',
656
+ recipient: 'user@example.com',
657
+ content: 'Welcome!',
658
+ timestamp: new Date()
659
+ },
660
+ {
661
+ id: 'msg-002',
662
+ type: 'sms',
663
+ recipient: '+1234567890',
664
+ content: 'OTP: 123456',
665
+ timestamp: new Date()
666
+ },
667
+ {
668
+ id: 'msg-003',
669
+ type: 'push',
670
+ recipient: 'device-token-xyz',
671
+ content: 'New notification',
672
+ timestamp: new Date()
673
+ },
674
+ {
675
+ id: 'msg-004',
676
+ type: 'email',
677
+ recipient: 'admin@example.com',
678
+ content: 'Daily report',
679
+ timestamp: new Date()
657
680
  }
681
+ ]);
658
682
 
659
- taskQueue.push(task);
660
- cooldownQueue.push(task);
661
- if (cooldownQueue.length > cooldown) {
662
- cooldownQueue.shift();
683
+ // Process messages in FIFO order (first message first)
684
+ const processedMessages: string[] = [];
685
+ while (messageQueue.length > 0) {
686
+ const message = messageQueue.shift();
687
+ if (message) {
688
+ processedMessages.push(`${message.type}:${message.recipient}`);
663
689
  }
664
690
  }
665
691
 
666
- const scheduled = taskQueue.elements;
667
- expect(scheduled).toEqual(['A', 'idle', 'A', 'idle', 'A', 'B', 'B', 'idle', 'idle', 'B']);
692
+ // Verify messages were processed in order
693
+ expect(processedMessages).toEqual([
694
+ 'email:user@example.com',
695
+ 'sms:+1234567890',
696
+ 'push:device-token-xyz',
697
+ 'email:admin@example.com'
698
+ ]);
699
+
700
+ // Queue should be empty after processing all messages
701
+ expect(messageQueue.length).toBe(0);
668
702
  });
669
703
  });
@@ -164,6 +164,50 @@ describe('Stack iterative methods', () => {
164
164
  });
165
165
 
166
166
  describe('classic uses', () => {
167
+ it('@example basic Stack creation and push operation', () => {
168
+ // Create a simple Stack with initial values
169
+ const stack = new Stack([1, 2, 3, 4, 5]);
170
+
171
+ // Verify the stack maintains insertion order (LIFO will be shown in pop)
172
+ expect([...stack]).toEqual([1, 2, 3, 4, 5]);
173
+
174
+ // Check length
175
+ expect(stack.size).toBe(5);
176
+
177
+ // Push a new element to the top
178
+ stack.push(6);
179
+ expect(stack.size).toBe(6);
180
+ });
181
+
182
+ it('@example Stack pop operation (LIFO - Last In First Out)', () => {
183
+ const stack = new Stack<number>([10, 20, 30, 40, 50]);
184
+
185
+ // Peek at the top element without removing
186
+ const top = stack.peek();
187
+ expect(top).toBe(50);
188
+
189
+ // Pop removes from the top (LIFO order)
190
+ const popped = stack.pop();
191
+ expect(popped).toBe(50);
192
+
193
+ // Next pop gets the previous element
194
+ const next = stack.pop();
195
+ expect(next).toBe(40);
196
+
197
+ // Verify length decreased
198
+ expect(stack.size).toBe(3);
199
+ });
200
+
201
+ it('@example Function Call Stack', () => {
202
+ const functionStack = new Stack<string>();
203
+ functionStack.push('main');
204
+ functionStack.push('foo');
205
+ functionStack.push('bar');
206
+ expect(functionStack.pop()).toBe('bar');
207
+ expect(functionStack.pop()).toBe('foo');
208
+ expect(functionStack.pop()).toBe('main');
209
+ });
210
+
167
211
  it('@example Balanced Parentheses or Brackets', () => {
168
212
  type ValidCharacters = ')' | '(' | ']' | '[' | '}' | '{';
169
213
 
@@ -197,21 +241,6 @@ describe('classic uses', () => {
197
241
  expect(stack.pop()).toBe(8);
198
242
  });
199
243
 
200
- it('@example Depth-First Search (DFS)', () => {
201
- const stack = new Stack<number>();
202
- const graph: { [key in number]: number[] } = { 1: [2, 3], 2: [4], 3: [5], 4: [], 5: [] };
203
- const visited: number[] = [];
204
- stack.push(1);
205
- while (!stack.isEmpty()) {
206
- const node = stack.pop()!;
207
- if (!visited.includes(node)) {
208
- visited.push(node);
209
- graph[node].forEach(neighbor => stack.push(neighbor));
210
- }
211
- }
212
- expect(visited).toEqual([1, 3, 5, 2, 4]); // Example DFS order
213
- });
214
-
215
244
  it('@example Backtracking Algorithms', () => {
216
245
  const stack = new Stack<[number, number]>();
217
246
  const maze = [
@@ -258,14 +287,18 @@ describe('classic uses', () => {
258
287
  expect(path).toContainEqual(end);
259
288
  });
260
289
 
261
- it('@example Function Call Stack', () => {
262
- const functionStack = new Stack<string>();
263
- functionStack.push('main');
264
- functionStack.push('foo');
265
- functionStack.push('bar');
266
- expect(functionStack.pop()).toBe('bar');
267
- expect(functionStack.pop()).toBe('foo');
268
- expect(functionStack.pop()).toBe('main');
290
+ it('@example Stock Span Problem', () => {
291
+ const stack = new Stack<number>();
292
+ const prices = [100, 80, 60, 70, 60, 75, 85];
293
+ const spans: number[] = [];
294
+ prices.forEach((price, i) => {
295
+ while (!stack.isEmpty() && prices[stack.peek()!] <= price) {
296
+ stack.pop();
297
+ }
298
+ spans.push(stack.isEmpty() ? i + 1 : i - stack.peek()!);
299
+ stack.push(i);
300
+ });
301
+ expect(spans).toEqual([1, 1, 1, 2, 1, 4, 6]);
269
302
  });
270
303
 
271
304
  it('@example Simplify File Paths', () => {
@@ -278,18 +311,94 @@ describe('classic uses', () => {
278
311
  expect(stack.elements.join('/')).toBe('c');
279
312
  });
280
313
 
281
- it('@example Stock Span Problem', () => {
314
+ it('Stack for function call stack simulation', () => {
315
+ interface CallFrame {
316
+ functionName: string;
317
+ lineNumber: number;
318
+ variables: Record<string, unknown>;
319
+ timestamp: number;
320
+ }
321
+
322
+ // Simulate a call stack for debugging/tracing
323
+ const callStack = new Stack<CallFrame>();
324
+
325
+ // Simulate function calls pushing frames onto stack
326
+ callStack.push({
327
+ functionName: 'main',
328
+ lineNumber: 1,
329
+ variables: { x: 10, y: 20 },
330
+ timestamp: 1000
331
+ });
332
+
333
+ callStack.push({
334
+ functionName: 'calculateSum',
335
+ lineNumber: 5,
336
+ variables: { a: 10, b: 20 },
337
+ timestamp: 1100
338
+ });
339
+
340
+ callStack.push({
341
+ functionName: 'helper',
342
+ lineNumber: 12,
343
+ variables: { result: 30 },
344
+ timestamp: 1200
345
+ });
346
+
347
+ // Verify current call frame
348
+ expect(callStack.size).toBe(3);
349
+ const currentFrame = callStack.peek();
350
+ expect(currentFrame?.functionName).toBe('helper');
351
+ expect(currentFrame?.lineNumber).toBe(12);
352
+
353
+ // Simulate function returns popping from stack (LIFO)
354
+ const returnedFrame = callStack.pop();
355
+ expect(returnedFrame?.functionName).toBe('helper');
356
+ expect(callStack.size).toBe(2);
357
+
358
+ // Next return
359
+ const nextReturn = callStack.pop();
360
+ expect(nextReturn?.functionName).toBe('calculateSum');
361
+
362
+ // Back to main
363
+ const mainFrame = callStack.pop();
364
+ expect(mainFrame?.functionName).toBe('main');
365
+
366
+ // Stack empty after all returns
367
+ expect(callStack.size).toBe(0);
368
+ });
369
+
370
+ it('Stack for...of iteration and isEmpty', () => {
371
+ const stack = new Stack<string>(['A', 'B', 'C', 'D']);
372
+
373
+ // Iterate through stack
374
+ const elements: string[] = [];
375
+ for (const item of stack) {
376
+ elements.push(item);
377
+ }
378
+ expect(elements).toEqual(['A', 'B', 'C', 'D']);
379
+
380
+ // Clear the stack
381
+ while (stack.size > 0) {
382
+ stack.pop();
383
+ }
384
+
385
+ // Stack is now empty
386
+ expect(stack.size).toBe(0);
387
+ });
388
+
389
+ it('Depth-First Search (DFS)', () => {
282
390
  const stack = new Stack<number>();
283
- const prices = [100, 80, 60, 70, 60, 75, 85];
284
- const spans: number[] = [];
285
- prices.forEach((price, i) => {
286
- while (!stack.isEmpty() && prices[stack.peek()!] <= price) {
287
- stack.pop();
391
+ const graph: { [key in number]: number[] } = { 1: [2, 3], 2: [4], 3: [5], 4: [], 5: [] };
392
+ const visited: number[] = [];
393
+ stack.push(1);
394
+ while (!stack.isEmpty()) {
395
+ const node = stack.pop()!;
396
+ if (!visited.includes(node)) {
397
+ visited.push(node);
398
+ graph[node].forEach(neighbor => stack.push(neighbor));
288
399
  }
289
- spans.push(stack.isEmpty() ? i + 1 : i - stack.peek()!);
290
- stack.push(i);
291
- });
292
- expect(spans).toEqual([1, 1, 1, 2, 1, 4, 6]);
400
+ }
401
+ expect(visited).toEqual([1, 3, 5, 2, 4]); // Example DFS order
293
402
  });
294
403
 
295
404
  it('Browser Navigation', () => {