min-heap-typed 2.0.0 → 2.0.1

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.
@@ -250,7 +250,7 @@ class AbstractGraph extends base_1.IterableEntryBase {
250
250
  isWeight = false;
251
251
  if (isWeight) {
252
252
  const allPaths = this.getAllPathsBetween(v1, v2);
253
- let min = Infinity;
253
+ let min = Number.MAX_SAFE_INTEGER;
254
254
  for (const path of allPaths) {
255
255
  min = Math.min(this.getPathSumWeight(path), min);
256
256
  }
@@ -315,7 +315,7 @@ class AbstractGraph extends base_1.IterableEntryBase {
315
315
  if (isWeight) {
316
316
  if (isDFS) {
317
317
  const allPaths = this.getAllPathsBetween(v1, v2, 10000);
318
- let min = Infinity;
318
+ let min = Number.MAX_SAFE_INTEGER;
319
319
  let minIndex = -1;
320
320
  let index = 0;
321
321
  for (const path of allPaths) {
@@ -379,7 +379,7 @@ class AbstractGraph extends base_1.IterableEntryBase {
379
379
  * @returns The function `dijkstraWithoutHeap` returns an object of type `DijkstraResult<VO>`.
380
380
  */
381
381
  dijkstraWithoutHeap(src, dest = undefined, getMinDist = false, genPaths = false) {
382
- let minDist = Infinity;
382
+ let minDist = Number.MAX_SAFE_INTEGER;
383
383
  let minDest = undefined;
384
384
  let minPath = [];
385
385
  const paths = [];
@@ -395,12 +395,12 @@ class AbstractGraph extends base_1.IterableEntryBase {
395
395
  for (const vertex of vertexMap) {
396
396
  const vertexOrKey = vertex[1];
397
397
  if (vertexOrKey instanceof AbstractVertex)
398
- distMap.set(vertexOrKey, Infinity);
398
+ distMap.set(vertexOrKey, Number.MAX_SAFE_INTEGER);
399
399
  }
400
400
  distMap.set(srcVertex, 0);
401
401
  preMap.set(srcVertex, undefined);
402
402
  const getMinOfNoSeen = () => {
403
- let min = Infinity;
403
+ let min = Number.MAX_SAFE_INTEGER;
404
404
  let minV = undefined;
405
405
  for (const [key, value] of distMap) {
406
406
  if (!seen.has(key)) {
@@ -435,7 +435,7 @@ class AbstractGraph extends base_1.IterableEntryBase {
435
435
  seen.add(cur);
436
436
  if (destVertex && destVertex === cur) {
437
437
  if (getMinDist) {
438
- minDist = distMap.get(destVertex) || Infinity;
438
+ minDist = distMap.get(destVertex) || Number.MAX_SAFE_INTEGER;
439
439
  }
440
440
  if (genPaths) {
441
441
  getPaths(destVertex);
@@ -497,7 +497,7 @@ class AbstractGraph extends base_1.IterableEntryBase {
497
497
  */
498
498
  dijkstra(src, dest = undefined, getMinDist = false, genPaths = false) {
499
499
  var _a;
500
- let minDist = Infinity;
500
+ let minDist = Number.MAX_SAFE_INTEGER;
501
501
  let minDest = undefined;
502
502
  let minPath = [];
503
503
  const paths = [];
@@ -512,7 +512,7 @@ class AbstractGraph extends base_1.IterableEntryBase {
512
512
  for (const vertex of vertexMap) {
513
513
  const vertexOrKey = vertex[1];
514
514
  if (vertexOrKey instanceof AbstractVertex)
515
- distMap.set(vertexOrKey, Infinity);
515
+ distMap.set(vertexOrKey, Number.MAX_SAFE_INTEGER);
516
516
  }
517
517
  const heap = new heap_1.Heap([], { comparator: (a, b) => a.key - b.key });
518
518
  heap.add({ key: 0, value: srcVertex });
@@ -549,7 +549,7 @@ class AbstractGraph extends base_1.IterableEntryBase {
549
549
  seen.add(cur);
550
550
  if (destVertex && destVertex === cur) {
551
551
  if (getMinDist) {
552
- minDist = distMap.get(destVertex) || Infinity;
552
+ minDist = distMap.get(destVertex) || Number.MAX_SAFE_INTEGER;
553
553
  }
554
554
  if (genPaths) {
555
555
  getPaths(destVertex);
@@ -618,7 +618,7 @@ class AbstractGraph extends base_1.IterableEntryBase {
618
618
  const paths = [];
619
619
  const distMap = new Map();
620
620
  const preMap = new Map(); // predecessor
621
- let min = Infinity;
621
+ let min = Number.MAX_SAFE_INTEGER;
622
622
  let minPath = [];
623
623
  // TODO
624
624
  let hasNegativeCycle;
@@ -631,7 +631,7 @@ class AbstractGraph extends base_1.IterableEntryBase {
631
631
  const edgeMap = this.edgeSet();
632
632
  const numOfEdges = edgeMap.length;
633
633
  this._vertexMap.forEach(vertex => {
634
- distMap.set(vertex, Infinity);
634
+ distMap.set(vertex, Number.MAX_SAFE_INTEGER);
635
635
  });
636
636
  distMap.set(srcVertex, 0);
637
637
  for (let i = 1; i < numOfVertices; ++i) {
@@ -643,7 +643,7 @@ class AbstractGraph extends base_1.IterableEntryBase {
643
643
  const sWeight = distMap.get(s);
644
644
  const dWeight = distMap.get(d);
645
645
  if (sWeight !== undefined && dWeight !== undefined) {
646
- if (distMap.get(s) !== Infinity && sWeight + weight < dWeight) {
646
+ if (distMap.get(s) !== Number.MAX_SAFE_INTEGER && sWeight + weight < dWeight) {
647
647
  distMap.set(d, sWeight + weight);
648
648
  if (genPath)
649
649
  preMap.set(d, s);
@@ -688,7 +688,7 @@ class AbstractGraph extends base_1.IterableEntryBase {
688
688
  const weight = edgeMap[j].weight;
689
689
  const sWeight = distMap.get(s);
690
690
  if (sWeight) {
691
- if (sWeight !== Infinity && sWeight + weight < sWeight)
691
+ if (sWeight !== Number.MAX_SAFE_INTEGER && sWeight + weight < sWeight)
692
692
  hasNegativeCycle = true;
693
693
  }
694
694
  }
@@ -738,7 +738,7 @@ class AbstractGraph extends base_1.IterableEntryBase {
738
738
  }
739
739
  for (let i = 0; i < n; i++) {
740
740
  for (let j = 0; j < n; j++) {
741
- costs[i][j] = ((_a = this.getEdge(idAndVertices[i][1], idAndVertices[j][1])) === null || _a === void 0 ? void 0 : _a.weight) || Infinity;
741
+ costs[i][j] = ((_a = this.getEdge(idAndVertices[i][1], idAndVertices[j][1])) === null || _a === void 0 ? void 0 : _a.weight) || Number.MAX_SAFE_INTEGER;
742
742
  }
743
743
  }
744
744
  for (let k = 0; k < n; k++) {
@@ -13,6 +13,52 @@ import { IterableEntryBase } from '../base';
13
13
  * 3. Unique Keys: Keys are unique.
14
14
  * If you try to insert another entry with the same key, the new one will replace the old entry.
15
15
  * 4. Unordered Collection: HashMap does not guarantee the order of entries, and the order may change over time.
16
+ * @example
17
+ * // should maintain insertion order
18
+ * const linkedHashMap = new LinkedHashMap<number, string>();
19
+ * linkedHashMap.set(1, 'A');
20
+ * linkedHashMap.set(2, 'B');
21
+ * linkedHashMap.set(3, 'C');
22
+ *
23
+ * const result = Array.from(linkedHashMap);
24
+ * console.log(result); // [
25
+ * // [1, 'A'],
26
+ * // [2, 'B'],
27
+ * // [3, 'C']
28
+ * // ]
29
+ * @example
30
+ * // fast lookup of values by key
31
+ * const hashMap = new HashMap<number, string>();
32
+ * hashMap.set(1, 'A');
33
+ * hashMap.set(2, 'B');
34
+ * hashMap.set(3, 'C');
35
+ *
36
+ * console.log(hashMap.get(1)); // 'A'
37
+ * console.log(hashMap.get(2)); // 'B'
38
+ * console.log(hashMap.get(3)); // 'C'
39
+ * console.log(hashMap.get(99)); // undefined
40
+ * @example
41
+ * // remove duplicates when adding multiple entries
42
+ * const hashMap = new HashMap<number, string>();
43
+ * hashMap.set(1, 'A');
44
+ * hashMap.set(2, 'B');
45
+ * hashMap.set(1, 'C'); // Update value for key 1
46
+ *
47
+ * console.log(hashMap.size); // 2
48
+ * console.log(hashMap.get(1)); // 'C'
49
+ * console.log(hashMap.get(2)); // 'B'
50
+ * @example
51
+ * // count occurrences of keys
52
+ * const data = [1, 2, 1, 3, 2, 1];
53
+ *
54
+ * const countMap = new HashMap<number, number>();
55
+ * for (const key of data) {
56
+ * countMap.set(key, (countMap.get(key) || 0) + 1);
57
+ * }
58
+ *
59
+ * console.log(countMap.get(1)); // 3
60
+ * console.log(countMap.get(2)); // 2
61
+ * console.log(countMap.get(3)); // 1
16
62
  */
17
63
  export declare class HashMap<K = any, V = any, R = [K, V]> extends IterableEntryBase<K, V> {
18
64
  /**
@@ -9,6 +9,52 @@ const utils_1 = require("../../utils");
9
9
  * 3. Unique Keys: Keys are unique.
10
10
  * If you try to insert another entry with the same key, the new one will replace the old entry.
11
11
  * 4. Unordered Collection: HashMap does not guarantee the order of entries, and the order may change over time.
12
+ * @example
13
+ * // should maintain insertion order
14
+ * const linkedHashMap = new LinkedHashMap<number, string>();
15
+ * linkedHashMap.set(1, 'A');
16
+ * linkedHashMap.set(2, 'B');
17
+ * linkedHashMap.set(3, 'C');
18
+ *
19
+ * const result = Array.from(linkedHashMap);
20
+ * console.log(result); // [
21
+ * // [1, 'A'],
22
+ * // [2, 'B'],
23
+ * // [3, 'C']
24
+ * // ]
25
+ * @example
26
+ * // fast lookup of values by key
27
+ * const hashMap = new HashMap<number, string>();
28
+ * hashMap.set(1, 'A');
29
+ * hashMap.set(2, 'B');
30
+ * hashMap.set(3, 'C');
31
+ *
32
+ * console.log(hashMap.get(1)); // 'A'
33
+ * console.log(hashMap.get(2)); // 'B'
34
+ * console.log(hashMap.get(3)); // 'C'
35
+ * console.log(hashMap.get(99)); // undefined
36
+ * @example
37
+ * // remove duplicates when adding multiple entries
38
+ * const hashMap = new HashMap<number, string>();
39
+ * hashMap.set(1, 'A');
40
+ * hashMap.set(2, 'B');
41
+ * hashMap.set(1, 'C'); // Update value for key 1
42
+ *
43
+ * console.log(hashMap.size); // 2
44
+ * console.log(hashMap.get(1)); // 'C'
45
+ * console.log(hashMap.get(2)); // 'B'
46
+ * @example
47
+ * // count occurrences of keys
48
+ * const data = [1, 2, 1, 3, 2, 1];
49
+ *
50
+ * const countMap = new HashMap<number, number>();
51
+ * for (const key of data) {
52
+ * countMap.set(key, (countMap.get(key) || 0) + 1);
53
+ * }
54
+ *
55
+ * console.log(countMap.get(1)); // 3
56
+ * console.log(countMap.get(2)); // 2
57
+ * console.log(countMap.get(3)); // 1
12
58
  */
13
59
  class HashMap extends base_1.IterableEntryBase {
14
60
  /**
@@ -25,6 +25,72 @@ export declare class SinglyLinkedListNode<E = any> extends LinkedListNode<E> {
25
25
  * 4. High Efficiency in Insertion and Deletion: Adding or removing elements in a linked list does not require moving other elements, making these operations more efficient than in arrays.
26
26
  * Caution: Although our linked list classes provide methods such as at, setAt, addAt, and indexOf that are based on array indices, their time complexity, like that of the native Array.lastIndexOf, is 𝑂(𝑛). If you need to use these methods frequently, you might want to consider other data structures, such as Deque or Queue (designed for random access). Similarly, since the native Array.shift method has a time complexity of 𝑂(𝑛), using an array to simulate a queue can be inefficient. In such cases, you should use Queue or Deque, as these data structures leverage deferred array rearrangement, effectively reducing the average time complexity to 𝑂(1).
27
27
  *
28
+ * @example
29
+ * // implementation of a basic text editor
30
+ * class TextEditor {
31
+ * private content: SinglyLinkedList<string>;
32
+ * private cursorIndex: number;
33
+ * private undoStack: Stack<{ operation: string; data?: any }>;
34
+ *
35
+ * constructor() {
36
+ * this.content = new SinglyLinkedList<string>();
37
+ * this.cursorIndex = 0; // Cursor starts at the beginning
38
+ * this.undoStack = new Stack<{ operation: string; data?: any }>(); // Stack to keep track of operations for undo
39
+ * }
40
+ *
41
+ * insert(char: string) {
42
+ * this.content.addAt(this.cursorIndex, char);
43
+ * this.cursorIndex++;
44
+ * this.undoStack.push({ operation: 'insert', data: { index: this.cursorIndex - 1 } });
45
+ * }
46
+ *
47
+ * delete() {
48
+ * if (this.cursorIndex === 0) return; // Nothing to delete
49
+ * const deleted = this.content.deleteAt(this.cursorIndex - 1);
50
+ * this.cursorIndex--;
51
+ * this.undoStack.push({ operation: 'delete', data: { index: this.cursorIndex, char: deleted } });
52
+ * }
53
+ *
54
+ * moveCursor(index: number) {
55
+ * this.cursorIndex = Math.max(0, Math.min(index, this.content.length));
56
+ * }
57
+ *
58
+ * undo() {
59
+ * if (this.undoStack.size === 0) return; // No operations to undo
60
+ * const lastAction = this.undoStack.pop();
61
+ *
62
+ * if (lastAction!.operation === 'insert') {
63
+ * this.content.deleteAt(lastAction!.data.index);
64
+ * this.cursorIndex = lastAction!.data.index;
65
+ * } else if (lastAction!.operation === 'delete') {
66
+ * this.content.addAt(lastAction!.data.index, lastAction!.data.char);
67
+ * this.cursorIndex = lastAction!.data.index + 1;
68
+ * }
69
+ * }
70
+ *
71
+ * getText(): string {
72
+ * return [...this.content].join('');
73
+ * }
74
+ * }
75
+ *
76
+ * // Example Usage
77
+ * const editor = new TextEditor();
78
+ * editor.insert('H');
79
+ * editor.insert('e');
80
+ * editor.insert('l');
81
+ * editor.insert('l');
82
+ * editor.insert('o');
83
+ * console.log(editor.getText()); // 'Hello' // Output: "Hello"
84
+ *
85
+ * editor.delete();
86
+ * console.log(editor.getText()); // 'Hell' // Output: "Hell"
87
+ *
88
+ * editor.undo();
89
+ * console.log(editor.getText()); // 'Hello' // Output: "Hello"
90
+ *
91
+ * editor.moveCursor(1);
92
+ * editor.insert('a');
93
+ * console.log(editor.getText()); // 'Haello'
28
94
  */
29
95
  export declare class SinglyLinkedList<E = any, R = any> extends LinearLinkedBase<E, R, SinglyLinkedListNode<E>> {
30
96
  constructor(elements?: Iterable<E> | Iterable<R> | Iterable<SinglyLinkedListNode<E>>, options?: SinglyLinkedListOptions<E, R>);
@@ -28,6 +28,72 @@ exports.SinglyLinkedListNode = SinglyLinkedListNode;
28
28
  * 4. High Efficiency in Insertion and Deletion: Adding or removing elements in a linked list does not require moving other elements, making these operations more efficient than in arrays.
29
29
  * Caution: Although our linked list classes provide methods such as at, setAt, addAt, and indexOf that are based on array indices, their time complexity, like that of the native Array.lastIndexOf, is 𝑂(𝑛). If you need to use these methods frequently, you might want to consider other data structures, such as Deque or Queue (designed for random access). Similarly, since the native Array.shift method has a time complexity of 𝑂(𝑛), using an array to simulate a queue can be inefficient. In such cases, you should use Queue or Deque, as these data structures leverage deferred array rearrangement, effectively reducing the average time complexity to 𝑂(1).
30
30
  *
31
+ * @example
32
+ * // implementation of a basic text editor
33
+ * class TextEditor {
34
+ * private content: SinglyLinkedList<string>;
35
+ * private cursorIndex: number;
36
+ * private undoStack: Stack<{ operation: string; data?: any }>;
37
+ *
38
+ * constructor() {
39
+ * this.content = new SinglyLinkedList<string>();
40
+ * this.cursorIndex = 0; // Cursor starts at the beginning
41
+ * this.undoStack = new Stack<{ operation: string; data?: any }>(); // Stack to keep track of operations for undo
42
+ * }
43
+ *
44
+ * insert(char: string) {
45
+ * this.content.addAt(this.cursorIndex, char);
46
+ * this.cursorIndex++;
47
+ * this.undoStack.push({ operation: 'insert', data: { index: this.cursorIndex - 1 } });
48
+ * }
49
+ *
50
+ * delete() {
51
+ * if (this.cursorIndex === 0) return; // Nothing to delete
52
+ * const deleted = this.content.deleteAt(this.cursorIndex - 1);
53
+ * this.cursorIndex--;
54
+ * this.undoStack.push({ operation: 'delete', data: { index: this.cursorIndex, char: deleted } });
55
+ * }
56
+ *
57
+ * moveCursor(index: number) {
58
+ * this.cursorIndex = Math.max(0, Math.min(index, this.content.length));
59
+ * }
60
+ *
61
+ * undo() {
62
+ * if (this.undoStack.size === 0) return; // No operations to undo
63
+ * const lastAction = this.undoStack.pop();
64
+ *
65
+ * if (lastAction!.operation === 'insert') {
66
+ * this.content.deleteAt(lastAction!.data.index);
67
+ * this.cursorIndex = lastAction!.data.index;
68
+ * } else if (lastAction!.operation === 'delete') {
69
+ * this.content.addAt(lastAction!.data.index, lastAction!.data.char);
70
+ * this.cursorIndex = lastAction!.data.index + 1;
71
+ * }
72
+ * }
73
+ *
74
+ * getText(): string {
75
+ * return [...this.content].join('');
76
+ * }
77
+ * }
78
+ *
79
+ * // Example Usage
80
+ * const editor = new TextEditor();
81
+ * editor.insert('H');
82
+ * editor.insert('e');
83
+ * editor.insert('l');
84
+ * editor.insert('l');
85
+ * editor.insert('o');
86
+ * console.log(editor.getText()); // 'Hello' // Output: "Hello"
87
+ *
88
+ * editor.delete();
89
+ * console.log(editor.getText()); // 'Hell' // Output: "Hell"
90
+ *
91
+ * editor.undo();
92
+ * console.log(editor.getText()); // 'Hello' // Output: "Hello"
93
+ *
94
+ * editor.moveCursor(1);
95
+ * editor.insert('a');
96
+ * console.log(editor.getText()); // 'Haello'
31
97
  */
32
98
  class SinglyLinkedList extends linear_base_1.LinearLinkedBase {
33
99
  constructor(elements = [], options) {
@@ -14,6 +14,53 @@ import { LinearBase } from '../base/linear-base';
14
14
  * 5. Data Buffering: Acting as a buffer for data packets in network communication.
15
15
  * 6. Breadth-First Search (BFS): In traversal algorithms for graphs and trees, queues store elements that are to be visited.
16
16
  * 7. Real-time Queuing: Like queuing systems in banks or supermarkets.
17
+ * @example
18
+ * // Sliding Window using Queue
19
+ * const nums = [2, 3, 4, 1, 5];
20
+ * const k = 2;
21
+ * const queue = new Queue<number>();
22
+ *
23
+ * let maxSum = 0;
24
+ * let currentSum = 0;
25
+ *
26
+ * nums.forEach((num, i) => {
27
+ * queue.push(num);
28
+ * currentSum += num;
29
+ *
30
+ * if (queue.length > k) {
31
+ * currentSum -= queue.shift()!;
32
+ * }
33
+ *
34
+ * if (queue.length === k) {
35
+ * maxSum = Math.max(maxSum, currentSum);
36
+ * }
37
+ * });
38
+ *
39
+ * console.log(maxSum); // 7
40
+ * @example
41
+ * // Breadth-First Search (BFS) using Queue
42
+ * const graph: { [key in number]: number[] } = {
43
+ * 1: [2, 3],
44
+ * 2: [4, 5],
45
+ * 3: [],
46
+ * 4: [],
47
+ * 5: []
48
+ * };
49
+ *
50
+ * const queue = new Queue<number>();
51
+ * const visited: number[] = [];
52
+ *
53
+ * queue.push(1);
54
+ *
55
+ * while (!queue.isEmpty()) {
56
+ * const node = queue.shift()!;
57
+ * if (!visited.includes(node)) {
58
+ * visited.push(node);
59
+ * graph[node].forEach(neighbor => queue.push(neighbor));
60
+ * }
61
+ * }
62
+ *
63
+ * console.log(visited); // [1, 2, 3, 4, 5]
17
64
  */
18
65
  export declare class Queue<E = any, R = any> extends LinearBase<E, R> {
19
66
  constructor(elements?: Iterable<E> | Iterable<R>, options?: QueueOptions<E, R>);
@@ -11,6 +11,53 @@ const linear_base_1 = require("../base/linear-base");
11
11
  * 5. Data Buffering: Acting as a buffer for data packets in network communication.
12
12
  * 6. Breadth-First Search (BFS): In traversal algorithms for graphs and trees, queues store elements that are to be visited.
13
13
  * 7. Real-time Queuing: Like queuing systems in banks or supermarkets.
14
+ * @example
15
+ * // Sliding Window using Queue
16
+ * const nums = [2, 3, 4, 1, 5];
17
+ * const k = 2;
18
+ * const queue = new Queue<number>();
19
+ *
20
+ * let maxSum = 0;
21
+ * let currentSum = 0;
22
+ *
23
+ * nums.forEach((num, i) => {
24
+ * queue.push(num);
25
+ * currentSum += num;
26
+ *
27
+ * if (queue.length > k) {
28
+ * currentSum -= queue.shift()!;
29
+ * }
30
+ *
31
+ * if (queue.length === k) {
32
+ * maxSum = Math.max(maxSum, currentSum);
33
+ * }
34
+ * });
35
+ *
36
+ * console.log(maxSum); // 7
37
+ * @example
38
+ * // Breadth-First Search (BFS) using Queue
39
+ * const graph: { [key in number]: number[] } = {
40
+ * 1: [2, 3],
41
+ * 2: [4, 5],
42
+ * 3: [],
43
+ * 4: [],
44
+ * 5: []
45
+ * };
46
+ *
47
+ * const queue = new Queue<number>();
48
+ * const visited: number[] = [];
49
+ *
50
+ * queue.push(1);
51
+ *
52
+ * while (!queue.isEmpty()) {
53
+ * const node = queue.shift()!;
54
+ * if (!visited.includes(node)) {
55
+ * visited.push(node);
56
+ * graph[node].forEach(neighbor => queue.push(neighbor));
57
+ * }
58
+ * }
59
+ *
60
+ * console.log(visited); // [1, 2, 3, 4, 5]
14
61
  */
15
62
  class Queue extends linear_base_1.LinearBase {
16
63
  constructor(elements = [], options) {
@@ -14,6 +14,127 @@ import { IterableElementBase } from '../base';
14
14
  * 4. Function Calls: In most modern programming languages, the records of function calls are managed through a stack. When a function is called, its record (including parameters, local variables, and return address) is 'pushed' into the stack. When the function returns, its record is 'popped' from the stack.
15
15
  * 5. Expression Evaluation: Used for the evaluation of arithmetic or logical expressions, especially when dealing with parenthesis matching and operator precedence.
16
16
  * 6. Backtracking Algorithms: In problems where multiple branches need to be explored but only one branch can be explored at a time, stacks can be used to save the state at each branching point.
17
+ * @example
18
+ * // Balanced Parentheses or Brackets
19
+ * type ValidCharacters = ')' | '(' | ']' | '[' | '}' | '{';
20
+ *
21
+ * const stack = new Stack<string>();
22
+ * const input: ValidCharacters[] = '[({})]'.split('') as ValidCharacters[];
23
+ * const matches: { [key in ValidCharacters]?: ValidCharacters } = { ')': '(', ']': '[', '}': '{' };
24
+ * for (const char of input) {
25
+ * if ('([{'.includes(char)) {
26
+ * stack.push(char);
27
+ * } else if (')]}'.includes(char)) {
28
+ * if (stack.pop() !== matches[char]) {
29
+ * fail('Parentheses are not balanced');
30
+ * }
31
+ * }
32
+ * }
33
+ * console.log(stack.isEmpty()); // true
34
+ * @example
35
+ * // Expression Evaluation and Conversion
36
+ * const stack = new Stack<number>();
37
+ * const expression = [5, 3, '+']; // Equivalent to 5 + 3
38
+ * expression.forEach(token => {
39
+ * if (typeof token === 'number') {
40
+ * stack.push(token);
41
+ * } else {
42
+ * const b = stack.pop()!;
43
+ * const a = stack.pop()!;
44
+ * stack.push(token === '+' ? a + b : 0); // Only handling '+' here
45
+ * }
46
+ * });
47
+ * console.log(stack.pop()); // 8
48
+ * @example
49
+ * // Depth-First Search (DFS)
50
+ * const stack = new Stack<number>();
51
+ * const graph: { [key in number]: number[] } = { 1: [2, 3], 2: [4], 3: [5], 4: [], 5: [] };
52
+ * const visited: number[] = [];
53
+ * stack.push(1);
54
+ * while (!stack.isEmpty()) {
55
+ * const node = stack.pop()!;
56
+ * if (!visited.includes(node)) {
57
+ * visited.push(node);
58
+ * graph[node].forEach(neighbor => stack.push(neighbor));
59
+ * }
60
+ * }
61
+ * console.log(visited); // [1, 3, 5, 2, 4]
62
+ * @example
63
+ * // Backtracking Algorithms
64
+ * const stack = new Stack<[number, number]>();
65
+ * const maze = [
66
+ * ['S', ' ', 'X'],
67
+ * ['X', ' ', 'X'],
68
+ * [' ', ' ', 'E']
69
+ * ];
70
+ * const start: [number, number] = [0, 0];
71
+ * const end = [2, 2];
72
+ * const directions = [
73
+ * [0, 1], // To the right
74
+ * [1, 0], // down
75
+ * [0, -1], // left
76
+ * [-1, 0] // up
77
+ * ];
78
+ *
79
+ * const visited = new Set<string>(); // Used to record visited nodes
80
+ * stack.push(start);
81
+ * const path: number[][] = [];
82
+ *
83
+ * while (!stack.isEmpty()) {
84
+ * const [x, y] = stack.pop()!;
85
+ * if (visited.has(`${x},${y}`)) continue; // Skip already visited nodes
86
+ * visited.add(`${x},${y}`);
87
+ *
88
+ * path.push([x, y]);
89
+ *
90
+ * if (x === end[0] && y === end[1]) {
91
+ * break; // Find the end point and exit
92
+ * }
93
+ *
94
+ * for (const [dx, dy] of directions) {
95
+ * const nx = x + dx;
96
+ * const ny = y + dy;
97
+ * if (
98
+ * maze[nx]?.[ny] === ' ' || // feasible path
99
+ * maze[nx]?.[ny] === 'E' // destination
100
+ * ) {
101
+ * stack.push([nx, ny]);
102
+ * }
103
+ * }
104
+ * }
105
+ *
106
+ * expect(path).toContainEqual(end);
107
+ * @example
108
+ * // Function Call Stack
109
+ * const functionStack = new Stack<string>();
110
+ * functionStack.push('main');
111
+ * functionStack.push('foo');
112
+ * functionStack.push('bar');
113
+ * console.log(functionStack.pop()); // 'bar'
114
+ * console.log(functionStack.pop()); // 'foo'
115
+ * console.log(functionStack.pop()); // 'main'
116
+ * @example
117
+ * // Simplify File Paths
118
+ * const stack = new Stack<string>();
119
+ * const path = '/a/./b/../../c';
120
+ * path.split('/').forEach(segment => {
121
+ * if (segment === '..') stack.pop();
122
+ * else if (segment && segment !== '.') stack.push(segment);
123
+ * });
124
+ * console.log(stack.elements.join('/')); // 'c'
125
+ * @example
126
+ * // Stock Span Problem
127
+ * const stack = new Stack<number>();
128
+ * const prices = [100, 80, 60, 70, 60, 75, 85];
129
+ * const spans: number[] = [];
130
+ * prices.forEach((price, i) => {
131
+ * while (!stack.isEmpty() && prices[stack.peek()!] <= price) {
132
+ * stack.pop();
133
+ * }
134
+ * spans.push(stack.isEmpty() ? i + 1 : i - stack.peek()!);
135
+ * stack.push(i);
136
+ * });
137
+ * console.log(spans); // [1, 1, 1, 2, 1, 4, 6]
17
138
  */
18
139
  export declare class Stack<E = any, R = any> extends IterableElementBase<E, R> {
19
140
  constructor(elements?: Iterable<E> | Iterable<R>, options?: StackOptions<E, R>);
@@ -9,6 +9,127 @@ const base_1 = require("../base");
9
9
  * 4. Function Calls: In most modern programming languages, the records of function calls are managed through a stack. When a function is called, its record (including parameters, local variables, and return address) is 'pushed' into the stack. When the function returns, its record is 'popped' from the stack.
10
10
  * 5. Expression Evaluation: Used for the evaluation of arithmetic or logical expressions, especially when dealing with parenthesis matching and operator precedence.
11
11
  * 6. Backtracking Algorithms: In problems where multiple branches need to be explored but only one branch can be explored at a time, stacks can be used to save the state at each branching point.
12
+ * @example
13
+ * // Balanced Parentheses or Brackets
14
+ * type ValidCharacters = ')' | '(' | ']' | '[' | '}' | '{';
15
+ *
16
+ * const stack = new Stack<string>();
17
+ * const input: ValidCharacters[] = '[({})]'.split('') as ValidCharacters[];
18
+ * const matches: { [key in ValidCharacters]?: ValidCharacters } = { ')': '(', ']': '[', '}': '{' };
19
+ * for (const char of input) {
20
+ * if ('([{'.includes(char)) {
21
+ * stack.push(char);
22
+ * } else if (')]}'.includes(char)) {
23
+ * if (stack.pop() !== matches[char]) {
24
+ * fail('Parentheses are not balanced');
25
+ * }
26
+ * }
27
+ * }
28
+ * console.log(stack.isEmpty()); // true
29
+ * @example
30
+ * // Expression Evaluation and Conversion
31
+ * const stack = new Stack<number>();
32
+ * const expression = [5, 3, '+']; // Equivalent to 5 + 3
33
+ * expression.forEach(token => {
34
+ * if (typeof token === 'number') {
35
+ * stack.push(token);
36
+ * } else {
37
+ * const b = stack.pop()!;
38
+ * const a = stack.pop()!;
39
+ * stack.push(token === '+' ? a + b : 0); // Only handling '+' here
40
+ * }
41
+ * });
42
+ * console.log(stack.pop()); // 8
43
+ * @example
44
+ * // Depth-First Search (DFS)
45
+ * const stack = new Stack<number>();
46
+ * const graph: { [key in number]: number[] } = { 1: [2, 3], 2: [4], 3: [5], 4: [], 5: [] };
47
+ * const visited: number[] = [];
48
+ * stack.push(1);
49
+ * while (!stack.isEmpty()) {
50
+ * const node = stack.pop()!;
51
+ * if (!visited.includes(node)) {
52
+ * visited.push(node);
53
+ * graph[node].forEach(neighbor => stack.push(neighbor));
54
+ * }
55
+ * }
56
+ * console.log(visited); // [1, 3, 5, 2, 4]
57
+ * @example
58
+ * // Backtracking Algorithms
59
+ * const stack = new Stack<[number, number]>();
60
+ * const maze = [
61
+ * ['S', ' ', 'X'],
62
+ * ['X', ' ', 'X'],
63
+ * [' ', ' ', 'E']
64
+ * ];
65
+ * const start: [number, number] = [0, 0];
66
+ * const end = [2, 2];
67
+ * const directions = [
68
+ * [0, 1], // To the right
69
+ * [1, 0], // down
70
+ * [0, -1], // left
71
+ * [-1, 0] // up
72
+ * ];
73
+ *
74
+ * const visited = new Set<string>(); // Used to record visited nodes
75
+ * stack.push(start);
76
+ * const path: number[][] = [];
77
+ *
78
+ * while (!stack.isEmpty()) {
79
+ * const [x, y] = stack.pop()!;
80
+ * if (visited.has(`${x},${y}`)) continue; // Skip already visited nodes
81
+ * visited.add(`${x},${y}`);
82
+ *
83
+ * path.push([x, y]);
84
+ *
85
+ * if (x === end[0] && y === end[1]) {
86
+ * break; // Find the end point and exit
87
+ * }
88
+ *
89
+ * for (const [dx, dy] of directions) {
90
+ * const nx = x + dx;
91
+ * const ny = y + dy;
92
+ * if (
93
+ * maze[nx]?.[ny] === ' ' || // feasible path
94
+ * maze[nx]?.[ny] === 'E' // destination
95
+ * ) {
96
+ * stack.push([nx, ny]);
97
+ * }
98
+ * }
99
+ * }
100
+ *
101
+ * expect(path).toContainEqual(end);
102
+ * @example
103
+ * // Function Call Stack
104
+ * const functionStack = new Stack<string>();
105
+ * functionStack.push('main');
106
+ * functionStack.push('foo');
107
+ * functionStack.push('bar');
108
+ * console.log(functionStack.pop()); // 'bar'
109
+ * console.log(functionStack.pop()); // 'foo'
110
+ * console.log(functionStack.pop()); // 'main'
111
+ * @example
112
+ * // Simplify File Paths
113
+ * const stack = new Stack<string>();
114
+ * const path = '/a/./b/../../c';
115
+ * path.split('/').forEach(segment => {
116
+ * if (segment === '..') stack.pop();
117
+ * else if (segment && segment !== '.') stack.push(segment);
118
+ * });
119
+ * console.log(stack.elements.join('/')); // 'c'
120
+ * @example
121
+ * // Stock Span Problem
122
+ * const stack = new Stack<number>();
123
+ * const prices = [100, 80, 60, 70, 60, 75, 85];
124
+ * const spans: number[] = [];
125
+ * prices.forEach((price, i) => {
126
+ * while (!stack.isEmpty() && prices[stack.peek()!] <= price) {
127
+ * stack.pop();
128
+ * }
129
+ * spans.push(stack.isEmpty() ? i + 1 : i - stack.peek()!);
130
+ * stack.push(i);
131
+ * });
132
+ * console.log(spans); // [1, 1, 1, 2, 1, 4, 6]
12
133
  */
13
134
  class Stack extends base_1.IterableElementBase {
14
135
  constructor(elements = [], options) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "min-heap-typed",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "Min Heap. Javascript & Typescript Data Structure.",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -132,6 +132,6 @@
132
132
  "typescript": "^4.9.5"
133
133
  },
134
134
  "dependencies": {
135
- "data-structure-typed": "^2.0.0"
135
+ "data-structure-typed": "^2.0.1"
136
136
  }
137
137
  }
@@ -339,7 +339,7 @@ export abstract class AbstractGraph<
339
339
 
340
340
  if (isWeight) {
341
341
  const allPaths = this.getAllPathsBetween(v1, v2);
342
- let min = Infinity;
342
+ let min = Number.MAX_SAFE_INTEGER;
343
343
  for (const path of allPaths) {
344
344
  min = Math.min(this.getPathSumWeight(path), min);
345
345
  }
@@ -404,7 +404,7 @@ export abstract class AbstractGraph<
404
404
  if (isWeight) {
405
405
  if (isDFS) {
406
406
  const allPaths = this.getAllPathsBetween(v1, v2, 10000);
407
- let min = Infinity;
407
+ let min = Number.MAX_SAFE_INTEGER;
408
408
  let minIndex = -1;
409
409
  let index = 0;
410
410
  for (const path of allPaths) {
@@ -475,7 +475,7 @@ export abstract class AbstractGraph<
475
475
  getMinDist: boolean = false,
476
476
  genPaths: boolean = false
477
477
  ): DijkstraResult<VO> {
478
- let minDist = Infinity;
478
+ let minDist = Number.MAX_SAFE_INTEGER;
479
479
  let minDest: VO | undefined = undefined;
480
480
  let minPath: VO[] = [];
481
481
  const paths: VO[][] = [];
@@ -494,13 +494,13 @@ export abstract class AbstractGraph<
494
494
 
495
495
  for (const vertex of vertexMap) {
496
496
  const vertexOrKey = vertex[1];
497
- if (vertexOrKey instanceof AbstractVertex) distMap.set(vertexOrKey, Infinity);
497
+ if (vertexOrKey instanceof AbstractVertex) distMap.set(vertexOrKey, Number.MAX_SAFE_INTEGER);
498
498
  }
499
499
  distMap.set(srcVertex, 0);
500
500
  preMap.set(srcVertex, undefined);
501
501
 
502
502
  const getMinOfNoSeen = () => {
503
- let min = Infinity;
503
+ let min = Number.MAX_SAFE_INTEGER;
504
504
  let minV: VO | undefined = undefined;
505
505
  for (const [key, value] of distMap) {
506
506
  if (!seen.has(key)) {
@@ -537,7 +537,7 @@ export abstract class AbstractGraph<
537
537
  seen.add(cur);
538
538
  if (destVertex && destVertex === cur) {
539
539
  if (getMinDist) {
540
- minDist = distMap.get(destVertex) || Infinity;
540
+ minDist = distMap.get(destVertex) || Number.MAX_SAFE_INTEGER;
541
541
  }
542
542
  if (genPaths) {
543
543
  getPaths(destVertex);
@@ -605,7 +605,7 @@ export abstract class AbstractGraph<
605
605
  getMinDist: boolean = false,
606
606
  genPaths: boolean = false
607
607
  ): DijkstraResult<VO> {
608
- let minDist = Infinity;
608
+ let minDist = Number.MAX_SAFE_INTEGER;
609
609
  let minDest: VO | undefined = undefined;
610
610
  let minPath: VO[] = [];
611
611
  const paths: VO[][] = [];
@@ -621,7 +621,7 @@ export abstract class AbstractGraph<
621
621
 
622
622
  for (const vertex of vertexMap) {
623
623
  const vertexOrKey = vertex[1];
624
- if (vertexOrKey instanceof AbstractVertex) distMap.set(vertexOrKey, Infinity);
624
+ if (vertexOrKey instanceof AbstractVertex) distMap.set(vertexOrKey, Number.MAX_SAFE_INTEGER);
625
625
  }
626
626
 
627
627
  const heap = new Heap<{ key: number; value: VO }>([], { comparator: (a, b) => a.key - b.key });
@@ -661,7 +661,7 @@ export abstract class AbstractGraph<
661
661
  seen.add(cur);
662
662
  if (destVertex && destVertex === cur) {
663
663
  if (getMinDist) {
664
- minDist = distMap.get(destVertex) || Infinity;
664
+ minDist = distMap.get(destVertex) || Number.MAX_SAFE_INTEGER;
665
665
  }
666
666
  if (genPaths) {
667
667
  getPaths(destVertex);
@@ -732,7 +732,7 @@ export abstract class AbstractGraph<
732
732
  const paths: VO[][] = [];
733
733
  const distMap: Map<VO, number> = new Map();
734
734
  const preMap: Map<VO, VO> = new Map(); // predecessor
735
- let min = Infinity;
735
+ let min = Number.MAX_SAFE_INTEGER;
736
736
  let minPath: VO[] = [];
737
737
  // TODO
738
738
  let hasNegativeCycle: boolean | undefined;
@@ -745,7 +745,7 @@ export abstract class AbstractGraph<
745
745
  const numOfEdges = edgeMap.length;
746
746
 
747
747
  this._vertexMap.forEach(vertex => {
748
- distMap.set(vertex, Infinity);
748
+ distMap.set(vertex, Number.MAX_SAFE_INTEGER);
749
749
  });
750
750
 
751
751
  distMap.set(srcVertex, 0);
@@ -759,7 +759,7 @@ export abstract class AbstractGraph<
759
759
  const sWeight = distMap.get(s);
760
760
  const dWeight = distMap.get(d);
761
761
  if (sWeight !== undefined && dWeight !== undefined) {
762
- if (distMap.get(s) !== Infinity && sWeight + weight < dWeight) {
762
+ if (distMap.get(s) !== Number.MAX_SAFE_INTEGER && sWeight + weight < dWeight) {
763
763
  distMap.set(d, sWeight + weight);
764
764
  if (genPath) preMap.set(d, s);
765
765
  }
@@ -804,7 +804,7 @@ export abstract class AbstractGraph<
804
804
  const weight = edgeMap[j].weight;
805
805
  const sWeight = distMap.get(s);
806
806
  if (sWeight) {
807
- if (sWeight !== Infinity && sWeight + weight < sWeight) hasNegativeCycle = true;
807
+ if (sWeight !== Number.MAX_SAFE_INTEGER && sWeight + weight < sWeight) hasNegativeCycle = true;
808
808
  }
809
809
  }
810
810
  }
@@ -860,7 +860,7 @@ export abstract class AbstractGraph<
860
860
 
861
861
  for (let i = 0; i < n; i++) {
862
862
  for (let j = 0; j < n; j++) {
863
- costs[i][j] = this.getEdge(idAndVertices[i][1], idAndVertices[j][1])?.weight || Infinity;
863
+ costs[i][j] = this.getEdge(idAndVertices[i][1], idAndVertices[j][1])?.weight || Number.MAX_SAFE_INTEGER;
864
864
  }
865
865
  }
866
866
 
@@ -21,6 +21,52 @@ import { isWeakKey, rangeCheck } from '../../utils';
21
21
  * 3. Unique Keys: Keys are unique.
22
22
  * If you try to insert another entry with the same key, the new one will replace the old entry.
23
23
  * 4. Unordered Collection: HashMap does not guarantee the order of entries, and the order may change over time.
24
+ * @example
25
+ * // should maintain insertion order
26
+ * const linkedHashMap = new LinkedHashMap<number, string>();
27
+ * linkedHashMap.set(1, 'A');
28
+ * linkedHashMap.set(2, 'B');
29
+ * linkedHashMap.set(3, 'C');
30
+ *
31
+ * const result = Array.from(linkedHashMap);
32
+ * console.log(result); // [
33
+ * // [1, 'A'],
34
+ * // [2, 'B'],
35
+ * // [3, 'C']
36
+ * // ]
37
+ * @example
38
+ * // fast lookup of values by key
39
+ * const hashMap = new HashMap<number, string>();
40
+ * hashMap.set(1, 'A');
41
+ * hashMap.set(2, 'B');
42
+ * hashMap.set(3, 'C');
43
+ *
44
+ * console.log(hashMap.get(1)); // 'A'
45
+ * console.log(hashMap.get(2)); // 'B'
46
+ * console.log(hashMap.get(3)); // 'C'
47
+ * console.log(hashMap.get(99)); // undefined
48
+ * @example
49
+ * // remove duplicates when adding multiple entries
50
+ * const hashMap = new HashMap<number, string>();
51
+ * hashMap.set(1, 'A');
52
+ * hashMap.set(2, 'B');
53
+ * hashMap.set(1, 'C'); // Update value for key 1
54
+ *
55
+ * console.log(hashMap.size); // 2
56
+ * console.log(hashMap.get(1)); // 'C'
57
+ * console.log(hashMap.get(2)); // 'B'
58
+ * @example
59
+ * // count occurrences of keys
60
+ * const data = [1, 2, 1, 3, 2, 1];
61
+ *
62
+ * const countMap = new HashMap<number, number>();
63
+ * for (const key of data) {
64
+ * countMap.set(key, (countMap.get(key) || 0) + 1);
65
+ * }
66
+ *
67
+ * console.log(countMap.get(1)); // 3
68
+ * console.log(countMap.get(2)); // 2
69
+ * console.log(countMap.get(3)); // 1
24
70
  */
25
71
  export class HashMap<K = any, V = any, R = [K, V]> extends IterableEntryBase<K, V> {
26
72
  /**
@@ -38,6 +38,72 @@ export class SinglyLinkedListNode<E = any> extends LinkedListNode<E> {
38
38
  * 4. High Efficiency in Insertion and Deletion: Adding or removing elements in a linked list does not require moving other elements, making these operations more efficient than in arrays.
39
39
  * Caution: Although our linked list classes provide methods such as at, setAt, addAt, and indexOf that are based on array indices, their time complexity, like that of the native Array.lastIndexOf, is 𝑂(𝑛). If you need to use these methods frequently, you might want to consider other data structures, such as Deque or Queue (designed for random access). Similarly, since the native Array.shift method has a time complexity of 𝑂(𝑛), using an array to simulate a queue can be inefficient. In such cases, you should use Queue or Deque, as these data structures leverage deferred array rearrangement, effectively reducing the average time complexity to 𝑂(1).
40
40
  *
41
+ * @example
42
+ * // implementation of a basic text editor
43
+ * class TextEditor {
44
+ * private content: SinglyLinkedList<string>;
45
+ * private cursorIndex: number;
46
+ * private undoStack: Stack<{ operation: string; data?: any }>;
47
+ *
48
+ * constructor() {
49
+ * this.content = new SinglyLinkedList<string>();
50
+ * this.cursorIndex = 0; // Cursor starts at the beginning
51
+ * this.undoStack = new Stack<{ operation: string; data?: any }>(); // Stack to keep track of operations for undo
52
+ * }
53
+ *
54
+ * insert(char: string) {
55
+ * this.content.addAt(this.cursorIndex, char);
56
+ * this.cursorIndex++;
57
+ * this.undoStack.push({ operation: 'insert', data: { index: this.cursorIndex - 1 } });
58
+ * }
59
+ *
60
+ * delete() {
61
+ * if (this.cursorIndex === 0) return; // Nothing to delete
62
+ * const deleted = this.content.deleteAt(this.cursorIndex - 1);
63
+ * this.cursorIndex--;
64
+ * this.undoStack.push({ operation: 'delete', data: { index: this.cursorIndex, char: deleted } });
65
+ * }
66
+ *
67
+ * moveCursor(index: number) {
68
+ * this.cursorIndex = Math.max(0, Math.min(index, this.content.length));
69
+ * }
70
+ *
71
+ * undo() {
72
+ * if (this.undoStack.size === 0) return; // No operations to undo
73
+ * const lastAction = this.undoStack.pop();
74
+ *
75
+ * if (lastAction!.operation === 'insert') {
76
+ * this.content.deleteAt(lastAction!.data.index);
77
+ * this.cursorIndex = lastAction!.data.index;
78
+ * } else if (lastAction!.operation === 'delete') {
79
+ * this.content.addAt(lastAction!.data.index, lastAction!.data.char);
80
+ * this.cursorIndex = lastAction!.data.index + 1;
81
+ * }
82
+ * }
83
+ *
84
+ * getText(): string {
85
+ * return [...this.content].join('');
86
+ * }
87
+ * }
88
+ *
89
+ * // Example Usage
90
+ * const editor = new TextEditor();
91
+ * editor.insert('H');
92
+ * editor.insert('e');
93
+ * editor.insert('l');
94
+ * editor.insert('l');
95
+ * editor.insert('o');
96
+ * console.log(editor.getText()); // 'Hello' // Output: "Hello"
97
+ *
98
+ * editor.delete();
99
+ * console.log(editor.getText()); // 'Hell' // Output: "Hell"
100
+ *
101
+ * editor.undo();
102
+ * console.log(editor.getText()); // 'Hello' // Output: "Hello"
103
+ *
104
+ * editor.moveCursor(1);
105
+ * editor.insert('a');
106
+ * console.log(editor.getText()); // 'Haello'
41
107
  */
42
108
  export class SinglyLinkedList<E = any, R = any> extends LinearLinkedBase<E, R, SinglyLinkedListNode<E>> {
43
109
  constructor(
@@ -15,6 +15,53 @@ import { LinearBase } from '../base/linear-base';
15
15
  * 5. Data Buffering: Acting as a buffer for data packets in network communication.
16
16
  * 6. Breadth-First Search (BFS): In traversal algorithms for graphs and trees, queues store elements that are to be visited.
17
17
  * 7. Real-time Queuing: Like queuing systems in banks or supermarkets.
18
+ * @example
19
+ * // Sliding Window using Queue
20
+ * const nums = [2, 3, 4, 1, 5];
21
+ * const k = 2;
22
+ * const queue = new Queue<number>();
23
+ *
24
+ * let maxSum = 0;
25
+ * let currentSum = 0;
26
+ *
27
+ * nums.forEach((num, i) => {
28
+ * queue.push(num);
29
+ * currentSum += num;
30
+ *
31
+ * if (queue.length > k) {
32
+ * currentSum -= queue.shift()!;
33
+ * }
34
+ *
35
+ * if (queue.length === k) {
36
+ * maxSum = Math.max(maxSum, currentSum);
37
+ * }
38
+ * });
39
+ *
40
+ * console.log(maxSum); // 7
41
+ * @example
42
+ * // Breadth-First Search (BFS) using Queue
43
+ * const graph: { [key in number]: number[] } = {
44
+ * 1: [2, 3],
45
+ * 2: [4, 5],
46
+ * 3: [],
47
+ * 4: [],
48
+ * 5: []
49
+ * };
50
+ *
51
+ * const queue = new Queue<number>();
52
+ * const visited: number[] = [];
53
+ *
54
+ * queue.push(1);
55
+ *
56
+ * while (!queue.isEmpty()) {
57
+ * const node = queue.shift()!;
58
+ * if (!visited.includes(node)) {
59
+ * visited.push(node);
60
+ * graph[node].forEach(neighbor => queue.push(neighbor));
61
+ * }
62
+ * }
63
+ *
64
+ * console.log(visited); // [1, 2, 3, 4, 5]
18
65
  */
19
66
  export class Queue<E = any, R = any> extends LinearBase<E, R> {
20
67
  constructor(elements: Iterable<E> | Iterable<R> = [], options?: QueueOptions<E, R>) {
@@ -15,6 +15,127 @@ import { IterableElementBase } from '../base';
15
15
  * 4. Function Calls: In most modern programming languages, the records of function calls are managed through a stack. When a function is called, its record (including parameters, local variables, and return address) is 'pushed' into the stack. When the function returns, its record is 'popped' from the stack.
16
16
  * 5. Expression Evaluation: Used for the evaluation of arithmetic or logical expressions, especially when dealing with parenthesis matching and operator precedence.
17
17
  * 6. Backtracking Algorithms: In problems where multiple branches need to be explored but only one branch can be explored at a time, stacks can be used to save the state at each branching point.
18
+ * @example
19
+ * // Balanced Parentheses or Brackets
20
+ * type ValidCharacters = ')' | '(' | ']' | '[' | '}' | '{';
21
+ *
22
+ * const stack = new Stack<string>();
23
+ * const input: ValidCharacters[] = '[({})]'.split('') as ValidCharacters[];
24
+ * const matches: { [key in ValidCharacters]?: ValidCharacters } = { ')': '(', ']': '[', '}': '{' };
25
+ * for (const char of input) {
26
+ * if ('([{'.includes(char)) {
27
+ * stack.push(char);
28
+ * } else if (')]}'.includes(char)) {
29
+ * if (stack.pop() !== matches[char]) {
30
+ * fail('Parentheses are not balanced');
31
+ * }
32
+ * }
33
+ * }
34
+ * console.log(stack.isEmpty()); // true
35
+ * @example
36
+ * // Expression Evaluation and Conversion
37
+ * const stack = new Stack<number>();
38
+ * const expression = [5, 3, '+']; // Equivalent to 5 + 3
39
+ * expression.forEach(token => {
40
+ * if (typeof token === 'number') {
41
+ * stack.push(token);
42
+ * } else {
43
+ * const b = stack.pop()!;
44
+ * const a = stack.pop()!;
45
+ * stack.push(token === '+' ? a + b : 0); // Only handling '+' here
46
+ * }
47
+ * });
48
+ * console.log(stack.pop()); // 8
49
+ * @example
50
+ * // Depth-First Search (DFS)
51
+ * const stack = new Stack<number>();
52
+ * const graph: { [key in number]: number[] } = { 1: [2, 3], 2: [4], 3: [5], 4: [], 5: [] };
53
+ * const visited: number[] = [];
54
+ * stack.push(1);
55
+ * while (!stack.isEmpty()) {
56
+ * const node = stack.pop()!;
57
+ * if (!visited.includes(node)) {
58
+ * visited.push(node);
59
+ * graph[node].forEach(neighbor => stack.push(neighbor));
60
+ * }
61
+ * }
62
+ * console.log(visited); // [1, 3, 5, 2, 4]
63
+ * @example
64
+ * // Backtracking Algorithms
65
+ * const stack = new Stack<[number, number]>();
66
+ * const maze = [
67
+ * ['S', ' ', 'X'],
68
+ * ['X', ' ', 'X'],
69
+ * [' ', ' ', 'E']
70
+ * ];
71
+ * const start: [number, number] = [0, 0];
72
+ * const end = [2, 2];
73
+ * const directions = [
74
+ * [0, 1], // To the right
75
+ * [1, 0], // down
76
+ * [0, -1], // left
77
+ * [-1, 0] // up
78
+ * ];
79
+ *
80
+ * const visited = new Set<string>(); // Used to record visited nodes
81
+ * stack.push(start);
82
+ * const path: number[][] = [];
83
+ *
84
+ * while (!stack.isEmpty()) {
85
+ * const [x, y] = stack.pop()!;
86
+ * if (visited.has(`${x},${y}`)) continue; // Skip already visited nodes
87
+ * visited.add(`${x},${y}`);
88
+ *
89
+ * path.push([x, y]);
90
+ *
91
+ * if (x === end[0] && y === end[1]) {
92
+ * break; // Find the end point and exit
93
+ * }
94
+ *
95
+ * for (const [dx, dy] of directions) {
96
+ * const nx = x + dx;
97
+ * const ny = y + dy;
98
+ * if (
99
+ * maze[nx]?.[ny] === ' ' || // feasible path
100
+ * maze[nx]?.[ny] === 'E' // destination
101
+ * ) {
102
+ * stack.push([nx, ny]);
103
+ * }
104
+ * }
105
+ * }
106
+ *
107
+ * expect(path).toContainEqual(end);
108
+ * @example
109
+ * // Function Call Stack
110
+ * const functionStack = new Stack<string>();
111
+ * functionStack.push('main');
112
+ * functionStack.push('foo');
113
+ * functionStack.push('bar');
114
+ * console.log(functionStack.pop()); // 'bar'
115
+ * console.log(functionStack.pop()); // 'foo'
116
+ * console.log(functionStack.pop()); // 'main'
117
+ * @example
118
+ * // Simplify File Paths
119
+ * const stack = new Stack<string>();
120
+ * const path = '/a/./b/../../c';
121
+ * path.split('/').forEach(segment => {
122
+ * if (segment === '..') stack.pop();
123
+ * else if (segment && segment !== '.') stack.push(segment);
124
+ * });
125
+ * console.log(stack.elements.join('/')); // 'c'
126
+ * @example
127
+ * // Stock Span Problem
128
+ * const stack = new Stack<number>();
129
+ * const prices = [100, 80, 60, 70, 60, 75, 85];
130
+ * const spans: number[] = [];
131
+ * prices.forEach((price, i) => {
132
+ * while (!stack.isEmpty() && prices[stack.peek()!] <= price) {
133
+ * stack.pop();
134
+ * }
135
+ * spans.push(stack.isEmpty() ? i + 1 : i - stack.peek()!);
136
+ * stack.push(i);
137
+ * });
138
+ * console.log(spans); // [1, 1, 1, 2, 1, 4, 6]
18
139
  */
19
140
  export class Stack<E = any, R = any> extends IterableElementBase<E, R> {
20
141
  constructor(elements: Iterable<E> | Iterable<R> = [], options?: StackOptions<E, R>) {