Deque Data Structure



Deque is a hybrid data structure that combines the features of a stack and a queue. It allows us to insert and delete elements from both ends of the queue. The name Deque is an abbreviation of Double-Ended Queue.

Imagine an event where you have two gates to enter and exit a place. People are entering from the front gate and some are entering from the side gate. Now, when people are leaving, they are leaving from the front gate and some sneak from the side gate. Now, we need to manage flow of people from both ends. This is where Deque comes into play.

Operations on Deque

Following are the major operations on Deque −

  • push_front(x): Insert element x at the front of the deque.
  • push_back(x): Insert element x at the back of the deque.
  • pop_front(): Remove the element from the front of the deque.
  • pop_back(): Remove the element from the back of the deque.
  • peek_front(): Get the element from the front of the deque.
  • peek_back(): Get the element from the back of the deque.
  • size(): Get the number of elements in the deque.
  • isEmpty(): Check if the deque is empty.

Implementation of Deque

Let's understand how we can implement deque using array. For this, we need to maintain two pointers, front and rear, to keep track of the front and back of the deque. We also need to define the size of the deque.

The push_front(x) Operation on Deque

When we insert an element at the front of the deque, we need to shift all the elements to the right by one position. We will increment the front pointer by one and insert the element at the front of the deque.

Algorithm for push_front(x)

Following are the steps to insert an element at the front of the deque −

 1. Check if the deque is full. If it is full, return an error message. 2. Increment the front pointer by one. 3. Insert the element at the front position. 4. Increment the size of the deque. 

implementation

Following is the implementation of push_front(x) operation on deque.

 #include <stdio.h> #include <stdlib.h> #define SIZE 5 int deque[SIZE]; int front = -1, rear = -1; // Check if the deque is full int isFull() { return (front == 0 && rear == SIZE - 1) || (front == rear + 1); } // Check if the deque is empty int isEmpty() { return front == -1; } // Insert element at the front void push_front(int element) { if (isFull()) { printf("Deque is full\n"); return; } if (isEmpty()) { // First element being inserted front = rear = 0; } else { // Circularly move front pointer front = (front - 1 + SIZE) % SIZE; } deque[front] = element; printf("Inserted -> %d\n", element); } // Display the deque void display() { if (isEmpty()) { printf("Empty Deque\n"); return; } int i = front; printf("Elements -> "); while (1) { printf("%d ", deque[i]); if (i == rear) break; // Stop at the last element i = (i + 1) % SIZE; // Circular increment } printf("\n"); } int main() { push_front(1); push_front(2); push_front(3); push_front(4); push_front(5); display(); return 0; } 

Output

The output obtained is as follows −

 Inserted -> 1 Inserted -> 2 Inserted -> 3 Inserted -> 4 Inserted -> 5 Elements -> 5 4 3 2 1 
 #include <iostream> using namespace std; #define SIZE 5 int deque[SIZE]; int front = -1, rear = -1; // Check if the deque is full bool isFull() { return (front == 0 && rear == SIZE - 1) || (front == rear + 1); } // Check if the deque is empty bool isEmpty() { return front == -1; } // Insert element at the front void push_front(int element) { if (isFull()) { cout << "Deque is full" << endl; return; } if (isEmpty()) { // First element being inserted front = rear = 0; } else if (front == 0) { // Wrap around front = SIZE - 1; } else { front--; } deque[front] = element; cout << "Inserted -> " << element << endl; } // Display the deque void display() { if (isEmpty()) { cout << "Empty Deque" << endl; return; } cout << "Elements -> "; int i = front; while (true) { cout << deque[i] << " "; if (i == rear) break; // Stop at last element i = (i + 1) % SIZE; // Circular increment } cout << endl; } int main() { push_front(1); push_front(2); push_front(3); push_front(4); push_front(5); display(); return 0; } 

Output

