Introduction to Priority Queue
A priority queue is a type of queue where each element is associated with a priority value, and elements are served based on their priority rather than their insertion order.
- Elements with higher priority are retrieved or removed before those with lower priority.
- When a new item is added, it is inserted according to its priority.
The binary heap is the most common implementation of a priority queue:
- A min-heap allows quick access to the element with the smallest value.
- A max-heap allows quick access to the element with the largest value.
- Binary heaps are complete binary trees, making them easy to implement using arrays.
- Using arrays provides cache-friendly memory access, improving performance.
Priority queues are widely used in algorithms such as Dijkstra’s shortest path algorithm, Prim’s minimum spanning tree algorithm, and Huffman coding for data compression.
Types of Priority Queue

- Min-Heap: In this queue, elements with lower values have higher priority. For example, with elements 4, 6, 8, 9, and 10, 4 will be dequeued first since it has the smallest value, and the dequeue operation will return 4.
- Max-Heap: Elements with higher values have higher priority. The root of the heap is the highest element, and it is dequeued first. The queue adjusts by maintaining the heap property after each insertion or deletion.
Array Representation of Binary Heap:
Since the heap is maintained in the form of a complete binary tree, so it can be represented in the form of an array. To keep the tree complete and shallow, while inserting a new element insert it in the leftmost vacant position in the last level i.e., at the end of our array. Similarly, while extracting maximum replace the root with the last leaf at the last level i.e., the last element of the array.

