C++ Deque - C++ Programming Tutorial

C++ Deque

BLUF: Mastering C++ Deque is a critical step in becoming a proficient C++ developer. This lesson provides a deep dive into the syntax, performance considerations, and real-world applications of this concept.
Key Performance Insight: C++ Deque

C++ is renowned for its efficiency. Learn how C++ Deque enables low-level control and high-performance computing in the tutorial below.

In C++, the deque, short for Double-Ended Queue, functions as a type of queue where elements are insertable and removable from both the front and the back. This data structure caters to both First-In-First-Out (FIFO) and Last-In-First-Out (LIFO) operations, providing a more versatile alternative to traditional queues. Within the realm of C++, the STL deque is recognized as a linear container that enables the swift addition and elimination of elements at both ends of the queue.

Unlike a standard queue that restricts insertion to the back and removal from the front, a deque offers greater versatility with operations possible at both ends. Additionally, it facilitates element retrieval through index positions, making it well-suited for situations requiring random access and resizing on the fly. To utilize a deque container, the inclusion of the \<deque\> header file is essential.

Syntax

It has the following syntax:

Example

deque<object_type> deque_name;

In this syntax,

  • objecttype: The objecttype parameter determines the type of components that the deque will store, such as int, string, and custom class.
  • deque_name: It represents the name of the identifier and variable that is assigned to deque.
  • ;: It ends the statement according to C++ syntax instructions.
  • Simple C++ Deque Example

Let's consider a scenario to demonstrate the deque data structure in C++.

Example

Example

#include <iostream>

#include <deque>  //using deque header file

using namespace std; //using standard namespace

int main() {  //Main Function

    

    // Creating a deque of 5 elements

    deque<int> dq = {7, 8, 5, 1, 2, 9};

    

    for (auto a: dq)

        cout << a << " "; //prints the deque elements

    return 0;

}

Output:

Output

7 8 5 1 2 9

Explanation

In this instance, we establish a deque containing integers with an initial set of six elements: {7, 8, 5, 1, 2, 9}. Employing a range-based for loop, the program traverses the deque and displays each element with spaces in between. Subsequently, the deque offers rapid insertions and removals from both ends, enhancing its versatility compared to arrays or vectors in specific situations.

Basic operations on Deque

Various actions are carried out on a deque in C++. A few of these include:

1) Creating and Inserting Elements in a Deque:

In declaring a deque, you will utilize the deque keyword followed by the data type enclosed in angle brackets (< >), along with the chosen variable identifier. The Standard Template Library (STL) includes the deque as a data structure that facilitates rapid additions and removals at both the front and back ends.

In C++ deque, we have the ability to add and remove elements at both ends by utilizing the pushback and pushfront functions. When there is a need to insert an element at a particular position within the deque, the insert method can be employed.

Example of Creating and Inserting Element on Deque

Let's consider an example to generate and add elements to a deque container in C++.

Example

Example

#include <iostream>

#include <deque>  // for deque container

using namespace std;  //using standard namespace

int main() {  //main function

    // Creating an empty deque of integers

    deque<int> dq;

    // Inserting elements at the back

    dq.push_back(15);

    dq.push_back(18);

    // Inserting elements at the front

    dq.push_front(7);

    dq.push_front(5);

    // Using emplace_back

    dq.emplace_back(27);

    // Using emplace_front

    dq.emplace_front(1);

    cout << "Deque elements are: ";  //Print the deque elements

    for (int a : dq) {

        cout << a << " ";

    }

    return 0;

}

Output:

Output

Deque elements are: 1 5 7 15 18 27

Explanation

In this instance, we are demonstrating the utilization of the pushfront method to add a value at the start and the pushback method to add a value at the end. Following this, the emplacefront and emplaceback functions perform similarly to pushfront and pushback, but they offer greater efficiency when adding temporary or constructed values directly.

2) Accessing the Elements in a Deque