The output produced is as follows −

 Inserted -> 1 Inserted -> 2 Inserted -> 3 Inserted -> 4 Inserted -> 5 Elements -> 5 4 3 2 1 
 //Java Program class Deque { static final int SIZE = 5; static int deque[] = new int[SIZE]; static int front = -1, rear = -1; // Check if the deque is full static boolean isFull() { return (front == 0 && rear == SIZE - 1) || (front == rear + 1); } // Check if the deque is empty static boolean isEmpty() { if (front == -1) return true; return false; } // Insert element at the front static void push_front(int element) { if (isFull()) System.out.println("Deque is full"); if(isEmpty()) { front = rear = 0; }else { front = (front - 1 + SIZE) % SIZE; } deque[front] = element; System.out.println("Inserted -> " + element); } // Display the deque static void display() { if (isEmpty()) System.out.println("Empty Deque"); System.out.print("Elements -> "); int i = front; while (true) { System.out.print(deque[i] + " "); if (i == rear) break; i = (i + 1) % SIZE; } System.out.println(); } } public class Main{ public static void main(String[] args) { Deque deque = new Deque(); deque.push_front(1); deque.push_front(2); deque.push_front(3); deque.push_front(4); deque.push_front(5); deque.display(); } } 

Output

The output is as follows −

 Inserted -> 1 Inserted -> 2 Inserted -> 3 Inserted -> 4 Inserted -> 5 Elements -> 5 4 3 2 1 
 SIZE = 5 deque = [0] * SIZE front = -1 rear = -1 # Check if the deque is full def isFull(): return (front == 0 and rear == SIZE - 1) or (front == rear + 1) # Check if the deque is empty def isEmpty(): return front == -1 # Insert element at the front def push_front(element): global front, rear if isFull(): print("Deque is full") if isEmpty(): front = rear = 0 else: front = (front - 1 + SIZE) % SIZE deque[front] = element print("Inserted ->", element) # Display the deque def display(): global front, rear if isEmpty(): print("Empty Deque") else: i = front print("Elements ->", end=" ") while i != rear: print(deque[i], end=" ") i = (i + 1) % SIZE print(deque[rear]) # Print the last element # Testing the functions push_front(1) push_front(2) push_front(3) push_front(4) push_front(5) display() 

Output

Following is the output of the above code −

 Inserted -> 1 Inserted -> 2 Inserted -> 3 Inserted -> 4 Inserted -> 5 Elements -> 5 4 3 2 1 

push_back(x) Operation

This operation is used for inserting an element to the back of the deque. When we insert an element at the back of the deque, we need to increment the rear pointer by one and insert the element at the back of the deque.

Algorithm for push_back(x)

Following are the steps to insert an element at the back of the deque −

 1. Check if the deque is full. 2. Increment the rear pointer by one. 3. Insert the element at the rear position. 4. Increment the size of the deque. 

Implementation

Following is the implementation of push_back(x) operation on deque.

 //C Program #include <stdio.h> #include <stdlib.h> #define SIZE 5 int deque[SIZE]; int front = -1, rear = -1; // Check if the deque is full int isFull() { return ((front == 0 && rear == SIZE - 1) || (front == rear + 1)); } // Check if the deque is empty int isEmpty() { return (front == -1); } // Insert element at the back void push_back(int element) { if (isFull()) { printf("Deque is full\n"); } else { if (front == -1) { // If deque is initially empty front = rear = 0; } else if (rear == SIZE - 1) { // Wrap around to the front rear = 0; } else { rear++; } deque[rear] = element; printf("Inserted -> %d\n", element); } } // Display the deque void display() { if (isEmpty()) { printf("Empty Deque\n"); } else { printf("Elements -> "); int i = front; while (1) { printf("%d ", deque[i]); if (i == rear) break; // Stop when the rear is reached i = (i + 1) % SIZE; // Circular increment } printf("\n"); } } // Main function int main() { push_back(1); push_back(2); push_back(3); push_back(4); push_back(5); display(); return 0; } 

Output

The output obtained is as follows −

 Inserted -> 1 Inserted -> 2 Inserted -> 3 Inserted -> 4 Inserted -> 5 Elements -> 1 2 3 4 5 
 #include <iostream> using namespace std; #define SIZE 5 int deque[SIZE]; int front = -1, rear = -1; // Check if the deque is full bool isFull() { return (front == 0 && rear == SIZE - 1) || (front == rear + 1); } // Check if the deque is empty bool isEmpty() { return front == -1; } // Insert element at the back void push_back(int element) { if (isFull()) { cout << "Deque is full" << endl; } else { if (front == -1) { // First insertion front = 0; rear = 0; } else if (rear == SIZE - 1 && front != 0) { // Wrap around rear = 0; } else { // Normal case rear++; } deque[rear] = element; cout << "Inserted -> " << element << endl; } } // Display the deque void display() { if (isEmpty()) { cout << "Empty Deque" << endl; } else { cout << "Elements -> "; int i = front; while (true) { cout << deque[i] << " "; if (i == rear) break; // Stop when the last element is printed i = (i + 1) % SIZE; // Move circularly } cout << endl; } } int main() { push_back(1); push_back(2); push_back(3); push_back(4); push_back(5); display(); return 0; } 