Implementation of Priority Queue Using Heap :
A Binary Heap is ideal for priority queue implementation as it offers better performance The largest key is at the top and can be removed in O(log n) time, with the heap property restored efficiently. If a new entry is inserted immediately, its O(log n) insertion time may overlap with restoration. Since heaps use contiguous storage, they efficiently handle large datasets while ensuring logarithmic time for insertions and deletions.
- insert(p): Inserts a new element with priority p.
- pop(): Extracts an element with maximum priority.
- getMax(): Returns an element with maximum priority.
#include <iostream>
#include <vector>
using namespace std;
// Returns index of parent
int parent(int i) { return (i - 1) / 2; }
// Returns index of left child
int leftChild(int i) { return 2 * i + 1; }
// Returns index of right child
int rightChild(int i) { return 2 * i + 2; }
// Shift up to maintain max-heap property
void shiftUp(int i, vector<int> &arr) {
while (i > 0 && arr[parent(i)] < arr[i]) {
swap(arr[parent(i)], arr[i]);
i = parent(i);
}
}
// Shift down to maintain max-heap property
void shiftDown(int i, vector<int> &arr, int size) {
int maxIndex = i;
int l = leftChild(i);
if (l < size && arr[l] > arr[maxIndex]) maxIndex = l;
int r = rightChild(i);
if (r < size && arr[r] > arr[maxIndex]) maxIndex = r;
if (i != maxIndex) {
swap(arr[i], arr[maxIndex]);
shiftDown(maxIndex, arr, size);
}
}
// Insert a new element
void insert(int p, vector<int> &arr) {
arr.push_back(p);
shiftUp(arr.size() - 1, arr);
}
// Extract element with maximum priority
int pop(vector<int> &arr) {
int size = arr.size();
if (size == 0) return -1;
int result = arr[0];
arr[0] = arr[size - 1];
arr.pop_back();
shiftDown(0, arr, arr.size());
return result;
}
// Get current maximum element
int getMax(vector<int> &arr) {
if (arr.empty()) return -1;
return arr[0];
}
// Print heap
void printHeap(vector<int> &arr) {
for (int x : arr) cout << x << " ";
cout << endl;
}
int main() {
vector<int> pq;
insert(45, pq);
insert(20, pq);
insert(14, pq);
insert(12, pq);
insert(31, pq);
insert(7, pq);
insert(11, pq);
insert(13, pq);
insert(7, pq);
cout << "Priority Queue after inserts: ";
printHeap(pq);
// Demonstrate getMax
cout << "Current max element: " << getMax(pq) << endl;
// Demonstrate extractMax
pop(pq) ;
cout << "Priority Queue after extracting max: ";
printHeap(pq);
return 0;
}
import java.util.ArrayList;
import java.util.Collections;
class GFG {
// Returns index of parent
static int parent(int i) { return (i - 1) / 2; }
// Returns index of left child
static int leftChild(int i) { return 2 * i + 1; }
// Returns index of right child
static int rightChild(int i) { return 2 * i + 2; }
// Shift up to maintain max-heap property
static void shiftUp(int i, ArrayList<Integer> arr) {
while (i > 0 && arr.get(parent(i)) < arr.get(i)) {
Collections.swap(arr, parent(i), i);
i = parent(i);
}
}
// Shift down to maintain max-heap property
static void shiftDown(int i, ArrayList<Integer> arr, int size) {
int maxIndex = i;
int l = leftChild(i);
if (l < size && arr.get(l) > arr.get(maxIndex)) maxIndex = l;
int r = rightChild(i);
if (r < size && arr.get(r) > arr.get(maxIndex)) maxIndex = r;
if (i != maxIndex) {
Collections.swap(arr, i, maxIndex);
shiftDown(maxIndex, arr, size);
}
}
// Insert a new element
static void insert(int p, ArrayList<Integer> arr) {
arr.add(p);
shiftUp(arr.size() - 1, arr);
}
// Extract element with maximum priority
static int pop(ArrayList<Integer> arr) {
int size = arr.size();
if (size == 0) return -1;
int result = arr.get(0);
arr.set(0, arr.get(size - 1));
arr.remove(size - 1);
shiftDown(0, arr, arr.size());
return result;
}
// Get current maximum element
static int getMax(ArrayList<Integer> arr) {
if (arr.isEmpty()) return -1;
return arr.get(0);
}
// Print heap
static void printHeap(ArrayList<Integer> arr) {
for (int x : arr) System.out.print(x + " ");
System.out.println();
}
public static void main(String[] args) {
ArrayList<Integer> pq = new ArrayList<>();
insert(45, pq);
insert(20, pq);
insert(14, pq);
insert(12, pq);
insert(31, pq);
insert(7, pq);
insert(11, pq);
insert(13, pq);
insert(7, pq);
System.out.print("Priority Queue after inserts: ");
printHeap(pq);
// Demonstrate getMax
System.out.println("Current max element: " + getMax(pq));
// Demonstrate extractMax
pop(pq);
System.out.print("Priority Queue after extracting max: ");
printHeap(pq);
}
}
# Returns index of parent
def parent(i):
return (i - 1) // 2
# Returns index of left child
def leftChild(i):
return 2 * i + 1
# Returns index of right child
def rightChild(i):
return 2 * i + 2
# Shift up to maintain max-heap property
def shiftUp(i, arr):
while i > 0 and arr[parent(i)] < arr[i]:
arr[parent(i)], arr[i] = arr[i], arr[parent(i)]
i = parent(i)
# Shift down to maintain max-heap property
def shiftDown(i, arr, size):
maxIndex = i
l = leftChild(i)
if l < size and arr[l] > arr[maxIndex]:
maxIndex = l
r = rightChild(i)
if r < size and arr[r] > arr[maxIndex]:
maxIndex = r
if i != maxIndex:
arr[i], arr[maxIndex] = arr[maxIndex], arr[i]
shiftDown(maxIndex, arr, size)
# Insert a new element
def insert(p, arr):
arr.append(p)
shiftUp(len(arr) - 1, arr)
# Extract element with maximum priority
def pop(arr):
size = len(arr)
if size == 0:
return -1
result = arr[0]
arr[0] = arr[size - 1]
arr.pop()
shiftDown(0, arr, len(arr))
return result
# Get current maximum element
def getMax(arr):
if not arr:
return -1
return arr[0]
# Print heap
def printHeap(arr):
print(" ".join(map(str, arr)))
# Driver code
if __name__ == "__main__":
pq = []
insert(45, pq)
insert(20, pq)
insert(14, pq)
insert(12, pq)
insert(31, pq)
insert(7, pq)
insert(11, pq)
insert(13, pq)
insert(7, pq)
print("Priority Queue after inserts: ", end="")
printHeap(pq)
# Demonstrate getMax
print("Current max element:", getMax(pq))
# Demonstrate extractMax
pop(pq)
print("Priority Queue after extracting max: ", end="")
printHeap(pq)
using System;
using System.Collections.Generic;
class GFG
{
// Returns index of parent
static int parent(int i) => (i - 1) / 2;
// Returns index of left child
static int leftChild(int i) => 2 * i + 1;
// Returns index of right child
static int rightChild(int i) => 2 * i + 2;
// Shift up to maintain max-heap property
static void shiftUp(int i, List<int> arr)
{
while (i > 0 && arr[parent(i)] < arr[i])
{
int temp = arr[parent(i)];
arr[parent(i)] = arr[i];
arr[i] = temp;
i = parent(i);
}
}
// Shift down to maintain max-heap property
static void shiftDown(int i, List<int> arr, int size)
{
int maxIndex = i;
int l = leftChild(i);
if (l < size && arr[l] > arr[maxIndex]) maxIndex = l;
int r = rightChild(i);
if (r < size && arr[r] > arr[maxIndex]) maxIndex = r;
if (i != maxIndex)
{
int temp = arr[i];
arr[i] = arr[maxIndex];
arr[maxIndex] = temp;
shiftDown(maxIndex, arr, size);
}
}
// Insert a new element
static void insert(int p, List<int> arr)
{
arr.Add(p);
shiftUp(arr.Count - 1, arr);
}
// Extract element with maximum priority
static int pop(List<int> arr)
{
int size = arr.Count;
if (size == 0) return -1;
int result = arr[0];
arr[0] = arr[size - 1];
arr.RemoveAt(size - 1);
shiftDown(0, arr, arr.Count);
return result;
}
// Get current maximum element
static int getMax(List<int> arr)
{
if (arr.Count == 0) return -1;
return arr[0];
}
// Print heap
static void printHeap(List<int> arr)
{
foreach (int x in arr)
{
Console.Write(x + " ");
}
Console.WriteLine();
}
static void Main(string[] args)
{
List<int> pq = new List<int>();
insert(45, pq);
insert(20, pq);
insert(14, pq);
insert(12, pq);
insert(31, pq);
insert(7, pq);
insert(11, pq);
insert(13, pq);
insert(7, pq);
Console.Write("Priority Queue after inserts: ");
printHeap(pq);
// Demonstrate getMax
Console.WriteLine("Current max element: " + getMax(pq));
// Demonstrate extractMax
pop(pq);
Console.Write("Priority Queue after extracting max: ");
printHeap(pq);
}
}
// Returns index of parent
function parent(i) { return Math.floor((i - 1) / 2); }
// Returns index of left child
function leftChild(i) { return 2 * i + 1; }
// Returns index of right child
function rightChild(i) { return 2 * i + 2; }
// Shift up to maintain max-heap property
function shiftUp(i, arr) {
while (i > 0 && arr[parent(i)] < arr[i]) {
[arr[parent(i)], arr[i]] = [arr[i], arr[parent(i)]];
i = parent(i);
}
}
// Shift down to maintain max-heap property
function shiftDown(i, arr, size) {
let maxIndex = i;
const l = leftChild(i);
if (l < size && arr[l] > arr[maxIndex]) maxIndex = l;
const r = rightChild(i);
if (r < size && arr[r] > arr[maxIndex]) maxIndex = r;
if (i !== maxIndex) {
[arr[i], arr[maxIndex]] = [arr[maxIndex], arr[i]];
shiftDown(maxIndex, arr, size);
}
}
// Insert a new element
function insert(p, arr) {
arr.push(p);
shiftUp(arr.length - 1, arr);
}
// Extract element with maximum priority
function pop(arr) {
const size = arr.length;
if (size === 0) return -1;
const result = arr[0];
arr[0] = arr[size - 1];
arr.pop();
shiftDown(0, arr, arr.length);
return result;
}
// Get current maximum element
function getMax(arr) {
if (arr.length === 0) return -1;
return arr[0];
}
// Print heap
function printHeap(arr) {
console.log(arr.join(" "));
}
// Driver code
const pq = [];
insert(45, pq);
insert(20, pq);
insert(14, pq);
insert(12, pq);
insert(31, pq);
insert(7, pq);
insert(11, pq);
insert(13, pq);
insert(7, pq);
console.log("Priority Queue after inserts: ");
printHeap(pq);
// Demonstrate getMax
console.log("Current max element:", getMax(pq));
// Demonstrate extractMax
pop(pq);
console.log("Priority Queue after extracting max: ");
printHeap(pq);
Output
Priority Queue after inserts: 45 31 14 13 20 7 11 12 7 Current max element: 45 Priority Queue after extracting max: 31 20 14 13 7 7 11 12
Time Complexity: O(log n), for all the operation, except getMax(), which has time complexity of O(1).
Space Complexity: O(n)
Difference between Priority Queue and Queue
There is no priority attached to elements in a queue, the rule of first-in-first-out(FIFO) is implemented whereas, in a priority queue, the elements have a priority. The elements with higher priority are served first.
Library Implementation of Priority Queue

