red-black-tree-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 (46) hide show
  1. package/README.md +92 -37
  2. package/dist/cjs/index.cjs +163 -0
  3. package/dist/cjs/index.cjs.map +1 -1
  4. package/dist/cjs-legacy/index.cjs +164 -0
  5. package/dist/cjs-legacy/index.cjs.map +1 -1
  6. package/dist/esm/index.mjs +163 -0
  7. package/dist/esm/index.mjs.map +1 -1
  8. package/dist/esm-legacy/index.mjs +164 -0
  9. package/dist/esm-legacy/index.mjs.map +1 -1
  10. package/dist/types/data-structures/binary-tree/avl-tree.d.ts +96 -2
  11. package/dist/types/data-structures/binary-tree/binary-tree.d.ts +103 -7
  12. package/dist/types/data-structures/binary-tree/bst.d.ts +156 -13
  13. package/dist/types/data-structures/binary-tree/red-black-tree.d.ts +84 -35
  14. package/dist/types/data-structures/binary-tree/tree-multi-map.d.ts +2 -2
  15. package/dist/types/data-structures/graph/directed-graph.d.ts +126 -1
  16. package/dist/types/data-structures/graph/undirected-graph.d.ts +160 -1
  17. package/dist/types/data-structures/hash/hash-map.d.ts +110 -27
  18. package/dist/types/data-structures/heap/heap.d.ts +107 -58
  19. package/dist/types/data-structures/linked-list/doubly-linked-list.d.ts +72 -404
  20. package/dist/types/data-structures/linked-list/singly-linked-list.d.ts +121 -5
  21. package/dist/types/data-structures/queue/deque.d.ts +95 -67
  22. package/dist/types/data-structures/queue/queue.d.ts +90 -34
  23. package/dist/types/data-structures/stack/stack.d.ts +58 -40
  24. package/dist/types/data-structures/trie/trie.d.ts +109 -47
  25. package/dist/types/interfaces/binary-tree.d.ts +1 -0
  26. package/dist/umd/red-black-tree-typed.js +164 -0
  27. package/dist/umd/red-black-tree-typed.js.map +1 -1
  28. package/dist/umd/red-black-tree-typed.min.js +3 -3
  29. package/dist/umd/red-black-tree-typed.min.js.map +1 -1
  30. package/package.json +2 -2
  31. package/src/data-structures/binary-tree/avl-tree.ts +96 -2
  32. package/src/data-structures/binary-tree/binary-tree.ts +117 -7
  33. package/src/data-structures/binary-tree/bst.ts +322 -13
  34. package/src/data-structures/binary-tree/red-black-tree.ts +84 -35
  35. package/src/data-structures/binary-tree/tree-multi-map.ts +2 -2
  36. package/src/data-structures/graph/directed-graph.ts +126 -1
  37. package/src/data-structures/graph/undirected-graph.ts +160 -1
  38. package/src/data-structures/hash/hash-map.ts +110 -27
  39. package/src/data-structures/heap/heap.ts +107 -58
  40. package/src/data-structures/linked-list/doubly-linked-list.ts +72 -404
  41. package/src/data-structures/linked-list/singly-linked-list.ts +121 -5
  42. package/src/data-structures/queue/deque.ts +95 -67
  43. package/src/data-structures/queue/queue.ts +90 -34
  44. package/src/data-structures/stack/stack.ts +58 -40
  45. package/src/data-structures/trie/trie.ts +109 -47
  46. package/src/interfaces/binary-tree.ts +2 -0
@@ -27,93 +27,121 @@ import { LinearBase } from '../base/linear-base';
27
27
  * 4. Efficiency: Adding and removing elements at both ends of a deque is usually very fast. However, when the dynamic array needs to expand, it may involve copying the entire array to a larger one, and this operation has a time complexity of O(n).
28
28
  * 5. Performance jitter: Deque may experience performance jitter, but DoublyLinkedList will not
29
29
  * @example
