|
1 | | -# Deque (Double-Ended Queue) |
2 | | - |
3 | | -A **deque** (pronounced "deck", short for **double-ended queue**) is a linear data |
4 | | -structure that generalises both a stack and a queue. Elements can be added or |
5 | | -removed from **either end** — the front (head) or the back (tail) — in **O(1)** time. |
6 | | - |
7 | | -``` |
8 | | -addFront(3) addBack(4) |
9 | | - ↓ ↓ |
10 | | -┌───┬───┬───┬───┐ |
11 | | -│ 3 │ 1 │ 2 │ 4 │ ← internal linked list |
12 | | -└───┴───┴───┴───┘ |
13 | | - ↑ ↑ |
14 | | -removeFront() removeBack() |
15 | | -``` |
16 | | - |
17 | | -## Operations |
18 | | - |
19 | | -| Method | Description | Time | |
20 | | -| ------------- | -------------------------------------------- | ---- | |
21 | | -| `addFront(v)` | Insert element `v` at the front | O(1) | |
22 | | -| `addBack(v)` | Insert element `v` at the back | O(1) | |
23 | | -| `removeFront()` | Remove and return the front element | O(1) | |
24 | | -| `removeBack()` | Remove and return the back element | O(1) | |
25 | | -| `peekFront()` | Return the front element without removing it | O(1) | |
26 | | -| `peekBack()` | Return the back element without removing it | O(1) | |
27 | | -| `isEmpty()` | Return `true` if the deque has no elements | O(1) | |
28 | | -| `size` | Return the number of elements | O(n) | |
29 | | - |
30 | | -> **Note:** `size` is O(n) because the underlying linked list does not cache |
31 | | -> length. If you call `size` frequently, consider maintaining an internal counter. |
32 | | -
|
33 | | -## Complexity |
34 | | - |
35 | | -| | | |
36 | | -| --------- | ---- | |
37 | | -| Space | O(n) | |
38 | | -| addFront | O(1) | |
39 | | -| addBack | O(1) | |
40 | | -| removeFront | O(1) | |
41 | | -| removeBack | O(1) | |
42 | | -| peekFront | O(1) | |
43 | | -| peekBack | O(1) | |
44 | | - |
45 | | -## Use Cases |
46 | | - |
47 | | -A deque is the right tool when you need **O(1) access at both ends**: |
48 | | - |
49 | | -- **Sliding window maximum/minimum** — maintain candidates in a monotonic deque |
50 | | - so each element is pushed and popped at most once (overall O(n)). |
51 | | -- **Browser history** — navigate backward (`removeFront`) and forward |
52 | | - (`removeBack`) through pages. |
53 | | -- **Undo / redo stacks** — push actions to the back, undo from the back, |
54 | | - redo from the front. |
55 | | -- **Palindrome checking** — compare characters from both ends simultaneously. |
56 | | -- **Work-stealing schedulers** (e.g. Java's `ForkJoinPool`) — threads push/pop |
57 | | - from their own back, while idle threads steal from another thread's front. |
58 | | - |
59 | | -## Implementation Note |
60 | | - |
61 | | -This implementation is backed by the project's existing `LinkedList` (a doubly |
62 | | -linked list). This gives O(1) `prepend` (for `addFront`) and O(1) `append` / |
63 | | -`deleteTail` (for `addBack` / `removeBack`), with no need to shift array |
64 | | -elements. |
65 | | - |
66 | | -An alternative implementation using a circular buffer (fixed-size array) offers |
67 | | -better cache locality but requires resizing logic. The linked-list approach is |
68 | | -chosen here to stay consistent with the other data structures in this project. |
69 | | - |
70 | | -## References |
71 | | - |
72 | | -- [Deque — Wikipedia](https://en.wikipedia.org/wiki/Double-ended_queue) |
73 | | -- [Deque Data Structure — GeeksForGeeks](https://www.geeksforgeeks.org/deque-set-1-introduction-applications/) |
74 | | -- [▶ Deque in 3 minutes — YouTube](https://www.youtube.com/watch?v=kLBuJ1998Do) |
75 | | -- [Sliding Window Maximum using Deque — YouTube](https://www.youtube.com/watch?v=2SXqBsTR6a8) |
| 1 | +# Deque (Double-Ended Queue) |
| 2 | + |
| 3 | +A **deque** (pronounced "deck", short for **double-ended queue**) is a linear data |
| 4 | +structure that generalizes both a stack and a queue. Elements can be added or |
| 5 | +removed from **either end** — the front (head) or the back (tail) — in **O(1)** time. |
| 6 | + |
| 7 | +``` |
| 8 | + addFront(3) addBack(4) |
| 9 | + ↓ ↓ |
| 10 | + ┌───────┬───────┬───────┬───────┐ |
| 11 | + │ 3 │ 1 │ 2 │ 4 │ ← internal doubly linked list |
| 12 | + └───────┴───────┴───────┴───────┘ |
| 13 | + ↑ ↑ |
| 14 | + removeFront() removeBack() |
| 15 | +``` |
| 16 | + |
| 17 | +## Operations |
| 18 | + |
| 19 | +| Method | Description | Time | |
| 20 | +| --------------- | -------------------------------------------- | ---- | |
| 21 | +| `addFront(v)` | Insert element `v` at the front | O(1) | |
| 22 | +| `addBack(v)` | Insert element `v` at the back | O(1) | |
| 23 | +| `removeFront()` | Remove and return the front element | O(1) | |
| 24 | +| `removeBack()` | Remove and return the back element | O(1) | |
| 25 | +| `peekFront()` | Return the front element without removing it | O(1) | |
| 26 | +| `peekBack()` | Return the back element without removing it | O(1) | |
| 27 | +| `isEmpty()` | Return `true` if the deque has no elements | O(1) | |
| 28 | +| `size` | Return the number of elements | O(1) | |
| 29 | + |
| 30 | +> **Note:** `size` is O(1) because the deque keeps a running element count that |
| 31 | +> is updated on every add and remove operation. |
| 32 | +
|
| 33 | +## Complexity |
| 34 | + |
| 35 | +| Operation | Time | |
| 36 | +| ---------------------------- | ---- | |
| 37 | +| `addFront` / `addBack` | O(1) | |
| 38 | +| `removeFront` / `removeBack` | O(1) | |
| 39 | +| `peekFront` / `peekBack` | O(1) | |
| 40 | +| `isEmpty` / `size` | O(1) | |
| 41 | +| Space | O(n) | |
| 42 | + |
| 43 | +## Use Cases |
| 44 | + |
| 45 | +A deque is the right tool when you need **O(1) access at both ends**: |
| 46 | + |
| 47 | +- **Sliding window maximum/minimum** — maintain candidates in a monotonic deque |
| 48 | + so each element is pushed and popped at most once (overall O(n)). |
| 49 | +- **Browser history** — navigate backward (`removeFront`) and forward |
| 50 | + (`removeBack`) through pages. |
| 51 | +- **Undo / redo stacks** — push actions to the back, undo from the back, |
| 52 | + redo from the front. |
| 53 | +- **Palindrome checking** — compare characters from both ends simultaneously. |
| 54 | +- **Work-stealing schedulers** (e.g. Java's `ForkJoinPool`) — threads push/pop |
| 55 | + from their own back, while idle threads steal from another thread's front. |
| 56 | + |
| 57 | +## Implementation Note |
| 58 | + |
| 59 | +This implementation is backed by the project's existing |
| 60 | +[`DoublyLinkedList`](../doubly-linked-list). Because every node keeps a reference |
| 61 | +to both its previous and next neighbours, this gives O(1) `prepend` (for |
| 62 | +`addFront`), O(1) `deleteHead` (for `removeFront`) and O(1) `append` / |
| 63 | +`deleteTail` (for `addBack` / `removeBack`), with no need to shift array |
| 64 | +elements. The number of elements is tracked in a counter, so `size` is O(1) too. |
| 65 | + |
| 66 | +An alternative implementation using a circular buffer (fixed-size array) offers |
| 67 | +better cache locality but requires resizing logic. The linked-list approach is |
| 68 | +chosen here to stay consistent with the other data structures in this project. |
| 69 | + |
| 70 | +## References |
| 71 | + |
| 72 | +- [Deque — Wikipedia](https://en.wikipedia.org/wiki/Double-ended_queue) |
| 73 | +- [Deque Data Structure — GeeksForGeeks](https://www.geeksforgeeks.org/deque-set-1-introduction-applications/) |
| 74 | +- [▶ Deque (Double-Ended Queue) — YouTube](https://www.youtube.com/watch?v=pqg0SOPRlJ4) |
| 75 | +- [▶ Sliding Window Maximum using Deque — YouTube](https://www.youtube.com/watch?v=2SXqBsTR6a8) |
0 commit comments