data-structure-typed 2.2.1 → 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 +3 -1
  2. package/README.md +440 -1190
  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
@@ -452,18 +452,106 @@ describe('FibonacciHeap Stress Test', () => {
452
452
  });
453
453
 
454
454
  describe('classic use', () => {
455
- it('@example Use Heap to sort an array', () => {
456
- function heapSort(arr: number[]): number[] {
457
- const heap = new Heap<number>(arr, { comparator: (a, b) => a - b });
458
- const sorted: number[] = [];
459
- while (!heap.isEmpty()) {
460
- sorted.push(heap.poll()!); // Poll minimum element
455
+ it('@example basic Heap creation and add operation', () => {
456
+ // Create a min heap (default)
457
+ const minHeap = new Heap([5, 3, 7, 1, 9, 2]);
458
+
459
+ // Verify size
460
+ expect(minHeap.size).toBe(6);
461
+
462
+ // Add new element
463
+ minHeap.add(4);
464
+ expect(minHeap.size).toBe(7);
465
+
466
+ // Min heap property: smallest element at root
467
+ const min = minHeap.peek();
468
+ expect(min).toBe(1);
469
+ });
470
+
471
+ it('@example Heap with custom comparator (MaxHeap behavior)', () => {
472
+ interface Task {
473
+ id: number;
474
+ priority: number;
475
+ name: string;
476
+ }
477
+
478
+ // Custom comparator for max heap behavior (higher priority first)
479
+ const tasks: Task[] = [
480
+ { id: 1, priority: 5, name: 'Email' },
481
+ { id: 2, priority: 3, name: 'Chat' },
482
+ { id: 3, priority: 8, name: 'Alert' }
483
+ ];
484
+
485
+ const maxHeap = new Heap(tasks, {
486
+ comparator: (a: Task, b: Task) => b.priority - a.priority
487
+ });
488
+
489
+ expect(maxHeap.size).toBe(3);
490
+
491
+ // Peek returns highest priority task
492
+ const topTask = maxHeap.peek();
493
+ expect(topTask?.priority).toBe(8);
494
+ expect(topTask?.name).toBe('Alert');
495
+ });
496
+
497
+ it('@example Heap for event processing with priority', () => {
498
+ interface Event {
499
+ id: number;
500
+ type: 'critical' | 'warning' | 'info';
501
+ timestamp: number;
502
+ message: string;
503
+ }
504
+
505
+ // Custom priority: critical > warning > info
506
+ const priorityMap = { critical: 3, warning: 2, info: 1 };
507
+
508
+ const eventHeap = new Heap<Event>([], {
509
+ comparator: (a: Event, b: Event) => {
510
+ const priorityA = priorityMap[a.type];
511
+ const priorityB = priorityMap[b.type];
512
+ return priorityB - priorityA; // Higher priority first
513
+ }
514
+ });
515
+
516
+ // Add events in random order
517
+ eventHeap.add({ id: 1, type: 'info', timestamp: 100, message: 'User logged in' });
518
+ eventHeap.add({ id: 2, type: 'critical', timestamp: 101, message: 'Server down' });
519
+ eventHeap.add({ id: 3, type: 'warning', timestamp: 102, message: 'High memory' });
520
+ eventHeap.add({ id: 4, type: 'info', timestamp: 103, message: 'Cache cleared' });
521
+ eventHeap.add({ id: 5, type: 'critical', timestamp: 104, message: 'Database error' });
522
+
523
+ expect(eventHeap.size).toBe(5);
524
+
525
+ // Process events by priority (critical first)
526
+ const processedOrder: Event[] = [];
527
+ while (eventHeap.size > 0) {
528
+ const event = eventHeap.poll();
529
+ if (event) {
530
+ processedOrder.push(event);
461
531
  }
462
- return sorted;
463
532
  }
464
533
 
465
- const array = [5, 3, 8, 4, 1, 2];
466
- expect(heapSort(array)).toEqual([1, 2, 3, 4, 5, 8]);
534
+ // Verify critical events came first
535
+ expect(processedOrder[0].type).toBe('critical');
536
+ expect(processedOrder[1].type).toBe('critical');
537
+ expect(processedOrder[2].type).toBe('warning');
538
+ expect(processedOrder[3].type).toBe('info');
539
+ expect(processedOrder[4].type).toBe('info');
540
+
541
+ // Verify O(log n) operations
542
+ const newHeap = new Heap<number>([5, 3, 7, 1]);
543
+
544
+ // Add - O(log n)
545
+ newHeap.add(2);
546
+ expect(newHeap.size).toBe(5);
547
+
548
+ // Poll - O(log n)
549
+ const removed = newHeap.poll();
550
+ expect(removed).toBe(1);
551
+
552
+ // Peek - O(1)
553
+ const top = newHeap.peek();
554
+ expect(top).toBe(2);
467
555
  });
468
556
 
469
557
  it('@example Use Heap to solve top k problems', () => {
@@ -480,44 +568,6 @@ describe('classic use', () => {
480
568
  expect(topKElements(numbers, 3)).toEqual([15, 10, 5]);
481
569
  });
482
570
 
483
- it('@example Use Heap to merge sorted sequences', () => {
484
- function mergeSortedSequences(sequences: number[][]): number[] {
485
- const heap = new Heap<{ value: number; seqIndex: number; itemIndex: number }>([], {
486
- comparator: (a, b) => a.value - b.value // Min heap
487
- });
488
-
489
- // Initialize heap
490
- sequences.forEach((seq, seqIndex) => {
491
- if (seq.length) {
492
- heap.add({ value: seq[0], seqIndex, itemIndex: 0 });
493
- }
494
- });
495
-
496
- const merged: number[] = [];
497
- while (!heap.isEmpty()) {
498
- const { value, seqIndex, itemIndex } = heap.poll()!;
499
- merged.push(value);
500
-
501
- if (itemIndex + 1 < sequences[seqIndex].length) {
502
- heap.add({
503
- value: sequences[seqIndex][itemIndex + 1],
504
- seqIndex,
505
- itemIndex: itemIndex + 1
506
- });
507
- }
508
- }
509
-
510
- return merged;
511
- }
512
-
513
- const sequences = [
514
- [1, 4, 7],
515
- [2, 5, 8],
516
- [3, 6, 9]
517
- ];
518
- expect(mergeSortedSequences(sequences)).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9]);
519
- });
520
-
521
571
  it('@example Use Heap to dynamically maintain the median', () => {
522
572
  class MedianFinder {
523
573
  private low: MaxHeap<number>; // Max heap, stores the smaller half
@@ -622,4 +672,89 @@ describe('classic use', () => {
622
672
  ]);
623
673
  expect(scheduleTasks(tasks, 2)).toEqual(expectedMap);
624
674
  });
675
+
676
+ it('Use Heap to sort an array', () => {
677
+ function heapSort(arr: number[]): number[] {
678
+ const heap = new Heap<number>(arr, { comparator: (a, b) => a - b });
679
+ const sorted: number[] = [];
680
+ while (!heap.isEmpty()) {
681
+ sorted.push(heap.poll()!); // Poll minimum element
682
+ }
683
+ return sorted;
684
+ }
685
+
686
+ const array = [5, 3, 8, 4, 1, 2];
687
+ expect(heapSort(array)).toEqual([1, 2, 3, 4, 5, 8]);
688
+ });
689
+
690
+ it('Heap getHeight and structure', () => {
691
+ const heap = new Heap<number>([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
692
+
693
+ // Complete binary tree (heap property)
694
+ expect(heap.size).toBe(15);
695
+
696
+ // Verify min heap property (parent <= children)
697
+ const min = heap.peek();
698
+ expect(min).toBe(1);
699
+ });
700
+
701
+ it('Heap poll and priority extraction', () => {
702
+ // Create max heap (higher numbers first)
703
+ const heap = new Heap([3, 7, 1, 9, 5], {
704
+ comparator: (a: number, b: number) => b - a
705
+ });
706
+
707
+ expect(heap.size).toBe(5);
708
+
709
+ // Poll removes and returns the highest priority element
710
+ const first = heap.poll();
711
+ expect(first).toBe(9);
712
+ expect(heap.size).toBe(4);
713
+
714
+ const second = heap.poll();
715
+ expect(second).toBe(7);
716
+ expect(heap.size).toBe(3);
717
+
718
+ // Remaining elements are still in heap order
719
+ const third = heap.peek();
720
+ expect(third).toBe(5);
721
+ });
722
+
723
+ it('Use Heap to merge sorted sequences', () => {
724
+ function mergeSortedSequences(sequences: number[][]): number[] {
725
+ const heap = new Heap<{ value: number; seqIndex: number; itemIndex: number }>([], {
726
+ comparator: (a, b) => a.value - b.value // Min heap
727
+ });
728
+
729
+ // Initialize heap
730
+ sequences.forEach((seq, seqIndex) => {
731
+ if (seq.length) {
732
+ heap.add({ value: seq[0], seqIndex, itemIndex: 0 });
733
+ }
734
+ });
735
+
736
+ const merged: number[] = [];
737
+ while (!heap.isEmpty()) {
738
+ const { value, seqIndex, itemIndex } = heap.poll()!;
739
+ merged.push(value);
740
+
741
+ if (itemIndex + 1 < sequences[seqIndex].length) {
742
+ heap.add({
743
+ value: sequences[seqIndex][itemIndex + 1],
744
+ seqIndex,
745
+ itemIndex: itemIndex + 1
746
+ });
747
+ }
748
+ }
749
+
750
+ return merged;
751
+ }
752
+
753
+ const sequences = [
754
+ [1, 4, 7],
755
+ [2, 5, 8],
756
+ [3, 6, 9]
757
+ ];
758
+ expect(mergeSortedSequences(sequences)).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9]);
759
+ });
625
760
  });
@@ -612,17 +612,51 @@ describe('iterable methods', () => {
612
612
  });
613
613
 
614
614
  describe('classic use', () => {
615
- it('@example text editor operation history', () => {
616
- const actions = [
617
- { type: 'insert', content: 'first line of text' },
618
- { type: 'insert', content: 'second line of text' },
619
- { type: 'delete', content: 'delete the first line' }
620
- ];
621
- const editorHistory = new DoublyLinkedList<{ type: string; content: string }>(actions);
615
+ it('@example basic DoublyLinkedList creation and push operation', () => {
616
+ // Create a simple DoublyLinkedList with initial values
617
+ const list = new DoublyLinkedList([1, 2, 3, 4, 5]);
622
618
 
623
- expect(editorHistory.last?.type).toBe('delete');
624
- expect(editorHistory.pop()?.content).toBe('delete the first line');
625
- expect(editorHistory.last?.type).toBe('insert');
619
+ // Verify the list maintains insertion order
620
+ expect([...list]).toEqual([1, 2, 3, 4, 5]);
621
+
622
+ // Check length
623
+ expect(list.length).toBe(5);
624
+
625
+ // Push a new element to the end
626
+ list.push(6);
627
+ expect(list.length).toBe(6);
628
+ expect([...list]).toEqual([1, 2, 3, 4, 5, 6]);
629
+ });
630
+
631
+ it('@example DoublyLinkedList pop and shift operations', () => {
632
+ const list = new DoublyLinkedList<number>([10, 20, 30, 40, 50]);
633
+
634
+ // Pop removes from the end
635
+ const last = list.pop();
636
+ expect(last).toBe(50);
637
+
638
+ // Shift removes from the beginning
639
+ const first = list.shift();
640
+ expect(first).toBe(10);
641
+
642
+ // Verify remaining elements
643
+ expect([...list]).toEqual([20, 30, 40]);
644
+ expect(list.length).toBe(3);
645
+ });
646
+
647
+ it('@example DoublyLinkedList for...of iteration and map operation', () => {
648
+ const list = new DoublyLinkedList<number>([1, 2, 3, 4, 5]);
649
+
650
+ // Iterate through list
651
+ const doubled = list.map(value => value * 2);
652
+ expect(doubled.length).toBe(5);
653
+
654
+ // Use for...of loop
655
+ const result: number[] = [];
656
+ for (const item of list) {
657
+ result.push(item);
658
+ }
659
+ expect(result).toEqual([1, 2, 3, 4, 5]);
626
660
  });
627
661
 
628
662
  it('@example Browser history', () => {
@@ -637,7 +671,77 @@ describe('classic use', () => {
637
671
  expect(browserHistory.last).toBe('search page');
638
672
  });
639
673
 
640
- it('@example Use DoublyLinkedList to implement music player', () => {
674
+ it('@example DoublyLinkedList for LRU cache implementation', () => {
675
+ interface CacheEntry {
676
+ key: string;
677
+ value: string;
678
+ }
679
+
680
+ // Simulate LRU cache using DoublyLinkedList
681
+ // DoublyLinkedList is perfect because:
682
+ // - O(1) delete from any position
683
+ // - O(1) push to end
684
+ // - Bidirectional traversal for LRU policy
685
+
686
+ const cacheList = new DoublyLinkedList<CacheEntry>();
687
+ const maxSize = 3;
688
+
689
+ // Add cache entries
690
+ cacheList.push({ key: 'user:1', value: 'Alice' });
691
+ cacheList.push({ key: 'user:2', value: 'Bob' });
692
+ cacheList.push({ key: 'user:3', value: 'Charlie' });
693
+
694
+ // Try to add a new entry when cache is full
695
+ if (cacheList.length >= maxSize) {
696
+ // Remove the oldest (first) entry
697
+ const evicted = cacheList.shift();
698
+ expect(evicted?.key).toBe('user:1');
699
+ }
700
+
701
+ // Add new entry
702
+ cacheList.push({ key: 'user:4', value: 'Diana' });
703
+
704
+ // Verify current cache state
705
+ expect(cacheList.length).toBe(3);
706
+ const cachedKeys = [...cacheList].map(entry => entry.key);
707
+ expect(cachedKeys).toEqual(['user:2', 'user:3', 'user:4']);
708
+
709
+ // Access entry (in real LRU, this would move it to end)
710
+ const foundEntry = [...cacheList].find(entry => entry.key === 'user:2');
711
+ expect(foundEntry?.value).toBe('Bob');
712
+ });
713
+
714
+ it('DoublyLinkedList unshift and bidirectional traversal', () => {
715
+ const list = new DoublyLinkedList<number>([20, 30, 40]);
716
+
717
+ // Unshift adds to the beginning
718
+ list.unshift(10);
719
+ expect([...list]).toEqual([10, 20, 30, 40]);
720
+
721
+ // Access elements by index (bidirectional advantage)
722
+ const second = list.at(1);
723
+ expect(second).toBe(20);
724
+
725
+ const last = list.at(list.length - 1);
726
+ expect(last).toBe(40);
727
+
728
+ expect(list.length).toBe(4);
729
+ });
730
+
731
+ it('text editor operation history', () => {
732
+ const actions = [
733
+ { type: 'insert', content: 'first line of text' },
734
+ { type: 'insert', content: 'second line of text' },
735
+ { type: 'delete', content: 'delete the first line' }
736
+ ];
737
+ const editorHistory = new DoublyLinkedList<{ type: string; content: string }>(actions);
738
+
739
+ expect(editorHistory.last?.type).toBe('delete');
740
+ expect(editorHistory.pop()?.content).toBe('delete the first line');
741
+ expect(editorHistory.last?.type).toBe('insert');
742
+ });
743
+
744
+ it('Use DoublyLinkedList to implement music player', () => {
641
745
  // Define the Song interface
642
746
  interface Song {
643
747
  title: string;
@@ -763,7 +867,7 @@ describe('classic use', () => {
763
867
  ]);
764
868
  });
765
869
 
766
- it('@example Use DoublyLinkedList to implement LRU cache', () => {
870
+ it('Use DoublyLinkedList to implement LRU cache', () => {
767
871
  interface CacheEntry<K, V> {
768
872
  key: K;
769
873
  value: V;
@@ -926,7 +1030,7 @@ describe('classic use', () => {
926
1030
  expect(cache.isEmpty).toBe(true);
927
1031
  });
928
1032
 
929
- it('@example finding lyrics by timestamp in Coldplay\'s "Fix You"', () => {
1033
+ it('Finding lyrics by timestamp in Coldplay\'s "Fix You"', () => {
930
1034
  // Create a DoublyLinkedList to store song lyrics with timestamps
931
1035
  const lyricsList = new DoublyLinkedList<{ time: number; text: string }>();
932
1036
 
@@ -967,7 +1071,7 @@ describe('classic use', () => {
967
1071
  expect(lateTimeLyric?.text).toBe('And I will try to fix you');
968
1072
  });
969
1073
 
970
- it('@example cpu process schedules', () => {
1074
+ it('Cpu process schedules', () => {
971
1075
  class Process {
972
1076
  constructor(
973
1077
  public id: number,
@@ -646,6 +646,127 @@ describe('iterable methods', () => {
646
646
  });
647
647
 
648
648
  describe('classic uses', () => {
649
+ it('@example basic SinglyLinkedList creation and push operation', () => {
650
+ // Create a simple SinglyLinkedList with initial values
651
+ const list = new SinglyLinkedList([1, 2, 3, 4, 5]);
652
+
653
+ // Verify the list maintains insertion order
654
+ expect([...list]).toEqual([1, 2, 3, 4, 5]);
655
+
656
+ // Check length
657
+ expect(list.length).toBe(5);
658
+
659
+ // Push a new element to the end
660
+ list.push(6);
661
+ expect(list.length).toBe(6);
662
+ expect([...list]).toEqual([1, 2, 3, 4, 5, 6]);
663
+ });
664
+
665
+ it('@example SinglyLinkedList pop and shift operations', () => {
666
+ const list = new SinglyLinkedList<number>([10, 20, 30, 40, 50]);
667
+
668
+ // Pop removes from the end
669
+ const last = list.pop();
670
+ expect(last).toBe(50);
671
+
672
+ // Shift removes from the beginning
673
+ const first = list.shift();
674
+ expect(first).toBe(10);
675
+
676
+ // Verify remaining elements
677
+ expect([...list]).toEqual([20, 30, 40]);
678
+ expect(list.length).toBe(3);
679
+ });
680
+
681
+ it('@example SinglyLinkedList unshift and forward traversal', () => {
682
+ const list = new SinglyLinkedList<number>([20, 30, 40]);
683
+
684
+ // Unshift adds to the beginning
685
+ list.unshift(10);
686
+ expect([...list]).toEqual([10, 20, 30, 40]);
687
+
688
+ // Access elements (forward traversal only for singly linked)
689
+ const second = list.at(1);
690
+ expect(second).toBe(20);
691
+
692
+ // SinglyLinkedList allows forward iteration only
693
+ const elements: number[] = [];
694
+ for (const item of list) {
695
+ elements.push(item);
696
+ }
697
+ expect(elements).toEqual([10, 20, 30, 40]);
698
+
699
+ expect(list.length).toBe(4);
700
+ });
701
+
702
+ it('@example SinglyLinkedList filter and map operations', () => {
703
+ const list = new SinglyLinkedList<number>([1, 2, 3, 4, 5]);
704
+
705
+ // Filter even numbers
706
+ const filtered = list.filter(value => value % 2 === 0);
707
+ expect(filtered.length).toBe(2);
708
+
709
+ // Map to double values
710
+ const doubled = list.map(value => value * 2);
711
+ expect(doubled.length).toBe(5);
712
+
713
+ // Use reduce to sum
714
+ const sum = list.reduce((acc, value) => acc + value, 0);
715
+ expect(sum).toBe(15);
716
+ });
717
+
718
+ it('@example SinglyLinkedList for sequentially processed data stream', () => {
719
+ interface LogEntry {
720
+ timestamp: number;
721
+ level: 'INFO' | 'WARN' | 'ERROR';
722
+ message: string;
723
+ }
724
+
725
+ // SinglyLinkedList is ideal for sequential processing where you only need forward iteration
726
+ // O(1) insertion/deletion at head, O(n) for tail operations
727
+ const logStream = new SinglyLinkedList<LogEntry>();
728
+
729
+ // Simulate incoming log entries
730
+ const entries: LogEntry[] = [
731
+ { timestamp: 1000, level: 'INFO', message: 'Server started' },
732
+ { timestamp: 1100, level: 'WARN', message: 'Memory usage high' },
733
+ { timestamp: 1200, level: 'ERROR', message: 'Connection failed' },
734
+ { timestamp: 1300, level: 'INFO', message: 'Connection restored' }
735
+ ];
736
+
737
+ // Add entries to the stream
738
+ for (const entry of entries) {
739
+ logStream.push(entry);
740
+ }
741
+
742
+ expect(logStream.length).toBe(4);
743
+
744
+ // Process logs sequentially (only forward iteration needed)
745
+ const processedLogs: string[] = [];
746
+ for (const log of logStream) {
747
+ processedLogs.push(`[${log.level}] ${log.message}`);
748
+ }
749
+
750
+ expect(processedLogs).toEqual([
751
+ '[INFO] Server started',
752
+ '[WARN] Memory usage high',
753
+ '[ERROR] Connection failed',
754
+ '[INFO] Connection restored'
755
+ ]);
756
+
757
+ // Get first log (O(1) - direct head access)
758
+ const firstLog = logStream.at(0);
759
+ expect(firstLog?.message).toBe('Server started');
760
+
761
+ // Remove oldest log (O(1) operation at head)
762
+ const removed = logStream.shift();
763
+ expect(removed?.message).toBe('Server started');
764
+ expect(logStream.length).toBe(3);
765
+
766
+ // Remaining logs still maintain order for sequential processing
767
+ expect(logStream.length).toBe(3);
768
+ });
769
+
649
770
  it('@example implementation of a basic text editor', () => {
650
771
  class TextEditor {
651
772
  private content: SinglyLinkedList<string>;