Deque elements can be directly accessed using index notation represented by square brackets. Deques follow a 0-indexed system where the initial element is at index 0, the subsequent element is at index 1, and so forth. This feature enables efficient and effortless retrieval of elements from specific positions in the container. Additionally, deques provide the front and back functions for convenient access to the initial and final elements in the sequence.

Example of Accessing the Elements in a Deque

Now, let's examine a C++ illustration of retrieving the elements in a deque.

Example

Example

#include <iostream>

#include <deque>

using namespace std;

int main() 

{

deque<string> socialmedia_apps = {"Snapchat", "Twitter", "Whatsapp", "Instagram"};

    cout << "App at index 0 is: " << socialmedia_apps[0] << endl;

    cout << "App at index 1 is: " << socialmedia_apps[1] << endl;

    cout << "The first app (front) is: " << socialmedia_apps.front() << endl;

    cout << "The last app (back) is: " << socialmedia_apps.back() << endl;

    cout << "App at index 2 (using at()) is: " << socialmedia_apps.at(2) << endl;

    cout << "App at index 3 (using at()) is: " << socialmedia_apps.at(3) << endl;

    return 0;

}

Output:

Output

App at index 0 is: Snapchat

App at index 1 is: Twitter

The first app (front) is: Snapchat

The last app (back) is: Instagram

App at index 2 (using at()) is: Whatsapp

App at index 3 (using at()) is: Instagram

Explanation

In this instance, we create a deque named socialmedia_apps that holds a collection of social networking app names and illustrates retrieving its elements using index notation, front, back, and the at method. Subsequently, it showcases each available item in the console.

3) Modifying the Deque Element

To modify the value of a particular element within a deque, you can utilize square brackets along with the at method. These functionalities provide a direct pathway to both the position of an element and the ability to substitute its value. Although the operator enables quicker access, the at method ensures greater safety by conducting boundary validations and raising an exception when the index exceeds the valid range.

Example of Modifying the Deque Element

Now, let's examine a C++ illustration of altering the deque element.

Example

Example

#include <iostream>

#include <deque>

using namespace std;

int main() 

{

    deque<string>names_of_fruits = {"Mango", "Apple", "Watermelon", "Musk melon"};

    names_of_fruits[0] = "Pomegranate";

    names_of_fruits.at(1) = "Custard Apple";

    names_of_fruits.push_front("Banana");

    names_of_fruits.push_back("Grapes");

    names_of_fruits.pop_front();

    names_of_fruits.pop_back();

    cout << "Updated list of the Fruitnames:\n";

    for (const string& a : names_of_fruits) 

    {

        cout << a << endl;

    }

    return 0;

}

Output:

Output

Updated list of the Fruitnames:

Pomegranate

Custard Apple

Watermelon

Musk melon

Explanation

In this instance, we create a deque containing names of fruits by employing the index access operator as well as the at method. Subsequently, we add "Banana" to the front and "Grapes" to the rear of the deque.

4) Removing Elements from a Deque

In C++, the deque data structure enables efficient removal operations from both the front and back of the queue. To eliminate the element at the front, the popfront method is employed, whereas for the element at the rear, the popback function is utilized. These methods effectively erase the specific elements without any return value.

Example of Removing Elements from a Deque

Now, let's examine a C++ illustration of deleting elements from a deque.

Example

Example

#include <deque>

#include <iostream>

#include <string>

int main() 

{

    std::deque<std::string> s = {

        "Volvo", "BMW", "Ford", "Mazda"

    };

    std::cout << "The Service Queue elements are:\n";

    for (const auto& request: s)

    {

        std::cout << request << std::endl;

    }

    s.pop_front();  

    s.pop_back();   

    std::cout << "The updated Service Queue elements are:\n";

    for (const auto& request: s) 

    {

        std::cout << request << std::endl;

    }

    return 0;

}

Output:

Output

The Service Queue elements are:

Volvo

BMW

Ford

Mazda

The updated Service Queue elements are:

BMW

Ford

Explanation

In this instance, we illustrate the usage of a deque to manage a queue for servicing car brands. Subsequently, it displays the entirety of the items in the queue prior to eliminating the initial and final entries by employing popfront and popback.

