Open In App

Priority Queue using Binary Heap

Last Updated : 28 Mar, 2025
Summarize
Comments
Improve
Suggest changes
Like Article
Like
Share
Report
News Follow

What is a Priority Queue ?

Priority Queue is an extension of the queue with the following properties:  

  1. Every item has a priority associated with it.
  2. An element with high priority is dequeued before an element with low priority.
  3. If two elements have the same priority, they are served according to their order in the queue.

What is a Binary Heap ?

A Binary Heap is a Binary Tree with the following properties:  

  1. It is a Complete Tree. This property of Binary Heap makes them suitable to be stored in an array.
  2. A Binary Heap is either Min Heap or Max Heap.
  3. In a Min Binary Heap, the key at the root must be minimum among all keys present in Binary Heap. The same property must be recursively true for all nodes in Binary Tree.
  4. Similarly, in a Max Binary Heap, the key at the root must be maximum among all keys present in Binary Heap. The same property must be recursively true for all nodes in Binary Tree.

Operation on Binary Heap 

  • insert(p): Inserts a new element with priority p.
  • extractMax(): Extracts an element with maximum priority.
  • remove(i): Removes an element pointed by an iterator i.
  • getMax(): Returns an element with maximum priority.
  • changePriority(i, p): Changes the priority of an element pointed by i to p.

Example of A Binary Max Heap 

  • Suppose below is the given Binary Heap that follows all the properties of Binary Max Heap. 
     
  • Now a node with value 32 need to be inserted in the above heap: To insert an element, attach the new element to any leaf. For Example A node with priority 32 can be added to the leaf of the node 7. But this violates the heap property. To maintain the heap property, shift up the new node 32
     
  • Shift Up Operation get node with 32 at the correct position: Swap the incorrectly placed node with its parent until the heap property is satisfied. For Example: As node 7 is less than node 32 so, swap node 7 and node 32. Then, swap node 31 and node 32.
     
  • Extract Max: The maximum value is stored at the root of the tree. But the root of the tree cannot be directly removed. First, it is replaced with any one of the leaves and then removed. For Example: To remove Node 45, it is first replaced with node 7. But this violates the heap property, so move the replaced node down. For that, use shift-down operation. 
     
  • Shift Down Operation: Swap the incorrectly placed node with a larger child until the heap property is satisfied. For Example Node 7 is swapped with node 32 then, last it is swapped with node 31
     
  • Change Priority: Let the changed element shift up or down depending on whether its priority decreased or increased. For Example: Change the priority of nodes 11 to 35, due to this change the node has to shift up the node in order to maintain the heap property.
  • Remove: To remove an element, change its priority to a value larger than the current maximum, then shift it up, and then extract it using extract max. Find the current maximum using get Max.
  • Get Max: The max value is stored at the root of the tree. To get max, just return the value at the root of the tree.

Array Representation of Binary Heap

Since the heap is maintained in form of a complete binary tree, because of this fact the heap 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.

Below is the illustration of the same: 
 


Below is the program to implement Priority Queue using Binary Heap:

C++
#include <bits/stdc++.h>
using namespace std;

// Function to return the index of the
// parent node of a given node
int parent(int i) {
    return (i - 1) / 2;
}

// Function to return the index of the
// left child of the given node
int leftChild(int i) {
    return ((2 * i) + 1);
}

// Function to return the index of the
// right child of the given node
int rightChild(int i){
    return ((2 * i) + 2);
}

// Function to shift up the node in order
// to maintain the heap property
void shiftUp(int i, vector<int> &arr) {
    while (i > 0 && arr[parent(i)] < arr[i]) {

        // Swap parent and current node
        swap(arr[parent(i)], arr[i]);

        // Update i to parent of i
        i = parent(i);
    }
}

// Function to shift down the node in
// order to maintain the heap property
void shiftDown(int i, vector<int> &arr, int &size) {
    int maxIndex = i;

    // Left Child
    int l = leftChild(i);

    if (l <= size && arr[l] > arr[maxIndex]) {
        maxIndex = l;
    }

    // Right Child
    int r = rightChild(i);

    if (r <= size && arr[r] > arr[maxIndex]) {
        maxIndex = r;
    }

    // If i not same as maxIndex
    if (i != maxIndex) {
        swap(arr[i], arr[maxIndex]);
        shiftDown(maxIndex, arr, size);
    }
}

// Function to insert a new element
// in the Binary Heap
void insert(int p, vector<int> &arr, int &size) {
    size = size + 1;
    arr.push_back(p);

    // Shift Up to maintain heap property
    shiftUp(size, arr);
}

// Function to extract the element with
// maximum priority
int extractMax(vector<int> &arr, int &size) {
    int result = arr[0];

    // Replace the value at the root
    // with the last leaf
    arr[0] = arr[size];
    size = size - 1;

    // Shift down the replaced element
    // to maintain the heap property
    shiftDown(0, arr, size);
    return result;
}

// Function to change the priority
// of an element
void changePriority(int i, int p, vector<int> &arr, int &size) {
    int oldp = arr[i];
    arr[i] = p;

    if (p > oldp) {
        shiftUp(i, arr);
    }
    else {
        shiftDown(i, arr, size);
    }
}

