# Indexed Priority Queue with Implementation

• Difficulty Level : Medium
• Last Updated : 12 Jul, 2022

Priority queue is a data structure in which data is stored on basis of its priority. In an Indexed Priority Queue, data is stored just like standard priority queue and along with this, the value of a data can be updated using its key. It is called “indexed” because  a hash map can be used to store the index in container using the key of key-value pair input  as the key of hash map. This comes handy while implementing  Dijkstra’s Algorithm using min-heap. It can also be used in any other program where it is required to put key-value pairs in priority queue and along with it you need to update value of keys with push or pop function .

Operations in an Indexed Priority Queue: The operations which can be performed in Indexed Priority Queue are:

1. push Adding key-value pair in Indexed Priority Queue according to its priority. Implementation: To do this, add the key value pair in container and then heapify on basis of value in key-value pair. Time Complexity: O( log(n) )
2. pop:  Removing the highest priority key-value pair. Implementation: Remove top of heap and then heapify rest of the container. Time Complexity: O( log(n))
3. top: Return Key-Value pair to user. Implementation: Return Key-Value pair which is at top of the heap. Time Complexity: O(1)
4. size: Return the number of key-value pairs in the Indexed Priority Queue. Implementation: Keep a track if number of elements in queue in the class and return the variable when size() function is called. Time Complexity: O(1)
5. empty: Return true when Indexed Priority Queue is empty. Implementation: Return true when number of elements variable is equal to zero. Time Complexity: O(1)
6. changeAtKey: This function differentiate Indexed Priority Queue from standard priority queue. It takes two arguments from user, first is key and second is new value, and it update old value associated with the key to new value provided and update its position according to priority of new value. Implementation: Keep a hash-map whose key is key in key-value pair and it points to index of the key in container. When the function is called update the value at required index and position current element according to its priority and finally change index value in hash map. Time Complexity: O( log(n) )

Implementation of Indexed Priority Queue:

Indexed Priority Queue is implemented using binary heap, however it can also be implemented using Fibonacci heap or K-ary heap.

There are four parameters to be passed while defining an instance of Indexed Priority Queue(two mandatories and two optional) which are:

1. Data type of key:  This is the first parameter in the definition and it should be data type that can be hashed in hash map or user have pass his own hash function as fourth parameter. To learn more about hash function in hash map see this article.
2. Data type of value: This is second parameter in definition.
3. Comparator: This is third and optional parameter. By default Indexed Priority Queue will be implemented using max heap to change that user have to pass different comparator with its parameter (i.e. parameter of comparator) as the data type of value.
4. Hash function: This is fourth parameter and required only when user pass custom data type (like a class) for key, then user have to pass his own hash function.

Below is the implementation of Indexed Priority Queue:

