An quick look at the Queue data structure
11, May 2019 - 5 min readA queue is a list based data structure where data is inserted at the end and removed from the top. There are many real world example of queues for example when you are lining up for some service e.g to use an ATM, to see the doctor, at the cafeteria e.t.c, the first person in the line will be the first to be attended to.
A queue is known as a First In - First Out(FIFO) data structure since it stores data in the order it occurs i.e whatever goes in first comes out first as well. A queue is helpful when you would like to maintain data in the same sequence in which it flows in.
Types of Queue
The following are the types of queues we might need to use when building applications:-
-
The default queue - This is a simple FIFO queue in which the order is retained and data leaves in the same order in which it comes in
-
Priority queue - Elements in the Priority Queue are given a predefined priority and elements with a high priority leave the queue before those with a lower priority
-
Circular queue - A variation of the default queue in which the back of the queue is followed by the front of the queue
-
Double ended queue (Dequeue) - Similar to the default queue but can add or remove elements from either the front or the back of the queue
Queue Operations
The main queue operations include :-
- Enqueue - inserting a new element at the end of the queue
- Dequeue - Removing an element from the top of the queue
- Peek - viewing the element at the front of the queue without removing it
Other important operations of the queue can be determining whether the queue is empty, determining the length/size of the queue, clearing the Queue. We shall see this in action when implementing the Queue.
Implementing a Queue
Of all the queue types discussed above, we will implement the Default Queue and the Priority Queue. Lets see how we can go about implementing them in JavaScript
The Default Queue
We shall be using a factory function to implement the Queue based on the inbuilt JavaScript array as shown below.
Explanation of the code will be in the comments
function createQueue() {
// to store the elements in our queue
let queue = [];
return {
enqueue(item) {
// add item at the end of the queue
queue.push(item);
// return the queue length
return queue.length;
},
dequeue() {
// remove the element at the front of the queue and return it
return queue.shift();
},
peek() {
// return the element at the front of the queue but don't remove it
return queue[0];
},
clear() {
// empty the queue
queue = [];
},
// use a getter to make length a property of the queue and not a method
get length() {
// return the length of the queue
return queue.length;
},
// use a getter to make isEmpty a property of the queue and not a method
get isEmpty() {
// determine whether the queue is empty or not
return queue.length === 0;
},
};
}
// Testing our Queue
// create the queue
const queue = createQueue();
console.log('Queue is empty: ', queue.isEmpty); // Output => Queue is empty: true
console.log('Adding some elements to the queue');
queue.enqueue('Wake Up');
queue.enqueue('Take a Shower');
queue.enqueue('Take Some coffee');
queue.enqueue('Go for work');
console.log('Queue is empty: ', queue.isEmpty); // Output => Queue is empty: false
console.log('Next Item to remove: ', queue.peek()); // Output => Next Item to remove: Wake Up
console.log('Length: ', queue.length); // Output => Length: 4
console.log('Removed: ', queue.dequeue()); // Output => Removed: Wake Up
console.log('Next Item: ', queue.peek()); // Output => Next Item: Take a Shower
console.log('Length: ', queue.length); // Output => Length: 3
console.log('Clearing The Queue');
queue.clear();
console.log('Queue is empty: ', queue.isEmpty); // Output => Queue is empty: true
console.log('Length: ', queue.length); // Output => Length: 0
In the code block above we implemented the default Queue and tested it out. We used a factory function to create it as it helps us to hide the array we use as the queue from the outside world.
The Priority Queue
In the Priority Queue, items are added and removed based on priority. It can either be a minimum priority Queue where elements with lower priority are removed first or a maximum priority Queue where elements with a maximum priority are removed first.
A real world example of the priority Queue can be the boarding line at the airport where first class passengers get priority over business class or in some cases pregnant women and elderly people are given priority. There are various approaches we can take while implementing the priority queue, the approach we will take will be adding elements with high priority at the top of the queue. By doing this, we will only modify the add method but other methods will remain as they were implemented in the default queue. Let's see this in action.
function createPriorityQueue() {
// to store the elements in our queue
let queue = [];
return {
enqueue(item, priority) { // create queue item const newItem = { value: item, priority }; // a variable to keep help us know whether we have added an item in the queue let newItemIsAdded = false; // loop through all items in the queue for ( let currentItemIndex = 0; currentItemIndex < queue.length; currentItemIndex += 1 ) { // get the current item let currentItem = queue[currentItemIndex]; // if priority of the current item is less than priority of the item to be added if (currentItem.priority < newItem.priority) { // insert the current item at the current index queue.splice(currentItemIndex, 0, newItem); // mark newItemIsAdded as true newItemIsAdded = true; // break out of the loop break; } } // if we haven't added the item if (!newItemIsAdded) { // add it to the end of the queue queue.push(newItem); } // return queue length return queue.length; }, dequeue() {
// remove the element at the front of the queue and return it
return queue.shift();
},
peek() {
// return the element at the front of the queue but don't remove it
return queue[0];
},
clear() {
// empty the queue
queue = [];
},
// use a getter to make length a property of the queue and not a method
get length() {
// return the length of the queue
return queue.length;
},
// use a getter to make isEmpty a property of the queue and not a method
get isEmpty() {
// determine whether the queue is empty or not
return queue.length === 0;
},
};
}
// Testing our priority Queue
const priorityQueue = createPriorityQueue();
priorityQueue.enqueue('Dennis', 1);
priorityQueue.enqueue('John', 2);
priorityQueue.enqueue('Rain', 3);
priorityQueue.enqueue('Don', 2);
console.log(priorityQueue.peek()); // { value: 'Rain', priority: 3 }
console.log('Length: ', priorityQueue.length); // Length: 4
console.log('Is Empty: ', priorityQueue.isEmpty); // Is Empty: false
console.log('Removing: ', priorityQueue.dequeue()); // Removing: { value: 'Rain', priority: 3 }
console.log(priorityQueue.peek()); // { value: 'John', priority: 2 }
console.log('Clearing priority queue');
priorityQueue.clear();
console.log('Length: ', priorityQueue.length); // Length: 0
console.log('Is Empty: ', priorityQueue.isEmpty); // Is Empty: true
The
enqueue
method is highlighted in the priority queue implementation since its the only method we have modified. Thanks you for reading this blog post this far. If there is anyway this can be made better, reach out to me on twitter.