We will see what is priority queue and why is this data structure is needed and also implement a priority queue in javascript.
What is priority queue?
As queues are widely used in computer programming and in real lives as well, there was a need for some different models of original queue data structure to process the data more efficiently.
A priority queue is one of the variants of the original queue. In this elements are added and removed based on their priorities. It is an abstract data type that captures the idea of a container whose elements have priorities attached to them. An element of highest priority always appears at the front of the queue. If that element is removed, the next highest priority element advances to the front.
A real-life example of the priority queue are the patients in the hospitals, the one with at most priority are treated first and then the others.
Another example is people standing in a queue at the boarding line at the airport, first and second class (Business class) passengers get priority over the coach class (Economy).
In India elderly or women get priority over young men in many places like on railways and buses.
Why do we need priority queue?
It is used when we have to choose between the same values and have different priorities or weights.
- Dijkstra’s Shortest Path Algorithm using priority queue: When the graph is stored in the form of an adjacency list or matrix, a priority queue can be used to extract minimum efficiently when implementing Dijkstra’s algorithm.
- Prim’s algorithm: to store keys of nodes and extract minimum key node at every step.
- Data compression: It is used in Huffman Codes which is used to compresses data.
- Operating system: It is used by operating systems for load balancing.
Now I am sure that you have a good idea about priority queue, so let us start implementing it in javascript.
List of operations performed on priority queue
- enqueue(): Adds an item at the tail of the queue.
- dequeue(): Removes an item from the head of the queue.
- front(): Returns the first item in the queue.
- rear(): Returns the last item in the queue.
- size(): Returns the size of the queue.
- isEmpty(): Returns
true
if queue is empty,false
otherwise.
There are two ways of implementing a priority queue.
- Add elements at appropriate place based on their priorities.
- Queue elements as they are added and remove them according to their priorities.
We will use the first approach as we just have to place the elements at the appropriate place and then it can be dequeued normally.
Implementing a priority queue in javascript
We will use an extra function (container) which will be storing the value and its priority.
function PriorityQueue(){ let items = []; //Container function QueueElement(element, priority){ this.element = element; this.priority = priority; } //Other methods go here }
Adding an item in the priority queue.
This is the only major method which will be modifying to store the data based on priorities.
We will iterate each element that is already present in the queue and compare their priority with the new element’s priority. If the new elements priority is greater then will add it at that place.
To add elements at specific index we will need to shift the remaining elements back, But javascript array has an inbuilt method for this splice(index, count, element)
which we will be using.
//Add a new element in queue this.enqueue = function(element, priority){ let queueElement = new QueueElement(element, priority); //To check if element is added let added = false; for(let i = 0; i < items.length; i++){ //We are using giving priority to higher numbers //If new element has more priority then add it at that place if(queueElement.priority > items[i].priority){ items.splice(i, 0, queueElement); //Mark the flag true added = true; break; } } //If element is not added //Then add it to the end of the queue if(!added){ items.push(queueElement); } }
Remove an item from the priority queue
//Remove element from the queue this.dequeue = () => { return items.shift(); }
Return the first element from the priority queue
//Return the first element from the queue this.front = () => { return items[0]; }
Return the last element from the priority queue
//Return the last element from the queue this.rear = () => { return items[items.length - 1]; }
Check if queue is empty
//Check if queue is empty this.isEmpty = () => { return items.length == 0; }
Return the size of the queue
//Return the size of the queue this.size = () => { return items.length; }
Print the queue
//Print the queue this.print = function(){ for(let i = 0; i < items.length; i++){ console.log(`${items[i].element} - ${items[i].priority}`); } }
Complete code of the priority queue.
function PriorityQueue(){ let items = []; //Container function QueueElement(element, priority){ this.element = element; this.priority = priority; } //Add a new element in queue this.enqueue = function(element, priority){ let queueElement = new QueueElement(element, priority); //To check if element is added let added = false; for(let i = 0; i < items.length; i++){ //We are using giving priority to higher numbers //If new element has more priority then add it at that place if(queueElement.priority > items[i].priority){ items.splice(i, 0, queueElement); //Mark the flag true added = true; break; } } //If element is not added //Then add it to the end of the queue if(!added){ items.push(queueElement); } } //Remove element from the queue this.dequeue = () => { return items.shift(); } //Return the first element from the queue this.front = () => { return items[0]; } //Return the last element from the queue this.rear = () => { return items[items.length - 1]; } //Check if queue is empty this.isEmpty = () => { return items.length == 0; } //Return the size of the queue this.size = () => { return items.length; } //Print the queue this.print = function(){ for(let i = 0; i < items.length; i++){ console.log(`${items[i].element} - ${items[i].priority}`); } } }
Input: let pQ = new PriorityQueue(); pQ.enqueue(1, 3); pQ.enqueue(5, 2); pQ.enqueue(6, 1); pQ.enqueue(11, 1); pQ.enqueue(13, 1); pQ.enqueue(10, 3); pQ.dequeue(); pQ.print(); Output: "10 - 3" "5 - 2" "6 - 1" "11 - 1" "13 - 1"
ES6 class based implementation of priority queue.
//Container class QueueElement{ constructor(element, priority){ this.element = element; this.priority = priority; } } //PriorityQueue class PriorityQueue{ constructor(){ this.items = []; } //Add a new element in queue enqueue = function(element, priority){ let queueElement = new QueueElement(element, priority); //To check if element is added let added = false; for(let i = 0; i < this.items.length; i++){ //We are using giving priority to higher numbers //If new element has more priority then add it at that place if(queueElement.priority > this.items[i].priority){ this.items.splice(i, 0, queueElement); //Mark the flag true added = true; break; } } //If element is not added //Then add it to the end of the queue if(!added){ this.items.push(queueElement); } } //Remove element from the queue dequeue = function(){ return this.items.shift(); } //Return the first element from the queue front = function(){ return this.items[0]; } //Return the last element from the queue rear = function(){ return this.items[this.items.length - 1]; } //Check if queue is empty isEmpty = function(){ return this.items.length == 0; } //Return the size of the queue size = function(){ return this.items.length; } //Print the queue print = function(){ for(let i = 0; i < this.items.length; i++){ console.log(`${this.items[i].element} - ${this.items[i].priority}`); } } }
Input: let pQ = new PriorityQueue(); pQ.enqueue(1, 3); pQ.enqueue(5, 2); pQ.enqueue(6, 1); pQ.enqueue(11, 1); pQ.enqueue(13, 1); pQ.enqueue(10, 3); pQ.dequeue(); pQ.print(); Output: "10 - 3" "5 - 2" "6 - 1" "11 - 1" "13 - 1"
Making this class private with closure and IIFE.
let PriorityQueue = (function(){ //Container class QueueElement{ constructor(element, priority){ this.element = element; this.priority = priority; } } //PriorityQueue return class PriorityQueue{ constructor(){ this.items = []; } //Add a new element in queue enqueue = function(element, priority){ let queueElement = new QueueElement(element, priority); //To check if element is added let added = false; for(let i = 0; i < this.items.length; i++){ //We are using giving priority to higher numbers //If new element has more priority then add it at that place if(queueElement.priority > this.items[i].priority){ this.items.splice(i, 0, queueElement); //Mark the flag true added = true; break; } } //If element is not added //Then add it to the end of the queue if(!added){ this.items.push(queueElement); } } //Remove element from the queue dequeue = function(){ return this.items.shift(); } //Return the first element from the queue front = function(){ return this.items[0]; } //Return the last element from the queue rear = function(){ return this.items[this.items.length - 1]; } //Check if queue is empty isEmpty = function(){ return this.items.length == 0; } //Return the size of the queue size = function(){ return this.items.length; } //Print the queue print = function(){ for(let i = 0; i < this.items.length; i++){ console.log(`${this.items[i].element} - ${this.items[i].priority}`); } } } }());
Time Complexity
# | Access | Search | Insert | Delete |
---|---|---|---|---|
Average | Θ(N) | Θ(N) | Θ(N) | Θ(1) |
Worst | O(N) | O(N) | O(N) | O(1) |
Space Complexity
# | space |
---|---|
Worst | O(N) |