What is a Double-Ended Queue (Deque)?
A Double-Ended Queue (Deque) is a versatile data structure that allows insertion and deletion of elements from both ends (front and rear). Unlike a single-ended queue, it provides more flexibility while maintaining efficient O(1) operations.
Key Characteristics
Deques have these fundamental properties:
- Two open ends:
- Supports operations at both front and rear
- Four core operations:
- addFront() - Insert at front
- addRear() - Insert at rear
- removeFront() - Delete from front
- removeRear() - Delete from rear
- Hybrid nature:
- Combines features of both stacks and queues
Visual Example
Operation sequence on an empty deque:
- addFront(30): [30]
- addRear(40): [30, 40]
- addFront(20): [20, 30, 40]
- addRear(50): [20, 30, 40, 50]
- removeFront(): Returns 20 → [30, 40, 50]
- removeRear(): Returns 50 → [30, 40]
Implementation Variations
Common implementation approaches:
- Doubly Linked List:
- Natural fit with head and tail pointers
- All operations are O(1)
- Extra memory for previous/next pointers
- Circular Array:
- Fixed capacity but efficient
- Requires careful index management
- Good for memory-constrained environments
- Dynamic Array:
- Amortized O(1) operations
- May need occasional resizing
Time Complexity
- addFront(): O(1)
- addRear(): O(1)
- removeFront(): O(1)
- removeRear(): O(1)
- peekFront(): O(1)
- peekRear(): O(1)
Applications
Deques are used in:
- Undo/Redo operations: Store history at both ends
- Palindrome checking: Compare front and rear elements
- Steal algorithms: Work stealing in parallel processing
- Sliding window problems: Efficient maximum/minimum tracking
- Browser history: Navigation in both directions
Special Cases
Interesting deque variations:
- Input-Restricted Deque: Insertion only at one end
- Output-Restricted Deque: Deletion only at one end
- Palindrome Checker: Using deque properties
- Priority Deque: Combines deque and priority queue features
The double-ended queue is a powerful hybrid data structure that combines the best features of stacks and queues. Its flexibility makes it invaluable for algorithms requiring access to both ends of a dataset, while maintaining efficient constant-time operations for all key functions.