UNPKG

arrayqeque

Version:

High-performance Deque (Double-Ended Queue) for DSA practice with O(1) operations

220 lines (161 loc) 5.49 kB
A high-performance ArrayDeque (Double-Ended Queue) implementation in TypeScript, optimized for Data Structures and Algorithms practice. All operations are O(1) time complexity (amortized). ## Features - ✅ **O(1) Operations**: All main operations run in constant time (amortized) - ✅ **Versatile**: Use as Stack, Queue, or ArrayDeque - ✅ **Type-Safe**: Full TypeScript support with generics - ✅ **Memory Efficient**: Circular buffer with dynamic growth - ✅ **Well-Documented**: JSDoc with time/space complexity annotations - ✅ **Iterable**: Works with for...of loops and spread operator - ✅ **Zero Dependencies**: Lightweight and standalone ## Installation ```bash npm install arraydeque ``` ## Quick Start ```typescript import { ArrayDeque } from 'arraydeque'; const deque = new ArrayDeque<number>(); // Use as Stack (LIFO) deque.push(1); deque.push(2); console.log(deque.pop()); // 2 // Use as Queue (FIFO) deque.enqueue(1); deque.enqueue(2); console.log(deque.dequeue()); // 1 // Use as ArrayDeque deque.pushFront(1); deque.pushBack(2); console.log(deque.popFront()); // 1 console.log(deque.popBack()); // 2 ``` ## API Reference ### Constructor ```typescript new ArrayDeque<T>(initialCapacity?: number) ``` Creates a new deque with optional initial capacity (default: 16). ### Properties | Property | Type | Description | Time | |----------|------|-------------|------| | `size` | `number` | Number of elements | O(1) | ### Stack Operations | Method | Description | Time | |--------|-------------|------| | `push(value)` | Add to back | O(1) amortized | | `pop()` | Remove from back | O(1) | | `peek()` | View back element | O(1) | | `top()` | Alias for peek | O(1) | ### Queue Operations | Method | Description | Time | |--------|-------------|------| | `enqueue(value)` | Add to back | O(1) amortized | | `dequeue()` | Remove from front | O(1) | | `front()` | View front element | O(1) | | `back()` | View back element | O(1) | ### ArrayDeque Operations | Method | Description | Time | |--------|-------------|------| | `pushFront(value)` | Add to front | O(1) amortized | | `pushBack(value)` | Add to back | O(1) amortized | | `popFront()` | Remove from front | O(1) | | `popBack()` | Remove from back | O(1) | | `peekFront()` | View front element | O(1) | | `peekBack()` | View back element | O(1) | ### Array-like Operations | Method | Description | Time | |--------|-------------|------| | `unshift(value)` | Add to front | O(1) amortized | | `shift()` | Remove from front | O(1) | | `at(index)` | Access by index | O(1) | ### Utility Methods | Method | Description | Time | |--------|-------------|------| | `isEmpty()` | Check if empty | O(1) | | `clear()` | Remove all elements | O(1) | | `toArray()` | Convert to array | O(n) | | `clone()` | Create shallow copy | O(n) | | `toString()` | String representation | O(n) | ## Examples ### BFS (Breadth-First Search) ```typescript const bfs = (graph: Map<string, string[]>, start: string) => { const deque = new ArrayDeque<string>(); const visited = new Set<string>(); deque.enqueue(start); visited.add(start); while (!deque.isEmpty()) { const node = deque.dequeue()!; console.log(node); for (const neighbor of graph.get(node) || []) { if (!visited.has(neighbor)) { visited.add(neighbor); deque.enqueue(neighbor); } } } }; ``` ### 0-1 BFS ```typescript const bfs01 = (graph: [number, number][][], start: number) => { const deque = new ArrayDeque<[number, number]>(); const dist = new Map<number, number>(); deque.pushBack([start, 0]); dist.set(start, 0); while (!deque.isEmpty()) { const [node, d] = deque.popFront()!; if (d > dist.get(node)!) continue; for (const [neighbor, weight] of graph[node] || []) { const newDist = d + weight; if (!dist.has(neighbor) || newDist < dist.get(neighbor)!) { dist.set(neighbor, newDist); if (weight === 0) { deque.pushFront([neighbor, newDist]); // 0-weight edge } else { deque.pushBack([neighbor, newDist]); // 1-weight edge } } } } return dist; }; ``` ### Sliding Window Maximum ```typescript const slidingWindowMaximum = (nums: number[], k: number): number[] => { const deque = new ArrayDeque<number>(); // Store indices const result: number[] = []; for (let i = 0; i < nums.length; i++) { // Remove indices outside window while (!deque.isEmpty() && deque.peekFront()! < i - k + 1) { deque.popFront(); } // Remove smaller elements while (!deque.isEmpty() && nums[deque.peekBack()!] < nums[i]) { deque.popBack(); } deque.pushBack(i); if (i >= k - 1) { result.push(nums[deque.peekFront()!]); } } return result; }; ``` ## Performance All main operations are **O(1)** amortized time complexity: - Push/Pop (both ends): O(1) amortized - Peek (both ends): O(1) - Size/isEmpty: O(1) - Random access via `at()`: O(1) Space complexity: O(n) where n is the number of elements. ## Why This Implementation? Unlike JavaScript's built-in array methods: - `Array.shift()` is O(n) - our `popFront()` is O(1) - `Array.unshift()` is O(n) - our `pushFront()` is O(1) This makes our ArrayDeque significantly faster for algorithms that require frequent front operations, such as BFS, sliding window problems, and 0-1 BFS. ## License MIT ## Contributing Contributions are welcome! Please feel free to submit a Pull Request.