No history yet

Introduction to C++ Queues

The First-In-First-Out Principle

In programming, a queue is a data structure that follows the First-In, First-Out (FIFO) principle. Think of a line at a ticket counter. The first person to get in line is the first person to buy a ticket. New people join at the back of the line and are served only after everyone in front of them.

This simple, fair system is exactly how a queue works. The first element added to the queue is the first one to be removed.

Lesson image

In C++, you can implement a queue using the std::queue container adapter from the <queue> header. It's called an "adapter" because it doesn't implement its own data structure from scratch. Instead, it wraps another container, like std::deque or std::list, and provides a specific queue-like interface to interact with it.

Core Queue Operations

A std::queue provides a few key functions to manage its elements. You don't get direct access to items in the middle of the queue; you can only interact with the front and back.

  • push(): Adds a new element to the back of the queue.
  • pop(): Removes the element from the front of the queue.
  • front(): Accesses the element at the front without removing it.
  • back(): Accesses the element at the back without removing it.
  • empty(): Checks if the queue is empty.
  • size(): Returns the number of elements in the queue.

Let's see these operations in action.

#include <iostream>
#include <queue>

int main() {
    std::queue<int> numbers;

    // Add elements to the queue
    numbers.push(10);
    numbers.push(20);
    numbers.push(30);

    std::cout << "Front element is: " << numbers.front() << std::endl; // 10
    std::cout << "Back element is: " << numbers.back() << std::endl;   // 30

    // Remove the front element
    numbers.pop();

    std::cout << "New front element is: " << numbers.front() << std::endl; // 20

    std::cout << "Queue size: " << numbers.size() << std::endl;

    return 0;
}

In the example, we first push 10, 20, and 30 into the queue. The element 10 is at the front and 30 is at the back. When we call pop(), the 10 is removed, and 20 becomes the new front element.

Underlying Container and Performance

As mentioned, std::queue is a container adapter. By default, it uses std::deque (a double-ended queue) as its underlying container. This is a great choice because std::deque is highly efficient at adding elements to the back (push_back) and removing them from the front (pop_front).

You can also specify std::list as the container, like this: std::queue<int, std::list<int>> my_list_queue;. A std::list also provides efficient insertions and deletions at both ends.

However, you cannot use std::vector as the underlying container for a queue. While a vector is efficient at adding elements to the back, removing an element from the front is very slow. It requires shifting all other elements one position to the left, which is an O(N)O(N) operation. The design of std::queue requires an underlying container with an efficient pop_front (or equivalent) operation, which std::vector lacks.

The choice of underlying container matters. For std::queue, the default std::deque provides the best balance of performance for typical queue operations.

Now, let's test your understanding of how queues work.

Quiz Questions 1/5

A queue data structure is best known for following which principle?

Quiz Questions 2/5

Consider the following C++ code snippet:

std::queue<int> q;
q.push(5);
q.push(10);
q.push(15);
q.pop();
q.push(20);

After this code executes, what is the value at the front of the queue?

Queues are a fundamental tool, especially in areas like scheduling tasks, handling requests on a web server, or implementing breadth-first search algorithms in graphs.