The Queue data structure is a linear data structure that allows you to store a collection of data inside it in a similar fashion to a real-world queue.
Whenever you’re going to a bank or buying a Starbucks coffee, you’re most likely going to form a line with other people and wait until it’s your turn to be served. A queue always implements the FIFO (First-In-First-Out) system. Those who came in earliest will be served first.
The process of adding a new customer to the line is called enqueue, while a customer that has been served by the store and removed from the line is called the dequeue process.
The Queue data structure mimics this real-world practice of waiting in line and serving the earliest customer first by creating an abstract rule that you need to implement to the data structure. The rules are as follows:
- The data structure has 2 pointers: the head and the tail
- The earliest element will be located on the head
- The latest element will be located on the tail
- A new element can be inserted into the structure using
enqueue()
method - The
dequeue()
method will remove the element on the head, moving the head to the next element in line
In addition, you may also count the length of the queue and peek to see the next element located in the head pointer to help with data manipulation. I will show you how to implement both additions later.
Here’s an illustration explaining how Queue data structure works:
The Queue data structure is commonly used because its fast insertion and deletion. The following table describes Queue data structure time complexity in Big O Notation (from Wikipedia):
Algorithm | Average | Worst case |
---|---|---|
Space | O(n) | O(n) |
Search | O(n) | O(n) |
Insert | O(1) | O(1) |
Delete | O(1) | O(1) |
Now that you understand what the queue data structure looks like, let’s learn how to implement one using JavaScript.
JavaScript Queue implementation
You can implement a Queue data structure using JavaScript in three steps:
- Create a
class
namedQueue
with three properties:elements
,head
, andtail
- Write the
length
function and bind it as a property usingget
syntax - Write the
enqueue()
,dequeue()
, andpeek()
method code
You will use the class as a blueprint to create a new object instance of Queue
. Alright, let’s start with creating a Queue
class that has the required properties:
class Queue {
constructor() {
this.elements = {};
this.head = 0;
this.tail = 0;
}
}
Any element enqueued to the object instance will be stored in elements
property. The head
and tail
properties will be the pointer, indicating the first and last element index inside the structure.
Next, write the length()
method code as follows:
get length() {
return this.tail - this.head;
}
The get
syntax before the length()
method declaration will bind the method as a property, so when you create a new instance later, you can call the method like a property:
const q = new Queue();
q.length; // calls the length() method
Finally, you need to write the three methods for enqueue()
, dequeue()
, and peek()
process.
The enqueue()
method takes an element
as its parameter and puts it in the tail
index. Once the new element is stored, you need to increment the tail
pointer by one:
enqueue(element) {
this.elements[this.tail] = element;
this.tail++;
}
The dequeue()
method first check if the length
property of the instance is larger than zero. When there’s no element, the method simply returns undefined
. When there is one or more element in the instance, the method will grab the element at head
index and delete it from the storage (elements
property in this case)
Then, the head
pointer will be incremented by one and the deleted element is returned to the caller.
Here’s the code for dequeue()
method:
dequeue() {
if (this.length) {
const element = this.elements[this.head];
delete this.elements[this.head];
this.head++;
return element;
}
return undefined;
}
Finally, the peek()
method will return the next element waiting in line. This will be the same element returned by dequeue()
method, but the difference is this element won’t be removed from the queue.
Here’s the code for the peek()
method:
peek() {
if (this.length) {
return this.elements[this.head];
}
return undefined;
}
And with that, your Queue
class is finished. Here’s the full code for your reference:
class Queue {
constructor() {
this.elements = {};
this.head = 0;
this.tail = 0;
}
get length() {
return this.tail - this.head;
}
enqueue(element) {
this.elements[this.tail] = element;
this.tail++;
}
dequeue() {
if (this.length) {
const element = this.elements[this.head];
delete this.elements[this.head];
this.head++;
return element;
}
return undefined;
}
peek() {
if (this.length) {
return this.elements[this.head];
}
return undefined;
}
}
You can test the code by creating a new object of Queue
class instance and call the methods from it:
const q = new Queue();
q.enqueue("James");
q.enqueue("Dean");
q.enqueue("Ben");
console.log(q.length); // 3
console.log(q.peek()); // "James"
console.log(q.dequeue()); // "James"
console.log(q.peek()); // "Dean"
console.log(q.length); // 2
Feel free to copy and use the code as you need 😉