Before anything, let me ask you something.
Before we learn about queues, try using the visualizer below and see if you can figure out how it works.
Now let's learn queues in the simplest way possible.
Imagine you're going to buy a movie ticket.
When you reach the ticket counter, you notice there are already five people waiting in line.
So, you join the back of the line and wait for your turn.
The first person in line buys their ticket and leaves.
Now, the second person moves to the front.
They buy their ticket and leave too.
This continues until everyone in front of you has bought their ticket.
Finally, you reach the front of the line and buy your ticket.
A queue works exactly the same way.
New elements are always added to the back of the queue.
Elements are always removed from the front of the queue.
That is why a queue follows the First In, First Out (FIFO) rule.
The first element added to the queue is always the first one to come out.
What is a Queue?
A queue is a data structure where elements are added at one end and removed from the other.
New elements are always added to the back of the queue.
Elements are always removed from the front of the queue.
Since the first element added is also the first one removed, a queue follows the First In, First Out (FIFO) rule.
Think of it just like waiting in line to buy a movie ticket.
The person who joins the line first gets served first, while everyone else waits for their turn.
Why can we only add at the back and remove from the front?
Imagine you're still waiting in line to buy a movie ticket.
Would it be fair if someone joined the line and went straight to the front?
Of course not.
Everyone has to wait for their turn.
That is why new people always join at the back of the line, while the person at the front gets served first.
A queue works the same way.
New elements are always added to the back of the queue.
Elements are always removed from the front of the queue.
This keeps the order fair, ensuring that the first element added is also the first one removed.
Queue Operations
Now that you know what a queue is, it's time to learn how to use one.
There are a few operations we can perform on a queue.
- Enqueue
- Dequeue
- Front
- Is Empty
- Size
Don't worry—we'll learn each one with simple examples and animations.
Let's start by creating our first queue.
How to Create a Queue
Before we can perform any operations, we first need to create a queue.
In C++, we can create one like this:
queue<int> q;
Let's break it down.
queue<int>
This creates a queue that stores integers.
If you want to store strings, you would write:
queue<string> q;
If you want to store characters, you would write:
queue<char> q;
The type inside < > tells C++ what kind of data the queue will store.
q
This is simply the name of our queue. You can name it anything you like.
Right now, our queue is empty.
Now let's add our first element using the Enqueue operation.
Enqueue
Before we start, try this visualizer to see how the Enqueue operation works.
Enqueue simply means adding an element to the queue.
In C++, we use the push() function to perform this operation.
For example, to add the value 10, we write:
q.push(10);
This adds 10 to the back of the queue.
Since our queue was empty, 10 becomes the first element.
Now let's add a few more elements.
q.push(20);
q.push(30);
q.push(40);
Each time we call push(), the new element is added to the back of the queue.
Now let's add one more element.
q.push(50);
Our queue now looks like this.
Notice that every new element is always added to the back of the queue.
push() always adds a new element to the back of the queue. Existing elements never change their order.
Time Complexity
To add an element, we simply place it at the back of the queue.
We don't have to move any other elements or search for a position.
Whether the queue has 1 element or 1,000 elements, it always takes just one step.
That is why the time complexity of Enqueue is O(1).
Great! Our queue now has a few elements. But queues aren't just for adding elements. Let's learn how to remove the first element using the Dequeue operation.
Dequeue
Before we start, try this visualizer to see how the Dequeue operation works.
Dequeue simply means removing an element from the queue.
In C++, we use the pop() function to perform this operation.
Suppose our queue looks like this.
To remove the first element, we write:
q.pop();
This removes 10 from the front of the queue.
Our queue now looks like this.
Notice that pop() always removes the front element.
We cannot remove an element from the middle or the back of the queue.
pop() always removes the element at the front.
Time Complexity
To remove an element, we simply remove the element at the front of the queue.
We don't have to search through the queue or move any other elements.
Whether the queue has 5 elements or 5,000 elements, it still takes just one step.
That is why the time complexity of Dequeue is O(1).
Now that we know how to remove elements, let's learn how to view the first element without removing it.
Front
Before we start, try this visualizer to see how the Front operation works.
Sometimes, we only want to see the first element in the queue without removing it.
For that, we use the front() function.
Suppose our queue looks like this.
To view the first element, we write:
q.front();
This returns the value 20, which is the first element in the queue.
Notice that nothing is removed.
Our queue still looks exactly the same.
The front() function only lets us view the first element. It does not remove it.
front() with pop(). front() only returns the first element, while pop() actually removes it.
Time Complexity
To view the first element, we simply look at the front of the queue.
We don't remove anything or search through the queue.
Whether the queue has 10 elements or 10,000 elements, it always takes just one step.
That is why the time complexity of Front is O(1).
Now let's learn how to check whether our queue is empty.
Is Empty
Before we start, try this visualizer to see how the Is Empty operation works.
Before removing or viewing an element, it's always a good idea to check whether the queue is empty.
After all, you can't remove or view an element if the queue doesn't have any!
To do this, we use the empty() function.
q.empty();
If the queue is empty, it returns true.
Otherwise, it returns false.
Suppose our queue looks like this.
If we write:
q.empty();
It returns false because the queue still contains elements.
Now imagine we remove every element from the queue.
If we call:
q.empty();
It returns true because the queue is now empty.
The empty() function only checks whether the queue is empty. It doesn't add or remove any elements.
front() or pop(), it's good practice to check empty() first. Trying to access an empty queue leads to undefined behavior.
Time Complexity
To check whether a queue is empty, we simply check if it contains any elements.
We don't need to go through the entire queue.
Whether the queue has 0 elements or 1,000 elements, it always takes just one step.
That is why the time complexity of Is Empty is O(1).
Now let's learn how to find the number of elements currently stored in the queue.
Size
Before we start, try this visualizer to see how the Size operation works.
Sometimes, we want to know how many elements are currently in the queue.
To find this, we use the size() function.
q.size();
This returns the total number of elements in the queue.
For example, suppose our queue looks like this.
If we write:
q.size();
It returns 4 because there are four elements in the queue.
Now let's add one more element.
q.push(60);
Our queue now looks like this.
If we call:
q.size();
It returns 5.
The size() function only tells us how many elements are in the queue. It doesn't add or remove any elements.
size() returns the current number of elements in the queue. It does not count them one by one every time you call it.
Time Complexity
To find the size of a queue, C++ already keeps track of the number of elements.
We don't have to count them one by one.
Whether the queue has 10 elements or 10,000 elements, it always takes just one step.
That is why the time complexity of Size is O(1).
Full Queue Code
Here's everything we've learned put together into one simple program.
#include <iostream>
#include <queue>
using namespace std;
int main() {
queue<int> q;
q.push(10);
q.push(20);
q.push(30);
q.push(40);
cout << "Front: " << q.front() << endl;
cout << "Size: " << q.size() << endl;
q.pop();
cout << "Front after pop: " << q.front() << endl;
if(q.empty()) {
cout << "Queue is empty";
} else {
cout << "Queue is not empty";
}
return 0;
}
Where Are Queues Used?
You might be wondering...
Where are queues actually used?
Queues are used in many applications you use every day.
Printer Queue
Documents are printed in the same order they are sent to the printer.
Waiting in Line
Whether it's buying movie tickets or checking out at a supermarket, the first person in line is served first.
Customer Support
Customers are usually helped in the order they join the queue.
Task Scheduling
Operating systems often process tasks in the order they are received.
These are just a few examples. As you continue learning DSA, you'll discover many more places where queues are used.