30
- * // prize roulette
31
- * class PrizeRoulette {
32
- * private deque: Deque<string>;
30
+ * // basic Deque creation and push/pop operations
31
+ * // Create a simple Deque with initial values
32
+ * const deque = new Deque([1, 2, 3, 4, 5]);
33
33
  *
34
- * constructor(prizes: string[]) {
35
- * // Initialize the deque with prizes
36
- * this.deque = new Deque<string>(prizes);
37
- * }
34
+ * // Verify the deque maintains insertion order
35
+ * console.log([...deque]); // [1, 2, 3, 4, 5];
38
36
  *
39
- * // Rotate clockwise to the right (forward)
40
- * rotateClockwise(steps: number): void {
41
- * const n = this.deque.length;
42
- * if (n === 0) return;
37
+ * // Check length
38
+ * console.log(deque.length); // 5;
43
39
  *
44
- * for (let i = 0; i < steps; i++) {
45
- * const last = this.deque.pop(); // Remove the last element
46
- * this.deque.unshift(last!); // Add it to the front
47
- * }
48
- * }
40
+ * // Push to the end
41
+ * deque.push(6);
42
+ * console.log(deque.length); // 6;
49
43
  *
50
- * // Rotate counterclockwise to the left (backward)
51
- * rotateCounterClockwise(steps: number): void {
52
- * const n = this.deque.length;
53
- * if (n === 0) return;
44
+ * // Pop from the end
45
+ * const last = deque.pop();
46
+ * console.log(last); // 6;
47
+ * @example
48
+ * // Deque shift and unshift operations
49
+ * const deque = new Deque<number>([20, 30, 40]);
54
50
  *
55
- * for (let i = 0; i < steps; i++) {
56
- * const first = this.deque.shift(); // Remove the first element
57
- * this.deque.push(first!); // Add it to the back
58
- * }
59
- * }
51
+ * // Unshift adds to the front
52
+ * deque.unshift(10);
53
+ * console.log([...deque]); // [10, 20, 30, 40];
60
54
  *
61
- * // Display the current prize at the head
62
- * display() {
63
- * return this.deque.first;
64
- * }
65
- * }
55
+ * // Shift removes from the front (O(1) complexity!)
56
+ * const first = deque.shift();
57
+ * console.log(first); // 10;
66
58
  *
67
- * // Example usage
68
- * const prizes = ['Car', 'Bike', 'Laptop', 'Phone', 'Watch', 'Headphones']; // Initialize the prize list
69
- * const roulette = new PrizeRoulette(prizes);
59
+ * // Verify remaining elements
60
+ * console.log([...deque]); // [20, 30, 40];
61
+ * console.log(deque.length); // 3;
62
+ * @example
63
+ * // Deque peek at both ends
64
+ * const deque = new Deque<number>([10, 20, 30, 40, 50]);
70
65
  *
71
- * // Display the initial state
72
- * console.log(roulette.display()); // 'Car' // Car
66
+ * // Get first element without removing
67
+ * const first = deque.at(0);
68
+ * console.log(first); // 10;
73
69
  *
74
- * // Rotate clockwise by 3 steps
75
- * roulette.rotateClockwise(3);
76
- * console.log(roulette.display()); // 'Phone' // Phone
70
+ * // Get last element without removing
71
+ * const last = deque.at(deque.length - 1);
72
+ * console.log(last); // 50;
77
73
  *
78
- * // Rotate counterclockwise by 2 steps
79
- * roulette.rotateCounterClockwise(2);
80
- * console.log(roulette.display()); // 'Headphones'
74
+ * // Length unchanged
75
+ * console.log(deque.length); // 5;
81
76
  * @example