Output

The output produced is as follows −

 Inserted -> 1 Inserted -> 2 Inserted -> 3 Inserted -> 4 Inserted -> 5 Elements -> 1 2 3 4 5 
 //Java Program class Deque { static final int SIZE = 5; static int deque[] = new int[SIZE]; static int front = -1, rear = -1; // Check if the deque is full static boolean isFull() { if ((front == 0 && rear == SIZE - 1) || front == rear + 1) return true; return false; } // Check if the deque is empty static boolean isEmpty() { if (front == -1) return true; return false; } // Insert element at the back static void push_back(int element) { if (isFull()) System.out.println("Deque is full"); else { if (front == -1) front = 0; if (rear == SIZE - 1) rear = 0; else rear = rear + 1; deque[rear] = element; System.out.println("Inserted -> " + element); } } // Display the deque static void display() { int i = front; if (isEmpty()) System.out.println("Empty Deque"); else { System.out.print("Elements -> "); for (i = front; i != rear; i = (i + 1) % SIZE) { System.out.print(deque[i] + " "); } System.out.print(deque[i]); } } } public class Main{ public static void main(String[] args) { Deque deque = new Deque(); deque.push_back(1); deque.push_back(2); deque.push_back(3); deque.push_back(4); deque.push_back(5); deque.display(); } } 

Output

The output is as follows −

 Inserted -> 1 Inserted -> 2 Inserted -> 3 Inserted -> 4 Inserted -> 5 Elements -> 1 2 3 4 5 
 #Python Program SIZE = 5 deque = [0] * SIZE front = -1 rear = -1 # Check if the deque is full def isFull(): if (front == 0 and rear == SIZE - 1) or (front == rear + 1): return True return False # Check if the deque is empty def isEmpty(): if front == -1: return True return False # Insert element at the back def push_back(element): global front, rear if isFull(): print("Deque is full") else: if front == -1: # Initial insertion front = 0 rear = 0 elif rear == SIZE - 1 and front != 0: # Wrap around rear = 0 else: # Normal case rear += 1 deque[rear] = element print("Inserted ->", element) # Display the deque def display(): global front, rear if isEmpty(): print("Empty Deque") else: print("Elements ->", end=" ") i = front while True: print(deque[i], end=" ") if i == rear: # Stop when we reach the last element break i = (i + 1) % SIZE # Move to the next index, circularly print() # Test the deque push_back(1) push_back(2) push_back(3) push_back(4) push_back(5) display() 

Output

Following is the output of the above code −

 Inserted -> 1 Inserted -> 2 Inserted -> 3 Inserted -> 4 Inserted -> 5 Elements -> 1 2 3 4 5 

The pop_front() and pop_back() Operations on Deque

These operation is done when we need to remove elements from front or back. When we remove an element from the front of the deque, we need to increment the front pointer by one.

Similarly, when we remove an element from the back of the deque, we need to decrement the rear pointer by one.

Algorithm for pop_front() and pop_back()

Following are the steps to remove an element from the front or back of the deque −

 1. Check if the deque is empty. 2. Remove the element from the front or back of the deque. 3. Increment or decrement the front or rear pointer. 4. Decrement the size of the deque. 

Implementation