## C++

 `// C++ program for the above approach`   `#include ` `using` `namespace` `std;`   `template` `<``class` `T1, ``class` `T2,` `          ``class` `Comparator = less,` `          ``class` `Hash = hash >`   `class` `indexed_priority_queue {`   `    ``// Storing indices of values using key` `    ``unordered_map m;`   `    ``// Container` `    ``vector > v;`   `    ``// Size` `    ``long` `long` `numberOfElement;`   `    ``// Creating a instance of Comparator class` `    ``Comparator comp;`   `    ``// Max Capacity` `    ``long` `long` `capacity = LLONG_MAX;`   `    ``// Obtaining the index value from hash map` `    ``long` `long` `int` `getValueIndex(T1 key)` `    ``{` `        ``if` `(m[key] == 0) {` `            ``cout << ``"No Such Key Exist"``;` `            ``return` `-1;` `        ``}` `        ``return` `v[m[key] - 1];` `    ``}`   `    ``// heapify the container` `    ``void` `heapify(vector >& v,` `                 ``long` `long` `int` `heap_size,` `                 ``long` `long` `index)` `    ``{` `        ``long` `long` `leftChild = 2 * index + 1,` `                  ``rightChild = 2 * index + 2,` `                  ``suitableNode = index;`   `        ``if` `(leftChild < heap_size` `            ``&& comp(v[suitableNode].second,` `                    ``v[leftChild].second)) {` `            ``suitableNode = leftChild;` `        ``}`   `        ``if` `(rightChild < heap_size` `            ``&& comp(v[suitableNode].second,` `                    ``v[rightChild].second)) {` `            ``suitableNode = rightChild;` `        ``}`   `        ``if` `(suitableNode != index) {`   `            ``// swap the value` `            ``pair temp = v[index];` `            ``v[index] = v[suitableNode];` `            ``v[suitableNode] = temp;`   `            ``// updating the map` `            ``m[v[index].first] = index + 1;` `            ``m[v[suitableNode].first]` `                ``= suitableNode + 1;`   `            ``// heapify other affected nodes` `            ``heapify(v, numberOfElement,` `                    ``suitableNode);` `        ``}` `    ``}`   `public``:` `    ``indexed_priority_queue()` `    ``{` `        ``numberOfElement = 0;` `        ``m.clear();` `        ``v.clear();` `    ``}`   `    ``void` `push(T1 key, T2 value)` `    ``{` `        ``if` `(numberOfElement == capacity) {` `            ``cout << ``"Overflow"``;` `            ``return``;` `        ``}` `        ``if` `(m[key] != 0) {` `            ``cout << ``"Element Already Exists"``;` `            ``return``;` `        ``}`   `        ``// Adding element` `        ``v.push_back(make_pair(key, value));` `        ``numberOfElement++;` `        ``m[key] = numberOfElement;`   `        ``long` `long` `index = numberOfElement - 1;`   `        ``// Comparing to parent node` `        ``while` `(index != 0` `               ``&& comp(v[(index - 1) / 2].second,` `                       ``v[index].second)) {`   `            ``// swap the value` `            ``pair temp = v[index];` `            ``v[index] = v[(index - 1) / 2];` `            ``v[(index - 1) / 2] = temp;`   `            ``// updating the map` `            ``m[v[index].first] = index + 1;` `            ``m[v[(index - 1) / 2].first]` `                ``= (index - 1) / 2 + 1;`   `            ``// updating index in map` `            ``index = (index - 1) / 2;` `        ``}` `    ``}`   `    ``void` `pop()` `    ``{` `        ``if` `(numberOfElement == 0) {` `            ``cout << ``"UnderFlow"``;` `            ``return``;` `        ``}`   `        ``// Removing element` `        ``v.erase(v.begin());` `        ``numberOfElement--;` `        ``heapify(v, numberOfElement, 0);` `    ``}`   `    ``pair top() { ``return` `v; }`   `    ``long` `long` `int` `size() { ``return` `numberOfElement; }`   `    ``bool` `empty() { ``return` `numberOfElement == 0; }`   `    ``void` `changeAtKey(T1 key, T2 value)` `    ``{` `        ``if` `(m[key] == 0) {` `            ``cout << ``"No Such Key Exist"``;` `            ``return``;` `        ``}` `        ``long` `long` `index = m[key] - 1;` `        ``v[index].second = value;`   `        ``// Comparing to child nodes` `        ``heapify(v, numberOfElement, index);`   `        ``// Comparing to Parent Node` `        ``while` `(index != 0` `               ``&& comp(v[(index - 1) / 2].second,` `                       ``v[index].second)) {`   `            ``// swap the value` `            ``pair temp = v[index];` `            ``v[index] = v[(index - 1) / 2];` `            ``v[(index - 1) / 2] = temp;`   `            ``// updating the map` `            ``m[v[index].first] = index + 1;` `            ``m[v[(index - 1) / 2].first]` `                ``= (index - 1) / 2 + 1;`   `            ``// updating index in map` `            ``index = (index - 1) / 2;` `        ``}` `    ``}` `};`   `void` `display(indexed_priority_queue<``int``, ``int``> IPQ)` `{` `    ``indexed_priority_queue<``int``, ``int``> temp = IPQ;` `    ``while` `(!IPQ.empty()) {` `        ``pair<``int``, ``int``> tmp;` `        ``tmp = IPQ.top();` `        ``IPQ.pop();` `        ``cout << ``"( "` `<< tmp.first << ``", "` `             ``<< tmp.second << ``" ) "``;` `    ``}` `    ``cout << ``'\n'``;` `}`   `// Driver Code` `int` `main()` `{`   `    ``// First parameter is key datatype` `    ``// and it should be hashable` `    ``// Second parameter is value datatype comparator` `    ``// function (by default it implements maxheap)` `    ``indexed_priority_queue<``int``, ``int``> IPQ;`   `    ``// Check if empty` `    ``cout << ``"Checking if initially the IPQ is empty\n"``;` `    ``if` `(IPQ.empty())` `        ``cout << ``"IPQ is empty\n"``;` `    ``else` `        ``cout << ``"IPQ is not empty\n"``;`   `    ``// Insertion` `    ``cout << ``"Inserting pairs (2, 1), (3, 7), "` `         ``<< ``" (1, 0) and (4, 5)\n"``;` `    ``IPQ.push(2, 1);` `    ``IPQ.push(3, 7);` `    ``IPQ.push(1, 0);` `    ``IPQ.push(4, 5);`   `    ``// Printing the contents of IPQ` `    ``cout << ``"IPQ: "``;` `    ``display(IPQ);` `    ``cout << ``'\n'``;`   `    ``// Checking size and top after pushing` `    ``cout << ``"Size: "` `<< IPQ.size() << endl;` `    ``cout << ``"Top: "` `<< IPQ.top().first` `         ``<< ``", "` `<< IPQ.top().second` `         ``<< ``"\n\n"``;`   `    ``// Replace operation` `    ``cout << ``"Changing value associated with"` `         ``<< ``" key 3 to 2 and 1 to 9\n"``;` `    ``IPQ.changeAtKey(3, 2);` `    ``IPQ.changeAtKey(1, 9);`   `    ``// Checking size and top after replacement` `    ``cout << ``"Size: "` `<< IPQ.size() << endl;` `    ``cout << ``"Top: "` `<< IPQ.top().first` `         ``<< ``", "` `<< IPQ.top().second` `         ``<< ``"\n\n"``;`   `    ``// Deleting 2 elements from IPQ` `    ``cout << ``"Poping an element from IPQ: "``;` `    ``IPQ.pop();` `    ``cout << ``"\nPoping an element from IPQ: "``;` `    ``IPQ.pop();` `    ``cout << ``'\n\n'``;`   `    ``// Printing the contents of IPQ after deletion` `    ``cout << ``"IPQ: "``;` `    ``display(IPQ);` `    ``cout << ``'\n'``;`   `    ``// Checking size and top after pushing` `    ``cout << ``"Size: "` `<< IPQ.size() << endl;` `    ``cout << ``"Top: "` `<< IPQ.top().first` `         ``<< ``", "` `<< IPQ.top().second` `         ``<< ``"\n\n"``;`   `    ``return` `0;` `}`

Output:Checking if initially the IPQ is empty IPQ is empty Inserting pairs (2, 1), (3, 7), (1, 0) and (4, 5) IPQ: ( 3, 7 ) ( 4, 5 ) ( 2, 1 ) ( 1, 0 ) Size: 4 Top: 3, 7 Changing value associated with key 3 to 2 and 1 to 9 Size: 4 Top: 1, 9 Poping an element from IPQ: Poping an element from IPQ: IPQ: ( 3, 2 ) ( 2, 1 ) Size: 2 Top: 3, 2

My Personal Notes arrow_drop_up
Recommended Articles
Page :