# Deque In a queue, we can only remove elements from the front or add elements at the rear. As shown in the figure below, a double-ended queue (deque) provides greater flexibility, allowing the addition or removal of elements at both the front and rear. ![Operations of deque](deque.assets/deque_operations.png) ## Common Deque Operations The common operations on a deque are shown in the table below. The specific method names depend on the programming language used.

Table   Efficiency of Deque Operations

| Method | Description | Time Complexity | | -------------- | ------------------------- | --------------- | | `push_first()` | Add element to front | $O(1)$ | | `push_last()` | Add element to rear | $O(1)$ | | `pop_first()` | Remove front element | $O(1)$ | | `pop_last()` | Remove rear element | $O(1)$ | | `peek_first()` | Access front element | $O(1)$ | | `peek_last()` | Access rear element | $O(1)$ | Similarly, we can directly use the deque classes already implemented in programming languages: === "Python" ```python title="deque.py" from collections import deque # Initialize deque deq: deque[int] = deque() # Enqueue elements deq.append(2) # Add to rear deq.append(5) deq.append(4) deq.appendleft(3) # Add to front deq.appendleft(1) # Access elements front: int = deq[0] # Front element rear: int = deq[-1] # Rear element # Dequeue elements pop_front: int = deq.popleft() # Front element dequeue pop_rear: int = deq.pop() # Rear element dequeue # Get deque length size: int = len(deq) # Check if deque is empty is_empty: bool = len(deq) == 0 ``` === "C++" ```cpp title="deque.cpp" /* Initialize deque */ deque deque; /* Enqueue elements */ deque.push_back(2); // Add to rear deque.push_back(5); deque.push_back(4); deque.push_front(3); // Add to front deque.push_front(1); /* Access elements */ int front = deque.front(); // Front element int back = deque.back(); // Rear element /* Dequeue elements */ deque.pop_front(); // Front element dequeue deque.pop_back(); // Rear element dequeue /* Get deque length */ int size = deque.size(); /* Check if deque is empty */ bool empty = deque.empty(); ``` === "Java" ```java title="deque.java" /* Initialize deque */ Deque deque = new LinkedList<>(); /* Enqueue elements */ deque.offerLast(2); // Add to rear deque.offerLast(5); deque.offerLast(4); deque.offerFirst(3); // Add to front deque.offerFirst(1); /* Access elements */ int peekFirst = deque.peekFirst(); // Front element int peekLast = deque.peekLast(); // Rear element /* Dequeue elements */ int popFirst = deque.pollFirst(); // Front element dequeue int popLast = deque.pollLast(); // Rear element dequeue /* Get deque length */ int size = deque.size(); /* Check if deque is empty */ boolean isEmpty = deque.isEmpty(); ``` === "C#" ```csharp title="deque.cs" /* Initialize deque */ // In C#, use LinkedList as a deque LinkedList deque = new(); /* Enqueue elements */ deque.AddLast(2); // Add to rear deque.AddLast(5); deque.AddLast(4); deque.AddFirst(3); // Add to front deque.AddFirst(1); /* Access elements */ int peekFirst = deque.First.Value; // Front element int peekLast = deque.Last.Value; // Rear element /* Dequeue elements */ deque.RemoveFirst(); // Front element dequeue deque.RemoveLast(); // Rear element dequeue /* Get deque length */ int size = deque.Count; /* Check if deque is empty */ bool isEmpty = deque.Count == 0; ``` === "Go" ```go title="deque_test.go" /* Initialize deque */ // In Go, use list as a deque deque := list.New() /* Enqueue elements */ deque.PushBack(2) // Add to rear deque.PushBack(5) deque.PushBack(4) deque.PushFront(3) // Add to front deque.PushFront(1) /* Access elements */ front := deque.Front() // Front element rear := deque.Back() // Rear element /* Dequeue elements */ deque.Remove(front) // Front element dequeue deque.Remove(rear) // Rear element dequeue /* Get deque length */ size := deque.Len() /* Check if deque is empty */ isEmpty := deque.Len() == 0 ``` === "Swift" ```swift title="deque.swift" /* Initialize deque */ // Swift does not have a built-in deque class, can use Array as a deque var deque: [Int] = [] /* Enqueue elements */ deque.append(2) // Add to rear deque.append(5) deque.append(4) deque.insert(3, at: 0) // Add to front deque.insert(1, at: 0) /* Access elements */ let peekFirst = deque.first! // Front element let peekLast = deque.last! // Rear element /* Dequeue elements */ // When using Array simulation, popFirst has O(n) complexity let popFirst = deque.removeFirst() // Front element dequeue let popLast = deque.removeLast() // Rear element dequeue /* Get deque length */ let size = deque.count /* Check if deque is empty */ let isEmpty = deque.isEmpty ``` === "JS" ```javascript title="deque.js" /* Initialize deque */ // JavaScript does not have a built-in deque, can only use Array as a deque const deque = []; /* Enqueue elements */ deque.push(2); deque.push(5); deque.push(4); // Please note that since it's an array, unshift() has O(n) time complexity deque.unshift(3); deque.unshift(1); /* Access elements */ const peekFirst = deque[0]; const peekLast = deque[deque.length - 1]; /* Dequeue elements */ // Please note that since it's an array, shift() has O(n) time complexity const popFront = deque.shift(); const popBack = deque.pop(); /* Get deque length */ const size = deque.length; /* Check if deque is empty */ const isEmpty = size === 0; ``` === "TS" ```typescript title="deque.ts" /* Initialize deque */ // TypeScript does not have a built-in deque, can only use Array as a deque const deque: number[] = []; /* Enqueue elements */ deque.push(2); deque.push(5); deque.push(4); // Please note that since it's an array, unshift() has O(n) time complexity deque.unshift(3); deque.unshift(1); /* Access elements */ const peekFirst: number = deque[0]; const peekLast: number = deque[deque.length - 1]; /* Dequeue elements */ // Please note that since it's an array, shift() has O(n) time complexity const popFront: number = deque.shift() as number; const popBack: number = deque.pop() as number; /* Get deque length */ const size: number = deque.length; /* Check if deque is empty */ const isEmpty: boolean = size === 0; ``` === "Dart" ```dart title="deque.dart" /* Initialize deque */ // In Dart, Queue is defined as a deque Queue deque = Queue(); /* Enqueue elements */ deque.addLast(2); // Add to rear deque.addLast(5); deque.addLast(4); deque.addFirst(3); // Add to front deque.addFirst(1); /* Access elements */ int peekFirst = deque.first; // Front element int peekLast = deque.last; // Rear element /* Dequeue elements */ int popFirst = deque.removeFirst(); // Front element dequeue int popLast = deque.removeLast(); // Rear element dequeue /* Get deque length */ int size = deque.length; /* Check if deque is empty */ bool isEmpty = deque.isEmpty; ``` === "Rust" ```rust title="deque.rs" /* Initialize deque */ let mut deque: VecDeque = VecDeque::new(); /* Enqueue elements */ deque.push_back(2); // Add to rear deque.push_back(5); deque.push_back(4); deque.push_front(3); // Add to front deque.push_front(1); /* Access elements */ if let Some(front) = deque.front() { // Front element } if let Some(rear) = deque.back() { // Rear element } /* Dequeue elements */ if let Some(pop_front) = deque.pop_front() { // Front element dequeue } if let Some(pop_rear) = deque.pop_back() { // Rear element dequeue } /* Get deque length */ let size = deque.len(); /* Check if deque is empty */ let is_empty = deque.is_empty(); ``` === "C" ```c title="deque.c" // C does not provide a built-in deque ``` === "Kotlin" ```kotlin title="deque.kt" /* Initialize deque */ val deque = LinkedList() /* Enqueue elements */ deque.offerLast(2) // Add to rear deque.offerLast(5) deque.offerLast(4) deque.offerFirst(3) // Add to front deque.offerFirst(1) /* Access elements */ val peekFirst = deque.peekFirst() // Front element val peekLast = deque.peekLast() // Rear element /* Dequeue elements */ val popFirst = deque.pollFirst() // Front element dequeue val popLast = deque.pollLast() // Rear element dequeue /* Get deque length */ val size = deque.size /* Check if deque is empty */ val isEmpty = deque.isEmpty() ``` === "Ruby" ```ruby title="deque.rb" # Initialize deque # Ruby does not have a built-in deque, can only use Array as a deque deque = [] # Enqueue elements deque << 2 deque << 5 deque << 4 # Please note that since it's an array, Array#unshift has O(n) time complexity deque.unshift(3) deque.unshift(1) # Access elements peek_first = deque.first peek_last = deque.last # Dequeue elements # Please note that since it's an array, Array#shift has O(n) time complexity pop_front = deque.shift pop_back = deque.pop # Get deque length size = deque.length # Check if deque is empty is_empty = size.zero? ``` ??? pythontutor "Code Visualization" https://pythontutor.com/render.html#code=from%20collections%20import%20deque%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E5%8F%8C%E5%90%91%E9%98%9F%E5%88%97%0A%20%20%20%20deq%20%3D%20deque%28%29%0A%0A%20%20%20%20%23%20%E5%85%83%E7%B4%A0%E5%85%A5%E9%98%9F%0A%20%20%20%20deq.append%282%29%20%20%23%20%E6%B7%BB%E5%8A%A0%E8%87%B3%E9%98%9F%E5%B0%BE%0A%20%20%20%20deq.append%285%29%0A%20%20%20%20deq.append%284%29%0A%20%20%20%20deq.appendleft%283%29%20%20%23%20%E6%B7%BB%E5%8A%A0%E8%87%B3%E9%98%9F%E9%A6%96%0A%20%20%20%20deq.appendleft%281%29%0A%20%20%20%20print%28%22%E5%8F%8C%E5%90%91%E9%98%9F%E5%88%97%20deque%20%3D%22,%20deq%29%0A%0A%20%20%20%20%23%20%E8%AE%BF%E9%97%AE%E5%85%83%E7%B4%A0%0A%20%20%20%20front%20%3D%20deq%5B0%5D%20%20%23%20%E9%98%9F%E9%A6%96%E5%85%83%E7%B4%A0%0A%20%20%20%20print%28%22%E9%98%9F%E9%A6%96%E5%85%83%E7%B4%A0%20front%20%3D%22,%20front%29%0A%20%20%20%20rear%20%3D%20deq%5B-1%5D%20%20%23%20%E9%98%9F%E5%B0%BE%E5%85%83%E7%B4%A0%0A%20%20%20%20print%28%22%E9%98%9F%E5%B0%BE%E5%85%83%E7%B4%A0%20rear%20%3D%22,%20rear%29%0A%0A%20%20%20%20%23%20%E5%85%83%E7%B4%A0%E5%87%BA%E9%98%9F%0A%20%20%20%20pop_front%20%3D%20deq.popleft%28%29%20%20%23%20%E9%98%9F%E9%A6%96%E5%85%83%E7%B4%A0%E5%87%BA%E9%98%9F%0A%20%20%20%20print%28%22%E9%98%9F%E9%A6%96%E5%87%BA%E9%98%9F%E5%85%83%E7%B4%A0%20%20pop_front%20%3D%22,%20pop_front%29%0A%20%20%20%20print%28%22%E9%98%9F%E9%A6%96%E5%87%BA%E9%98%9F%E5%90%8E%20deque%20%3D%22,%20deq%29%0A%20%20%20%20pop_rear%20%3D%20deq.pop%28%29%20%20%23%20%E9%98%9F%E5%B0%BE%E5%85%83%E7%B4%A0%E5%87%BA%E9%98%9F%0A%20%20%20%20print%28%22%E9%98%9F%E5%B0%BE%E5%87%BA%E9%98%9F%E5%85%83%E7%B4%A0%20%20pop_rear%20%3D%22,%20pop_rear%29%0A%20%20%20%20print%28%22%E9%98%9F%E5%B0%BE%E5%87%BA%E9%98%9F%E5%90%8E%20deque%20%3D%22,%20deq%29%0A%0A%20%20%20%20%23%20%E8%8E%B7%E5%8F%96%E5%8F%8C%E5%90%91%E9%98%9F%E5%88%97%E7%9A%84%E9%95%BF%E5%BA%A6%0A%20%20%20%20size%20%3D%20len%28deq%29%0A%20%20%20%20print%28%22%E5%8F%8C%E5%90%91%E9%98%9F%E5%88%97%E9%95%BF%E5%BA%A6%20size%20%3D%22,%20size%29%0A%0A%20%20%20%20%23%20%E5%88%A4%E6%96%AD%E5%8F%8C%E5%90%91%E9%98%9F%E5%88%97%E6%98%AF%E5%90%A6%E4%B8%BA%E7%A9%BA%0A%20%20%20%20is_empty%20%3D%20len%28deq%29%20%3D%3D%200%0A%20%20%20%20print%28%22%E5%8F%8C%E5%90%91%E9%98%9F%E5%88%97%E6%98%AF%E5%90%A6%E4%B8%BA%E7%A9%BA%20%3D%22,%20is_empty%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false ## Deque Implementation * The implementation of a deque is similar to that of a queue. You can choose either a linked list or an array as the underlying data structure. ### Doubly Linked List Implementation Reviewing the previous section, we used a regular singly linked list to implement a queue because it conveniently allows deleting the head node (corresponding to dequeue) and adding new nodes after the tail node (corresponding to enqueue). For a deque, both the front and rear can perform enqueue and dequeue operations. In other words, a deque needs to implement operations in the opposite direction as well. For this reason, we use a "doubly linked list" as the underlying data structure for the deque. As shown in the figure below, we treat the head and tail nodes of the doubly linked list as the front and rear of the deque, implementing functionality to add and remove nodes at both ends. === "LinkedListDeque" ![Enqueue and dequeue operations in linked list implementation of deque](deque.assets/linkedlist_deque_step1.png) === "push_last()" ![linkedlist_deque_push_last](deque.assets/linkedlist_deque_step2_push_last.png) === "push_first()" ![linkedlist_deque_push_first](deque.assets/linkedlist_deque_step3_push_first.png) === "pop_last()" ![linkedlist_deque_pop_last](deque.assets/linkedlist_deque_step4_pop_last.png) === "pop_first()" ![linkedlist_deque_pop_first](deque.assets/linkedlist_deque_step5_pop_first.png) The implementation code is shown below: ```src [file]{linkedlist_deque}-[class]{linked_list_deque}-[func]{} ``` ### Array Implementation As shown in the figure below, similar to implementing a queue based on an array, we can also use a circular array to implement a deque. === "ArrayDeque" ![Enqueue and dequeue operations in array implementation of deque](deque.assets/array_deque_step1.png) === "push_last()" ![array_deque_push_last](deque.assets/array_deque_step2_push_last.png) === "push_first()" ![array_deque_push_first](deque.assets/array_deque_step3_push_first.png) === "pop_last()" ![array_deque_pop_last](deque.assets/array_deque_step4_pop_last.png) === "pop_first()" ![array_deque_pop_first](deque.assets/array_deque_step5_pop_first.png) Based on the queue implementation, we only need to add methods for "enqueue at front" and "dequeue from rear": ```src [file]{array_deque}-[class]{array_deque}-[func]{} ``` ## Deque Applications A deque combines the logic of both stacks and queues. **Therefore, it can implement all application scenarios of both, while providing greater flexibility**. We know that the "undo" function in software is typically implemented using a stack: the system pushes each change operation onto the stack and then implements undo through pop. However, considering system resource limitations, software usually limits the number of undo steps (for example, only allowing 50 steps to be saved). When the stack length exceeds 50, the software needs to perform a deletion operation at the bottom of the stack (front of the queue). **But a stack cannot implement this functionality, so a deque is needed to replace the stack**. Note that the core logic of "undo" still follows the LIFO principle of a stack; it's just that the deque can more flexibly implement some additional logic.