// Function to get value of the current
// maximum element
int getMax(vector<int> &arr) {
    return arr[0];
}

// Function to remove the element
// located at given index
void remove(int i, vector<int> &arr, int &size) {
    arr[i] = getMax(arr) + 1;

    // Shift the node to the root
    // of the heap
    shiftUp(i, arr);

    // Extract the node
    extractMax(arr, size);
}

int main() {

    /*         45
            /      \
           31      14
          /  \    /  \
         13  20  7   11
        /  \
       12   7
    Create a priority queue shown in
    example in a binary max heap form.
    Queue will be represented in the
    form of array as:

    45 31 14 13 20 7 11 12 7 */

    // Insert the element to the
    // priority queue

    vector<int> arr;
    int size = -1;
    insert(45, arr, size);
    insert(20, arr, size);
    insert(14, arr, size);
    insert(12, arr, size);
    insert(31, arr, size);
    insert(7, arr, size);
    insert(11, arr, size);
    insert(13, arr, size);
    insert(7, arr, size);

    int i = 0;

    // Priority queue before extracting max
    cout << "Priority Queue : ";
    while (i <= size) {
        cout << arr[i] << " ";
        i++;
    }

    cout << endl;

    // Node with maximum priority
    cout << "Node with maximum priority : "
         << extractMax(arr, size) << endl;

    // Priority queue after extracting max
    cout << "Priority queue after "
         << "extracting maximum : ";
    int j = 0;
    while (j <= size) {
        cout << arr[j] << " ";
        j++;
    }

    cout << endl;

    // Change the priority of element
    // present at index 2 to 49
    changePriority(2, 49, arr, size);
    cout << "Priority queue after "
         << "priority change : ";
    int k = 0;
    while (k <= size) {
        cout << arr[k] << " ";
        k++;
    }

    cout << endl;

    // Remove element at index 3
    remove(3, arr, size);
    cout << "Priority queue after "
         << "removing the element : ";
    int l = 0;
    while (l <= size) {
        cout << arr[l] << " ";
        l++;
    }
    return 0;
}
Java Python C# JavaScript

Output
Priority Queue : 45 31 14 13 20 7 11 12 7 
Node with maximum priority : 45
Priority queue after extracting maximum : 31 20 14 13 7 7 11 12 
Priority queue after priority change : 49 20 31 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)

[Alternate Approach] – Using Generic Template in Statically Typed Languages like C++, Java and C#

Below is a valid approach to implementing a priority queue using a max heap. This implementation follows a class-based structure with a generic template, making it adaptable to all data types rather than being restricted to a specific one.

Below is given the implementation:

C++
#include <bits/stdc++.h>
using namespace std;

// Priority queue implementation
template <typename T>
class PriorityQueue {
private:
    vector<T> data;

public:
    PriorityQueue() {}

    // to enqueue the element
    void Enqueue(T item) {
        data.push_back(item);
        int ci = data.size() - 1;

        // Re-structure heap(Max Heap) so that after
        // addition max element will lie on top of pq
        while (ci > 0) {

            // Parent index of current index
            int pi = (ci - 1) / 2;

            if (data[ci] <= data[pi])
                break;

            // If current index element is greater 
            // than parent index element then swap
            T tmp = data[ci];
            data[ci] = data[pi];
            data[pi] = tmp;
            ci = pi;
        }
    }

    T Dequeue() {

        // deleting top element of pq
        int li = data.size() - 1;
        T frontItem = data[0];
        data[0] = data[li];
        data.pop_back();

        --li;
        int pi = 0;

        // Re-structure heap(Max Heap) so that after
        // deletion max element will lie on top of pq
        while (true) {

            // Left child index of parent index
            int ci = pi * 2 + 1;
            if (ci > li)
                break;

            // Right child index of parent index
            int rc = ci + 1;

            // If right child index is less than left child
            // index then assign right child index to ci
            if (rc <= li && data[rc] > data[ci])
                ci = rc;

            if (data[pi] >= data[ci])
                break;

            // If parent index element is less than child
            // index element then swap
            T tmp = data[pi];
            data[pi] = data[ci];
            data[ci] = tmp;
            pi = ci;
        }
        return frontItem;
    }

    // Function which returns peek element
    T Peek() {
        T frontItem = data[0];
        return frontItem;
    }

    int Count() {
        return data.size();
    }
};

int main() {
    PriorityQueue<int> pq;
    cout << "Size" << "  " << "Peek" << endl;
    pq.Enqueue(1);
    cout << pq.Count() << "     " << pq.Peek() << endl;
    pq.Enqueue(10);
    pq.Enqueue(-8);
    cout << pq.Count() << "     " << pq.Peek() << endl;
    pq.Dequeue();
    cout << pq.Count() << "     " << pq.Peek() << endl;
    pq.Dequeue();
    cout << pq.Count() << "     " << pq.Peek() << endl;
    pq.Enqueue(25);
    cout << pq.Count() << "     " << pq.Peek() << endl;
    return 0;
}
Java C#

Output
Size  Peek
1     1
3     10
2     1
1     -8
2     25

Time Complexity: O(log(n)), for enqueue operation and O(log(n)) for dequeue operation.
Space complexity: O(n), as we need n size array for implementation.



Next Article

Similar Reads

three90RightbarBannerImg