5) Deque Size

In C++, the size function provides the count of elements currently stored in a deque container. This operation has a constant time complexity and is beneficial for monitoring queue size. It plays a crucial role in controlling logic, facilitating iteration, and reporting status in practical software implementations.

Example of Deque Size:

Now, let's look at a C++ example of deque size.

Example

Example

#include <iostream>

#include <deque>

using namespace std;  //using standard namespace

int main()   //Main Function

{

    deque<string> patients_names = {"John", "Joseph", "Jacob", "Charles"};

    cout << "Number of patients waiting: " << patients_names.size() << endl;

    return 0;

}

Output:

Output

Number of patients waiting: 4

Explanation

This serves as a demonstration of a patient lineup at a medical facility. The.size method reveals the current number of patients in the queue.

6) Check if a Deque is Empty

In C++, the empty function checks if a deque container holds any elements. It outputs true (1) for an empty deque and false (0) if it has elements. This function proves beneficial in situations that require immediate actions, like task execution, user interaction handling, and queue administration, only when the container is not empty.

C++ Example to Check if a Deque is Empty

Now, let's examine a C++ illustration of verifying whether a deque is devoid of elements.

Example

Example

#include <iostream>

#include <deque>

using namespace std;  //using standard namespace

int main()   //main function

{

    deque<string> returnbox;

    if (returnbox.empty()) 

        cout << "No books have been returned yet.\n";

    else 

        cout << "There are books in the return box.\n";

    return 0;

}

Output:

Output

No books have been returned yet.

Explanation

In this instance, a new deque named returnbox is instantiated as empty, and the empty method is employed to verify its element count. A message is displayed based on whether the return box holds any books.

7) Looping Through a Deque

A loop is employed to fetch and handle each item in a deque. The index-driven loop enables access based on position and is suitable when the exact element positions are crucial. On the other hand, the range-based for-each loop (introduced in C++11) enhances readability and is beneficial when the focus is solely on the elements.

Example of looping through a Deque

Now, let's examine a C++ illustration of iterating over a deque.

Example

Example

#include <iostream>

#include <deque>

#include <string>

using namespace std;  //using standard namespace

int main()   //Main Function

{

deque<string> medicines = {"Aspirin", "Vitamin D", "Antibiotic", "Cough Syrup"};

    cout << "Medication Schedule - (using an index-based loop):\n";

    for (int i = 0; i < medicines.size(); i++) 

    {

        cout << medicines[i] << endl;

    }

    cout << "Medication Schedule - (using a for-each loop):\n";

    for (const string& med : medicines) 

    {

        cout << med << endl;

    }

    return 0;

}

Output:

Output

Medication Schedule - (using an index-based loop):

Aspirin

Vitamin D

Antibiotic

Cough Syrup

Medication Schedule - (using a for-each loop):

Aspirin

Vitamin D

Antibiotic

Cough Syrup

Explanation

In this instance, we are generating a deque that holds a collection of medications. Initially, it displays the medicine timetable by utilizing an index-oriented for loop to retrieve elements by their positions. Following that, it showcases the identical list using a more streamlined for-each loop, which directly iterates through the elements.

C++ Deque Functions

The following table outlines various functions of Deque responsible for executing operations in C++.

Method Description
assign() It assigns new content and replacing the old one.
emplace() It adds a new element at a specified position.
emplace_back() It adds a new element at the end.
emplace_front() It adds a new element in the beginning of a deque.
insert() It adds a new element just before the specified position.
push_back() It adds a new element at the end of the container.
push_front() It adds a new element at the beginning of the container.
pop_back() It deletes the last element from the deque.
pop_front() It deletes the first element from the deque.
swap() It exchanges the contents of two deques.
clear() It removes all the contents of the deque.
empty() It checks whether the container is empty or not.
erase() It removes the elements.
max_size() It determines the maximum size of the deque.
resize() It changes the size of the deque.
shrinktofit() It reduces the memory to fit the size of the deque.
size() It returns the number of elements.
at() It access the element at position pos.
operator_PRESERVE22__ It access the element at position pos.
operator=() It assigns new contents to the container.
back() It access the last element.
begin() It returns an iterator to the beginning of the deque.
cbegin() It returns a constant iterator to the beginning of the deque.
end() It returns an iterator to the end.
cend() It returns a constant iterator to the end.
rbegin() It returns a reverse iterator to the beginning.
crbegin() It returns a constant reverse iterator to the beginning.
rend() It returns a reverse iterator to the end.
crend() It returns a constant reverse iterator to the end.
front() It access the last element.