Following is the implementation of pop_front() and pop_back() operations on deque.

 //C Program #include <stdio.h> #include <stdlib.h> #define SIZE 5 int deque[SIZE]; int front = -1, rear = -1; // Check if the deque is full int isFull() { return ((front == 0 && rear == SIZE - 1) || (front == rear + 1)); } // Check if the deque is empty int isEmpty() { return (front == -1); } // Insert element at the back void push_back(int element) { if (isFull()) { printf("Deque is full\n"); } else { if (front == -1) { // If deque is initially empty front = rear = 0; } else if (rear == SIZE - 1) { // Wrap around to the front rear = 0; } else { rear++; } deque[rear] = element; printf("Inserted -> %d\n", element); } } // Remove element from the front void pop_front() { if (isEmpty()) { printf("Deque is empty\n"); } else { printf("Deleted from front -> %d\n", deque[front]); if (front == rear) { // If only one element is present front = rear = -1; } else { front = (front + 1) % SIZE; } } } // Remove element from the back void pop_back() { if (isEmpty()) { printf("Deque is empty\n"); } else { printf("Deleted from back -> %d\n", deque[rear]); if (front == rear) { // If only one element is present front = rear = -1; } else if (rear == 0) { rear = SIZE - 1; } else { rear--; } } } // Display the deque void display() { if (isEmpty()) { printf("Empty Deque\n"); } else { printf("Elements -> "); int i = front; while (1) { printf("%d ", deque[i]); if (i == rear) break; // Stop when the rear is reached i = (i + 1) % SIZE; // Circular increment } printf("\n"); } } // Main function int main() { push_back(1); push_back(2); push_back(3); push_back(4); push_back(5); pop_front(); pop_back(); display(); return 0; } 

Output

The output obtained is as follows −

 Inserted -> 1 Inserted -> 2 Inserted -> 3 Inserted -> 4 Inserted -> 5 Deleted -> 1 Deleted -> 5 
 //C++ Program #include <iostream> using namespace std; #define SIZE 5 int deque[SIZE]; int front = -1, rear = -1; // Check if the deque is full bool isFull() { if ((front == 0 && rear == SIZE - 1) || front == rear + 1) return true; return false; } // Check if the deque is empty bool isEmpty() { if (front == -1) return true; return false; } // Insert element at the back void push_back(int element) { if (isFull()) cout << "Deque is full" << endl; else { if (front == -1) front = 0; if (rear == SIZE - 1) rear = 0; else rear = rear + 1; deque[rear] = element; cout << "Inserted -> " << element << endl; } } // Remove element from the front void pop_front() { if (isEmpty()) cout << "Deque is empty" << endl; else { cout << "Deleted from front -> " << deque[front] << endl; if (front == rear) front = rear = -1; else front = (front + 1) % SIZE; } } // Remove element from the back void pop_back() { if (isEmpty()) cout << "Deque is empty" << endl; else { cout << "Deleted from back -> " << deque[rear] << endl; if (front == rear) front = rear = -1; else if (rear == 0) rear = SIZE - 1; else rear = rear - 1; } } // Display the deque void display() { int i = front; if (isEmpty()) cout << "Empty Deque" << endl; else { cout << "Elements -> "; for (int i = front; i != rear; i = (i + 1) % SIZE) { cout << deque[i] << " "; } cout << deque[i]; } } int main() { push_back(1); push_back(2); push_back(3); push_back(4); push_back(5); pop_front(); pop_back(); display(); return 0; } 

Output

The output produced is as follows −

 Inserted -> 1 Inserted -> 2 Inserted -> 3 Inserted -> 4 Inserted -> 5 Deleted from front -> 1 Deleted from back -> 5 Elements -> 2 3 4 
 //Java Program class Deque { static final int SIZE = 5; static int deque[] = new int[SIZE]; static int front = -1, rear = -1; // Check if the deque is full static boolean isFull() { if ((front == 0 && rear == SIZE - 1) || front == rear + 1) return true; return false; } // Check if the deque is empty static boolean isEmpty() { if (front == -1) return true; return false; } // Insert element at the back static void push_back(int element) { if (isFull()) System.out.println("Deque is full"); else { if (front == -1) front = 0; if (rear == SIZE - 1) rear = 0; else rear = rear + 1; deque[rear] = element; System.out.println("Inserted -> " + element); } } // Remove element from the front static void pop_front() { if (isEmpty()) System.out.println("Deque is empty"); else { System.out.println("Deleted from front -> " + deque[front]); if (front == rear) front = rear = -1; else front = (front + 1) % SIZE; } } // Remove element from the back static void pop_back() { if (isEmpty()) System.out.println("Deque is empty"); else { System.out.println("Deleted from back -> " + deque[rear]); if (front == rear) front = rear = -1; else if (rear == 0) rear = SIZE - 1; else rear = rear - 1; } } // Display the deque static void display() { int i = front; if (isEmpty()) System.out.println("Empty Deque"); else { System.out.print("Elements -> "); for (i = front; i != rear; i = (i + 1) % SIZE) { System.out.print(deque[i] + " "); } System.out.print(deque[i]); } } } public class Main{ public static void main(String[] args) { Deque deque = new Deque(); deque.push_back(1); deque.push_back(2); deque.push_back(3); deque.push_back(4); deque.push_back(5); deque.pop_front(); deque.pop_back(); deque.display(); } } 