82
- * // sliding window
83
- * // Maximum function of sliding window
84
- * function maxSlidingWindow(nums: number[], k: number): number[] {
85
- * const n = nums.length;
86
- * if (n * k === 0) return [];
77
+ * // Deque for...of iteration and reverse
78
+ * const deque = new Deque<string>(['A', 'B', 'C', 'D']);
87
79
  *
88
- * const deq = new Deque<number>();
89
- * const result: number[] = [];
80
+ * // Iterate forward
81
+ * const forward: string[] = [];
82
+ * for (const item of deque) {
83
+ * forward.push(item);
84
+ * }
85
+ * console.log(forward); // ['A', 'B', 'C', 'D'];
90
86
  *
91
- * for (let i = 0; i < n; i++) {
92
- * // Delete indexes in the queue that are not within the window range
93
- * if (deq.length > 0 && deq.first! === i - k) {
94
- * deq.shift();
95
- * }
87
+ * // Reverse the deque
88
+ * deque.reverse();
89
+ * const backward: string[] = [];
90
+ * for (const item of deque) {
91
+ * backward.push(item);
92
+ * }
93
+ * console.log(backward); // ['D', 'C', 'B', 'A'];
94
+ * @example
95
+ * // Deque as sliding window for stream processing
96
+ * interface DataPoint {
97
+ * timestamp: number;
98
+ * value: number;
99
+ * sensor: string;
100
+ * }
101
+ *
102
+ * // Create a deque-based sliding window for real-time data aggregation
103
+ * const windowSize = 3;
104
+ * const dataWindow = new Deque<DataPoint>();
96
105
  *
97
- * // Remove all indices less than the current value from the tail of the queue
98
- * while (deq.length > 0 && nums[deq.last!] < nums[i]) {
99
- * deq.pop();
100
- * }
106
+ * // Simulate incoming sensor data stream
107
+ * const incomingData: DataPoint[] = [
108
+ * { timestamp: 1000, value: 25.5, sensor: 'temp-01' },
109
+ * { timestamp: 1100, value: 26.2, sensor: 'temp-01' },
110
+ * { timestamp: 1200, value: 25.8, sensor: 'temp-01' },
111
+ * { timestamp: 1300, value: 27.1, sensor: 'temp-01' },
112
+ * { timestamp: 1400, value: 26.9, sensor: 'temp-01' }
113
+ * ];
101
114
  *
102
- * // Add the current index to the end of the queue
103
- * deq.push(i);
115
+ * const windowResults: Array<{ avgValue: number; windowSize: number }> = [];
116
+ *
117
+ * for (const dataPoint of incomingData) {
118
+ * // Add new data to the end
119
+ * dataWindow.push(dataPoint);
120
+ *
121
+ * // Remove oldest data when window exceeds size (O(1) from front)
122
+ * if (dataWindow.length > windowSize) {
123
+ * dataWindow.shift();
124
+ * }
104
125
  *
105
- * // Add the maximum value of the window to the results
106
- * if (i >= k - 1) {
107
- * result.push(nums[deq.first!]);
108
- * }
126
+ * // Calculate average of current window
127
+ * let sum = 0;
128
+ * for (const point of dataWindow) {
129
+ * sum += point.value;
109
130
  * }
131
+ * const avg = sum / dataWindow.length;
110
132
  *
111
- * return result;
133
+ * windowResults.push({
134
+ * avgValue: Math.round(avg * 10) / 10,
135
+ * windowSize: dataWindow.length
136
+ * });
112
137
  * }
113
138
  *
114
- * const nums = [1, 3, -1, -3, 5, 3, 6, 7];
115
- * const k = 3;
116
- * console.log(maxSlidingWindow(nums, k)); // [3, 3, 5, 5, 6, 7]
139
+ * // Verify sliding window behavior
140
+ * console.log(windowResults.length); // 5;
141
+ * console.log(windowResults[0].windowSize); // 1; // First window has 1 element
142
+ * console.log(windowResults[2].windowSize); // 3; // Windows are at max size from 3rd onwards
143
+ * console.log(windowResults[4].windowSize); // 3; // Last window still has 3 elements
144
+ * console.log(dataWindow.length); // 3;
117
145
  */
118
146
  export class Deque<E = any, R = any> extends LinearBase<E, R> {
119
147
  protected _equals: (a: E, b: E) => boolean = Object.is as unknown as (a: E, b: E) => boolean;
@@ -23,52 +23,108 @@ import { LinearBase } from '../base/linear-base';
23
23
  * 6. Breadth-First Search (BFS): In traversal algorithms for graphs and trees, queues store elements that are to be visited.
24
24
  * 7. Real-time Queuing: Like queuing systems in banks or supermarkets.
25
25
  * @example
26
- * // Sliding Window using Queue
27
- * const nums = [2, 3, 4, 1, 5];
28
- * const k = 2;
29
- * const queue = new Queue<number>();
26
+ * // basic Queue creation and push operation
27
+ * // Create a simple Queue with initial values
28
+ * const queue = new Queue([1, 2, 3, 4, 5]);
30
29
  *
31
- * let maxSum = 0;
32
- * let currentSum = 0;
30
+ * // Verify the queue maintains insertion order
31
+ * console.log([...queue]); // [1, 2, 3, 4, 5];
33
32
  *
34
- * nums.forEach(num => {
35
- * queue.push(num);
36
- * currentSum += num;
33
+ * // Check length
34
+ * console.log(queue.length); // 5;
35
+ * @example
36
+ * // Queue shift and peek operations
37
+ * const queue = new Queue<number>([10, 20, 30, 40]);
37
38
  *
38
- * if (queue.length > k) {
39
- * currentSum -= queue.shift()!;
40
- * }
39
+ * // Peek at the front element without removing it
40
+ * console.log(queue.first); // 10;
41
41
  *
42
- * if (queue.length === k) {
43
- * maxSum = Math.max(maxSum, currentSum);
44
- * }
45
- * });
42
+ * // Remove and get the first element (FIFO)
43
+ * const first = queue.shift();
44
+ * console.log(first); // 10;
46
45
  *
47
- * console.log(maxSum); // 7
46
+ * // Verify remaining elements and length decreased
47
+ * console.log([...queue]); // [20, 30, 40];
48
+ * console.log(queue.length); // 3;
48
49
  * @example
49
- * // Breadth-First Search (BFS) using Queue
50
- * const graph: { [key in number]: number[] } = {
51
- * 1: [2, 3],
52
- * 2: [4, 5],
53
- * 3: [],
54
- * 4: [],
55
- * 5: []
56
- * };
50
+ * // Queue for...of iteration and isEmpty check
51
+ * const queue = new Queue<string>(['A', 'B', 'C', 'D']);
52
+ *
53
+ * const elements: string[] = [];
54
+ * for (const item of queue) {
55
+ * elements.push(item);
56
+ * }
57
+ *
58
+ * // Verify all elements are iterated in order
59
+ * console.log(elements); // ['A', 'B', 'C', 'D'];
57
60
  *
58
- * const queue = new Queue<number>();
59
- * const visited: number[] = [];
61
+ * // Process all elements
62
+ * while (queue.length > 0) {
63
+ * queue.shift();
64
+ * }
65
+ *
66
+ * console.log(queue.length); // 0;
67
+ * @example
68
+ * // Queue as message broker for event processing
69
+ * interface Message {
70
+ * id: string;
71
+ * type: 'email' | 'sms' | 'push';
72
+ * recipient: string;
73
+ * content: string;
74
+ * timestamp: Date;
75
+ * }
60
76
  *
61
- * queue.push(1);
77
+ * // Create a message queue for real-time event processing
78
+ * const messageQueue = new Queue<Message>([
79
+ * {
80
+ * id: 'msg-001',
81
+ * type: 'email',
82
+ * recipient: 'user@example.com',
83
+ * content: 'Welcome!',
84
+ * timestamp: new Date()
85
+ * },
86
+ * {
87
+ * id: 'msg-002',
88
+ * type: 'sms',
89
+ * recipient: '+1234567890',
90
+ * content: 'OTP: 123456',
91
+ * timestamp: new Date()
92
+ * },
93
+ * {
94
+ * id: 'msg-003',
95
+ * type: 'push',
96
+ * recipient: 'device-token-xyz',
97
+ * content: 'New notification',
98
+ * timestamp: new Date()
99
+ * },
100
+ * {
101
+ * id: 'msg-004',
102
+ * type: 'email',
103
+ * recipient: 'admin@example.com',
104
+ * content: 'Daily report',
105
+ * timestamp: new Date()
106
+ * }
107
+ * ]);
62
108
  *
63
- * while (!queue.isEmpty()) {
64
- * const node = queue.shift()!;
65
- * if (!visited.includes(node)) {
66
- * visited.push(node);
67
- * graph[node].forEach(neighbor => queue.push(neighbor));
109
+ * // Process messages in FIFO order (first message first)
110
+ * const processedMessages: string[] = [];
111
+ * while (messageQueue.length > 0) {
112
+ * const message = messageQueue.shift();
113
+ * if (message) {
114
+ * processedMessages.push(`${message.type}:${message.recipient}`);
68
115
  * }
69
116
  * }
70
117
  *
71
- * console.log(visited); // [1, 2, 3, 4, 5]
118
+ * // Verify messages were processed in order
119
+ * console.log(processedMessages); // [
120
+ * // 'email:user@example.com',
121
+ * // 'sms:+1234567890',
122
+ * // 'push:device-token-xyz',
123
+ * // 'email:admin@example.com'
124
+ * // ];
125
+ *
126
+ * // Queue should be empty after processing all messages
127
+ * console.log(messageQueue.length); // 0;
72
128
  */
73
129
  export class Queue<E = any, R = any> extends LinearBase<E, R> {
74
130
  /**
@@ -21,8 +21,49 @@ import { IterableElementBase } from '../base';
21
21
  * 5. Expression Evaluation: Used for the evaluation of arithmetic or logical expressions, especially when dealing with parenthesis matching and operator precedence.
22
22
  * 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.
23
23
  * @example
24
+ * // basic Stack creation and push operation
25
+ * // Create a simple Stack with initial values
26
+ * const stack = new Stack([1, 2, 3, 4, 5]);
27
+ *
28
+ * // Verify the stack maintains insertion order (LIFO will be shown in pop)
29
+ * console.log([...stack]); // [1, 2, 3, 4, 5];
30
+ *
31
+ * // Check length
32
+ * console.log(stack.size); // 5;
33
+ *
34
+ * // Push a new element to the top
35
+ * stack.push(6);
36
+ * console.log(stack.size); // 6;
37
+ * @example
38
+ * // Stack pop operation (LIFO - Last In First Out)
39
+ * const stack = new Stack<number>([10, 20, 30, 40, 50]);
40
+ *
41
+ * // Peek at the top element without removing
42
+ * const top = stack.peek();
43
+ * console.log(top); // 50;
44
+ *
45
+ * // Pop removes from the top (LIFO order)
46
+ * const popped = stack.pop();
47
+ * console.log(popped); // 50;
48
+ *
49
+ * // Next pop gets the previous element
50
+ * const next = stack.pop();
51
+ * console.log(next); // 40;
52
+ *
53
+ * // Verify length decreased
54
+ * console.log(stack.size); // 3;
55
+ * @example
56
+ * // Function Call Stack
57
+ * const functionStack = new Stack<string>();
58
+ * functionStack.push('main');
59
+ * functionStack.push('foo');
60
+ * functionStack.push('bar');
61
+ * console.log(functionStack.pop()); // 'bar';
62
+ * console.log(functionStack.pop()); // 'foo';
63
+ * console.log(functionStack.pop()); // 'main';
64
+ * @example
24
65
  * // Balanced Parentheses or Brackets
25
- * type ValidCharacters = ')' | '(' | ']' | '[' | '}' | '{';
66
+ * type ValidCharacters = ')' | '(' | ']' | '[' | '}' | '{';
26
67
  *
27
68
  * const stack = new Stack<string>();
28
69
  * const input: ValidCharacters[] = '[({})]'.split('') as ValidCharacters[];
@@ -36,10 +77,10 @@ import { IterableElementBase } from '../base';
36
77
  * }
37
78
  * }
38
79
  * }
39
- * console.log(stack.isEmpty()); // true
80
+ * console.log(stack.isEmpty()); // true;
40
81
  * @example
41
82
  * // Expression Evaluation and Conversion
42
- * const stack = new Stack<number>();
83
+ * const stack = new Stack<number>();
43
84
  * const expression = [5, 3, '+']; // Equivalent to 5 + 3
44
85
  * expression.forEach(token => {
45
86
  * if (typeof token === 'number') {
@@ -50,24 +91,10 @@ import { IterableElementBase } from '../base';
50
91
  * stack.push(token === '+' ? a + b : 0); // Only handling '+' here
51
92
  * }
52
93
  * });
53
- * console.log(stack.pop()); // 8
54
- * @example
55
- * // Depth-First Search (DFS)
56
- * const stack = new Stack<number>();
57
- * const graph: { [key in number]: number[] } = { 1: [2, 3], 2: [4], 3: [5], 4: [], 5: [] };
58
- * const visited: number[] = [];
59
- * stack.push(1);
60
- * while (!stack.isEmpty()) {
61
- * const node = stack.pop()!;
62
- * if (!visited.includes(node)) {
63
- * visited.push(node);
64
- * graph[node].forEach(neighbor => stack.push(neighbor));
65
- * }
66
- * }
67
- * console.log(visited); // [1, 3, 5, 2, 4]
94
+ * console.log(stack.pop()); // 8;
68
95
  * @example
69
96
  * // Backtracking Algorithms
70
- * const stack = new Stack<[number, number]>();
97
+ * const stack = new Stack<[number, number]>();
71
98
  * const maze = [
72
99
  * ['S', ' ', 'X'],
73
100
  * ['X', ' ', 'X'],
@@ -109,28 +136,10 @@ import { IterableElementBase } from '../base';
109
136
  * }
110
137
  * }
111
138
  *
112
- * expect(path).toContainEqual(end);
113
- * @example
114
- * // Function Call Stack
115
- * const functionStack = new Stack<string>();
116
- * functionStack.push('main');
117
- * functionStack.push('foo');
118
- * functionStack.push('bar');
119
- * console.log(functionStack.pop()); // 'bar'
120
- * console.log(functionStack.pop()); // 'foo'
121
- * console.log(functionStack.pop()); // 'main'
122
- * @example
123
- * // Simplify File Paths
124
- * const stack = new Stack<string>();
125
- * const path = '/a/./b/../../c';
126
- * path.split('/').forEach(segment => {
127
- * if (segment === '..') stack.pop();
128
- * else if (segment && segment !== '.') stack.push(segment);
129
- * });
130
- * console.log(stack.elements.join('/')); // 'c'
139
+ * console.log(path); // contains end;
131
140
  * @example
132
141
  * // Stock Span Problem
133
- * const stack = new Stack<number>();
142
+ * const stack = new Stack<number>();
134
143
  * const prices = [100, 80, 60, 70, 60, 75, 85];
135
144
  * const spans: number[] = [];
136
145
  * prices.forEach((price, i) => {
@@ -140,7 +149,16 @@ import { IterableElementBase } from '../base';
140
149
  * spans.push(stack.isEmpty() ? i + 1 : i - stack.peek()!);
141
150
  * stack.push(i);
142
151
  * });
143
- * console.log(spans); // [1, 1, 1, 2, 1, 4, 6]
152
+ * console.log(spans); // [1, 1, 1, 2, 1, 4, 6];
153
+ * @example
154
+ * // Simplify File Paths
155
+ * const stack = new Stack<string>();
156
+ * const path = '/a/./b/../../c';
157
+ * path.split('/').forEach(segment => {
158
+ * if (segment === '..') stack.pop();
159
+ * else if (segment && segment !== '.') stack.push(segment);
160
+ * });
161
+ * console.log(stack.elements.join('/')); // 'c';
144
162
  */
145
163
  export class Stack<E = any, R = any> extends IterableElementBase<E, R> {
146
164
  protected _equals: (a: E, b: E) => boolean = Object.is as unknown as (a: E, b: E) => boolean;