Other Common Operations on Deque

Additional typical operations performed on a Deque in C++ include:

C++ Deque Iterators

In C++, the deque container enables the use of random-access iterators. These iterators have the capability to reference elements within the deque, allowing for traversal, modification, and access to elements in a manner similar to what is seen in a vector.

Syntax

Syntax for Declaring a Deque Iterator:

Example

deque<type>::iterator iterator_name;

C++ Deque Iterators Example

Now, let's examine a C++ illustration showcasing deque iterators.

Example

Example

#include <iostream>

#include <deque>

using namespace std;

int main() 

{

    deque<double> temperatures = {36.5, 37.0, 36.8, 37.2, 36.9};

    deque<double>::iterator q;

    cout << "Temperatures of the day:\n";

    for (q = temperatures.begin(); q!= temperatures.end(); ++q) 

    {

        cout << *q << "°C" << endl;

    }

    return 0;

}

Output:

Output

Temperature log for the day:

36.5°C

37°C

36.8°C

37.2°C

36.9°C

Explanation

In this instance, we start by creating a deque that stores temperatures as double values. We then define an iterator, denoted as q, to move through the deque using a for loop. As we iterate through the deque, each temperature is displayed along with the symbol "°C" indicating Celsius.

Accessing Elements using Deque Iterators

Deque iterators offer access to elements by referencing memory locations. These iterators can be repositioned anywhere using arithmetic operations (like begin + i) and the element can be retrieved by dereferencing with *.

Example of Accessing Elements using Deque Iterators

Now, let's explore a C++ illustration of accessing elements through deque iterators.

Example

Example

#include <iostream>

#include <deque>

using namespace std;

int main() 

{

    deque<int> IDs = {11, 12, 13};

    deque<int>::iterator q;

    q = IDs.begin();

    cout << "First ID: " << *q << endl;

    q = IDs.begin() + 1;

    cout << "Second ID: " << *q << endl;

    q = IDs.end() - 1;

    cout << "Last ID: " << *q << endl;

    return 0;

}

Output:

Output

First ID: 11

Second ID: 12

Last ID: 13

Explanation

In this instance, a deque containing integer IDs is established to access particular elements using the iterator q. It retrieves the initial, second, and final IDs by assigning the iterator to the correct positions through begin and end functions.

Time Complexity

The chart provided illustrates the time complexity of various operations executed on a deque.

Operation Time Complexity
Insert at back O(1)
Insert at front O(1)
Insert at arbitrary position O(n)
Remove from back O(1)
Remove from front O(1)
Remove from arbitrary position O(n)
Access element at any position using index O(1)
Update elements at any position using index O(1)
Iterate the deque O(n)

C++ Deque MCQS

1) Which header file is required to use deque in C++?

  • <vector>
  • <deque>
  • <array>
  • <list>

2) What is the time complexity of inserting an element at the front of a deque?

  • O(1)
  • O(n)
  • O(log n)
  • O(n log n)

3) Which function is used to remove the last element of a deque?

  • remove_back
  • delete_back
  • pop_back
  • erase_back

4) What does deque<int>::iterator represent?

  • An object
  • A pointer
  • An algorithm
  • An iterator for integer deque

5) Which of the following is true about deque?

  • It only supports push and pop at the back
  • It is implemented using arrays only
  • It supports random access iterators
  • It is slower than the list for insertion

Input Required

This code uses input(). Please provide values below:

Logic Practice
Install Logic Practice
Add to home screen for a faster app-like experience