Output

The output is as follows −

 Inserted -> 1 Inserted -> 2 Inserted -> 3 Inserted -> 4 Inserted -> 5 Deleted from front -> 1 Deleted from back -> 5 Elements -> 2 3 4 
 #Python Program SIZE = 5 deque = [0] * SIZE front = -1 rear = -1 # Check if the deque is full def isFull(): if (front == 0 and rear == SIZE - 1) or front == rear + 1: return True return False # Check if the deque is empty def isEmpty(): if front == -1: return True return False # Insert element at the back def push_back(element): global front global rear if isFull(): print("Deque is full") else: if front == -1: front = 0 if rear == SIZE - 1: rear = 0 else: rear = rear + 1 deque[rear] = element print("Inserted ->", element) # Remove element from the front def pop_front(): global front global rear if isEmpty(): print("Deque is empty") else: print("Deleted from front ->", deque[front]) if front == rear: front = rear = -1 else: front = (front + 1) % SIZE # Remove element from the back def pop_back(): global front global rear if isEmpty(): print("Deque is empty") else: print("Deleted from back ->", deque[rear]) if front == rear: front = rear = -1 elif rear == 0: rear = SIZE - 1 else: rear = rear - 1 # Display the deque def display(): i = front if isEmpty(): print("Empty Deque") else: print("Elements ->", end = " ") while True: print(deque[i], end = " ") if i == rear: break i = (i + 1) % SIZE print(deque[rear]) push_back(1) push_back(2) push_back(3) push_back(4) push_back(5) pop_front() pop_back() display() 

Output

Following is the output of the above code −

 Inserted -> 1 Inserted -> 2 Inserted -> 3 Inserted -> 4 Inserted -> 5 Deleted from front -> 1 Deleted from back -> 5 Elements -> 2 3 4 

The peek_front() and peek_back() Operations on Deque

When we want to get the element from the front or back of the deque, we can use the peek_front() and peek_back() operations.

Algorithm for peek_front() and peek_back()

Following are the steps to get the element from the front or back of the deque −

 1. Check if the deque is empty. 2. If not empty, return the element from the front or back of the deque. 

Implementation

Following is the implementation code of peek_front() and peek_back() operations on deque.

 //C Program #include <stdio.h> #include <stdlib.h> #define SIZE 5 int deque[SIZE]; int front = -1, rear = -1; // Check if the deque is full int isFull() { return ((front == 0 && rear == SIZE - 1) || (front == rear + 1)); } // Check if the deque is empty int isEmpty() { return (front == -1); } // Insert element at the back void push_back(int element) { if (isFull()) { printf("Deque is full\n"); } else { if (front == -1) { // If deque is initially empty front = rear = 0; } else if (rear == SIZE - 1) { // Wrap around to the front rear = 0; } else { rear++; } deque[rear] = element; printf("Inserted -> %d\n", element); } } // Get the element from the front int peek_front() { if (isEmpty()) { printf("Deque is empty\n"); return -1; } else { return deque[front]; } } // Get the element from the back int peek_back() { if (isEmpty()) { printf("Deque is empty\n"); return -1; } else { return deque[rear]; } } // Main function int main() { push_back(1); push_back(2); push_back(3); push_back(4); push_back(5); printf("\nElement at front: %d\n", peek_front()); printf("Element at back: %d\n", peek_back()); return 0; } 

Output

