Back to C++
2025-11-286 min read

C++ Deque

Learn C++ Deque step by step with clear examples and exercises.

Why This Matters

Understanding and mastering the use of C++ deques is essential for any serious C++ programmer. Deques, or double-ended queues, provide a flexible solution to handling data structures that require frequent additions and removals at both ends. They offer numerous advantages over traditional stacks and queues, making them an invaluable tool for solving complex problems in competitive programming, system design, and algorithmic challenges.

Prerequisites

To make the most of this tutorial, you should have a solid understanding of:

  1. Basic C++ syntax and data structures (arrays, vectors, and lists)
  2. Object-oriented programming concepts (classes, inheritance, and polymorphism)
  3. Standard Template Library (STL) basics (iterators, algorithms, and containers)
  4. Understanding of big O notation for time complexity analysis
  5. Familiarity with basic STL containers such as vectors, lists, and arrays

Core Concept

A deque is a double-ended queue that allows insertion and removal of elements from both ends. It is part of the STL container library and can be easily implemented using the deque template class. Here's an overview of its key features:

  1. Dynamic size: The size of a deque can grow or shrink dynamically as elements are added or removed, making it more efficient than fixed-size data structures like arrays.
  2. Random access: Deques support random access to their elements using iterators, allowing for efficient traversal and manipulation of the sequence. This feature makes deques more flexible compared to linked lists.
  3. Efficient insertion and deletion: Inserting and deleting elements from either end of a deque is faster than in traditional queues and stacks due to its doubly-linked list implementation. This efficiency is particularly useful when dealing with large data sets or dynamic data structures.
  4. Iterators: Deques support bidirectional iterators, allowing for traversal in both directions (forward and backward). This feature allows for efficient iteration over the deque's contents, making it a versatile choice for various programming tasks.
  5. Time Complexity: The time complexity of common operations on a deque is as follows:
  • Insertion at either end: O(1)
  • Deletion at either end: O(1)
  • Access (iteration): O(n)
  • Iterator insertion: O(n)

Worked Example

Let's create a simple program that demonstrates the use of deques and compares its performance with vectors in terms of inserting and deleting elements at both ends.

#include <iostream>
#include <deque>
#include <vector>
#include <chrono>
#include <random>

void fillDeque(std::deque<int>& deque, int size) {
std::default_random_engine generator;
std::uniform_int_distribution<int> distribution(1, 100);

for (int i = 0; i < size; ++i) {
deque.push_back(distribution(generator));
}
}

void fillVector(std::vector<int>& vector, int size) {
std::default_random_engine generator;
std::uniform_int_distribution<int> distribution(1, 100);

vector.resize(size);
for (auto& elem : vector) {
elem = distribution(generator);
}
}

void printDeque(const std::deque<int>& deque) {
std::cout << "[";
if (!deque.empty()) {
auto it = deque.cbegin();
std::cout << *it;
++it;

for (; it != deque.cend(); ++it) {
std::cout << ", " << *it;
}
}
std::cout << "]";
}

void printVector(const std::vector<int>& vector) {
std::cout << "[";
if (!vector.empty()) {
auto it = vector.cbegin();
std::cout << *it;
++it;

for (; it != vector.cend(); ++it) {
std::cout << ", " << *it;
}
}
std::cout << "]";
}

int main() {
const int size = 1000000;
std::deque<int> deque;
std::vector<int> vector;

fillDeque(deque, size);
fillVector(vector, size);

auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < size; ++i) {
deque.push_back(i + 1);
}
auto end = std::chrono::high_resolution_clock::now();
auto dequeInsertTime = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();

start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < size; ++i) {
deque.push_front(i + 1);
}
end = std::chrono::high_resolution_clock::now();
auto dequeFrontInsertTime = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();

start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < size; ++i) {
deque.pop_back();
}
end = std::chrono::high_resolution_clock::now();
auto dequePopBackTime = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();

start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < size; ++i) {
deque.pop_front();
}
end = std::chrono::high_resolution_clock::now();
auto dequePopFrontTime = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();

printDeque(deque);
std::cout << "\nVector Insertion Time: " << vector.size() * 2 << "ms\n";
std::cout << "Deque Front Insertion Time: " << dequeFrontInsertTime << "ms\n";
std::cout << "Deque Back Insertion Time: " << dequeInsertTime << "ms\n";
std::cout << "Deque Pop Front Time: " << dequePopFrontTime << "ms\n";
std::cout << "Deque Pop Back Time: " << dequePopBackTime << "ms\n";

return 0;
}

This program creates a deque and a vector, fills them with random integers, and measures the time it takes to insert elements at both ends and remove elements from both ends using deques. It then compares these times with the time it would take to perform the same operations on vectors.

Common Mistakes

  1. Forgetting to include the `` header: Remember to include the deque header at the beginning of your code to use the deque template class.
  2. Incorrect usage of push/pop functions: Be sure to use push_back(), push_front(), pop_back(), and pop_front() for adding and removing elements from the appropriate ends.
  3. Confusing deques with other containers: Deques are not a replacement for arrays, vectors, or lists but rather an alternative for handling specific use cases that require frequent additions and removals from either end.
  4. Ignoring time complexity: While deques offer fast insertion and deletion at both ends, it's essential to consider the time complexity of other operations like access and iteration when choosing between deques and other containers.
  5. Not handling empty or full deques: Be sure to check if a deque is empty before performing operations that require elements, and handle cases where the operation is not possible (e.g., inserting into a full deque).

Practice Questions

  1. Write a program that implements a simple implementation of a deque-based stack using the deque template class. Test your solution by pushing several elements onto the stack, popping them off in the correct order, and printing the remaining elements (if any).
  2. Implement a function that takes a deque as input and returns the maximum element in the deque using only iterators (no additional data structures or functions like max_element()).
  3. Write a program that uses a deque to implement a circular buffer with a fixed size of 5 elements. Test your solution by filling the buffer, emptying it, and repeating the process multiple times.
  4. Compare the performance of deques with vectors in terms of inserting and deleting elements at both ends for various data sizes (e.g., 100, 1000, 10000, and 100000 elements).
  5. Implement a function that takes a deque as input and returns the average value of its elements using only iterators (no additional data structures or functions like accumulate()).
  6. Write a program that uses a deque to implement a priority queue with custom priorities. Test your solution by adding several elements with different priorities, removing the highest-priority element, and printing the remaining elements in order of their priorities.

FAQ

  1. Why should I use a deque instead of a vector or list? Deques offer faster insertion and deletion at both ends compared to vectors and lists, making them more efficient for specific use cases that require frequent additions and removals from either end. However, for operations like iteration and access, vectors may be more suitable due to their better time complexity.
  2. Can I use iterators with deques? Yes! Deques support bidirectional iterators, allowing for traversal in both directions (forward and backward). This feature allows for efficient iteration over the deque's contents, making it a versatile choice for various programming tasks.
  3. What happens if I try to insert an element into a full deque or remove an element from an empty one? Attempting to add an element to a full deque or remove an element from an empty one will result in a runtime error. To prevent this, you can check the size of the deque before performing these operations and handle the case where the operation is not possible.
  4. Is it possible to use deques for implementing other data structures like stacks and queues? Yes! Deques can be used as an efficient alternative to implement stacks and queues, depending on the specific requirements of your use case.
  5. Can I customize the memory allocation strategy for deques? Unlike vectors, deques do not provide a direct way to customize their memory allocation strategy. However, you can achieve this by using a custom allocator with the deque template class.
C++ Deque | C++ | XQA Learn