Operations on a Priority Queue
A typical priority queue supports the following operations:
1) Insertion (push) : When a new item is inserted in a Max-Heap, if it has the highest value, it becomes the root; in a Min-Heap, if it has the smallest value, it becomes the root. Otherwise, it is placed so that all higher-priority elements (larger in Max-Heap, smaller in Min-Heap) are accessed before it.
2) Deletion(pop) : We usually remove the highest-priority item, which is always at the top. After removing it, the next highest-priority item automatically takes its place at the top.
3) top : This operation only returns the highest priority item (which is typically available at the top) and does not make any change to the priority queue.
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
int main() {
// Create a max priority queue
priority_queue<int> pq;
// Insert elements into the priority queue
pq.push(10);
pq.push(30);
cout << "Priority Queue elements (max-heap):\n";
// Access elements and pop them one by one
while (!pq.empty()) {
// Access the top (highest priority element)
cout << "Top element: " << pq.top() << endl;
// Remove the top element
pq.pop();
// Print remaining size
cout << "Remaining size: " << pq.size() << "\n\n";
}
// Check if empty
if (pq.empty()) {
cout << "Priority Queue is now empty.\n";
}
return 0;
}
import java.util.PriorityQueue;
import java.util.Collections;
class GFG {
public static void main(String[] args) {
// Create a max priority queue
PriorityQueue<Integer> pq = new PriorityQueue<>(Collections.reverseOrder());
// Insert elements into the priority queue
pq.add(10);
pq.add(30);
System.out.println("Priority Queue elements (max-heap):");
// Access elements and pop them one by one
while (!pq.isEmpty()) {
// Access the top (highest priority element)
System.out.println("Top element: " + pq.peek());
// Remove the top element
pq.poll();
// Print remaining size
System.out.println("Remaining size: " + pq.size() + "\n");
}
// Check if empty
if (pq.isEmpty()) {
System.out.println("Priority Queue is now empty.");
}
}
}
import heapq
if __name__ == "__main__":
# Create a max priority queue using min heap with negative values
pq = []
# Insert elements into the priority queue
heapq.heappush(pq, -10)
heapq.heappush(pq, -30)
print("Priority Queue elements (max-heap):")
# Access elements and pop them one by one
while pq:
# Access the top (highest priority element)
print("Top element:", -pq[0])
# Remove the top element
heapq.heappop(pq)
# Print remaining size
print("Remaining size:", len(pq), "\n")
# Check if empty
if not pq:
print("Priority Queue is now empty.")
using System;
using System.Collections.Generic;
class GFG {
static void Main() {
// Create a max priority queue
SortedSet<int> pq = new SortedSet<int>(Comparer<int>.Create((a, b) => b.CompareTo(a)));
// Insert elements into the priority queue
pq.Add(10);
pq.Add(30);
Console.WriteLine("Priority Queue elements (max-heap):");
// Access elements and pop them one by one
while (pq.Count > 0) {
// Access the top (highest priority element)
int top = pq.Min;
Console.WriteLine("Top element: " + top);
// Remove the top element
pq.Remove(top);
// Print remaining size
Console.WriteLine("Remaining size: " + pq.Count + "\n");
}
// Check if empty
if (pq.Count == 0) {
Console.WriteLine("Priority Queue is now empty.");
}
}
}
class MaxPriorityQueue {
constructor() {
this.data = [];
}
push(val) {
this.data.push(val);
this.data.sort((a, b) => b - a);
}
top() {
return this.data[0];
}
pop() {
this.data.shift();
}
size() {
return this.data.length;
}
empty() {
return this.data.length === 0;
}
}
//Driver Code
// Create a max priority queue
const pq = new MaxPriorityQueue();
// Insert elements into the priority queue
pq.push(10);
pq.push(30);
console.log("Priority Queue elements (max-heap):");
// Access elements and pop them one by one
while (!pq.empty()) {
// Access the top (highest priority element)
console.log("Top element:", pq.top());
// Remove the top element
pq.pop();
// Print remaining size
console.log("Remaining size:", pq.size(), "\n");
}
// Check if empty
if (pq.empty()) {
console.log("Priority Queue is now empty.");
}
Output
Priority Queue elements (max-heap): Top element: 30 Remaining size: 1 Top element: 10 Remaining size: 0 Priority Queue is now empty.
Applications of Priority Queue
- CPU Scheduling
- Graph algorithms like Dijkstra's shortest path algorithm, Prim's Minimum Spanning Tree, etc.
- All queue applications where priority is involved.
- Data compression in Huffman code
- Event-driven simulation such as customers waiting in a queue.