The output obtained is as follows −

 Inserted -> 1 Inserted -> 2 Inserted -> 3 Inserted -> 4 Inserted -> 5 Element at front: 1 Element at back: 5 
 //C++ Program #include <iostream> using namespace std; #define SIZE 5 int deque[SIZE]; int front = -1, rear = -1; // Check if the deque is full bool isFull() { if ((front == 0 && rear == SIZE - 1) || front == rear + 1) return true; return false; } // Check if the deque is empty bool isEmpty() { if (front == -1) return true; return false; } // Insert element at the back void push_back(int element) { if (isFull()) cout << "Deque is full" << endl; else { if (front == -1) front = 0; if (rear == SIZE - 1) rear = 0; else rear = rear + 1; deque[rear] = element; cout << "Inserted -> " << element << endl; } } // Get the element from the front int peek_front() { if (isEmpty()) { cout << "Deque is empty" << endl; return -1; } else { return deque[front]; } } // Get the element from the back int peek_back() { if (isEmpty()) { cout << "Deque is empty" << endl; return -1; } else { return deque[rear]; } } int main() { push_back(1); push_back(2); push_back(3); push_back(4); push_back(5); cout << "\nElement at front: " << peek_front() << endl; cout << "Element at back: " << peek_back() << endl; return 0; } 

Output

The output produced is as follows −

 Inserted -> 1 Inserted -> 2 Inserted -> 3 Inserted -> 4 Inserted -> 5 Element at front: 1 Element at back: 5 
 //Java Program class PeekFrontAndBack{ static final int SIZE = 5; static int deque[] = new int[SIZE]; static int front = -1, rear = -1; // Check if the deque is full static boolean isFull() { if ((front == 0 && rear == SIZE - 1) || front == rear + 1) return true; return false; } // Check if the deque is empty static boolean isEmpty() { if (front == -1) return true; return false; } // Insert element at the back static void push_back(int element) { if (isFull()) System.out.println("Deque is full"); else { if (front == -1) front = 0; if (rear == SIZE - 1) rear = 0; else rear = rear + 1; deque[rear] = element; System.out.println("Inserted -> " + element); } } // Get the element from the front static int peek_front() { if (isEmpty()) { System.out.println("Deque is empty"); return -1; } else { return deque[front]; } } // Get the element from the back static int peek_back() { if (isEmpty()) { System.out.println("Deque is empty"); return -1; } else { return deque[rear]; } } } public class Main{ public static void main(String[] args) { PeekFrontAndBack deque = new PeekFrontAndBack(); deque.push_back(1); deque.push_back(2); deque.push_back(3); deque.push_back(4); deque.push_back(5); System.out.println("\nElement at front: " + deque.peek_front()); System.out.println("Element at back: " + deque.peek_back()); } } 

Output

The output is as follows −

 Inserted -> 1 Inserted -> 2 Inserted -> 3 Inserted -> 4 Inserted -> 5 Element at front: 1 Element at back: 5 
 #Python Program SIZE = 5 deque = [0] * SIZE front = -1 rear = -1 # Check if the deque is full def isFull(): if (front == 0 and rear == SIZE - 1) or front == rear + 1: return True return False # Check if the deque is empty def isEmpty(): if front == -1: return True return False # Insert element at the back def push_back(element): global front global rear if isFull(): print("Deque is full") else: if front == -1: front = 0 if rear == SIZE - 1: rear = 0 else: rear = rear + 1 deque[rear] = element print("Inserted ->", element) # Get the element from the front def peek_front(): if isEmpty(): print("Deque is empty") return -1 else: return deque[front] # Get the element from the back def peek_back(): if isEmpty(): print("Deque is empty") return -1 else: return deque[rear] push_back(1) push_back(2) push_back(3) push_back(4) push_back(5) print("\nElement at front:", peek_front()) print("Element at back:", peek_back()) 

Output

Following is the output of the above code −

 Inserted -> 1 Inserted -> 2 Inserted -> 3 Inserted -> 4 Inserted -> 5 Element at front: 1 Element at back: 5 

Time Complexity of Deque Operations

The time complexity of the deque operations is as follows −

  • push_front(x) − O(1)
  • push_back(x) − O(1)
  • pop_front() − O(1)
  • pop_back() − O(1)
  • peek_front() − O(1)
  • peek_back() − O(1)

Thus, the deque operations have a time complexity of O(1).

Applications of Deque

Some of the applications of deque are as follows −

  • Deque is used for undo operation in text editors.
  • It is also used in implementation of the sliding window algorithm.
  • Deque is used in implementing the data structures like double-ended priority queue and double-ended stack.

In summary, we use deque when we need to perform insertion and deletion operations at both ends of the data structure.

Advertisements
close