索引优先队列与实施
- 最后更新: 2021年8月4日
优先级队列是一种数据结构,其中的数据是根据其优先级存储的。在索引优先级队列中,数据的存储方式与标准优先级队列相同,同时,数据的值可以使用其键值进行更新。它被称为 "索引",因为哈希图可以用来存储容器中的索引,使用键值对输入的键作为哈希图的键。这在使用min-heap实现Dijkstra算法时很方便。它也可以用在任何其他需要将键值对放入优先队列的程序中,同时你需要用push或pop函数来更新键值。
**索引优先队列中的操作。**在索引优先级队列中可以进行的操作有。
-
推动 。 在索引的优先级队列中根据其优先级添加键值对。
_实现。要_做到这一点,在容器中添加键值对,然后根据键值对的值进行堆积。
_时间复杂度。_O( log(n) )
-
流行。 移除最高优先级的键值对。
_实现方法。_移除堆的顶部,然后堆化容器的其余部分。
_时间复杂度。_O( log(n))
-
顶部:将键值对返回给用户。
_实现。返_回位于堆顶的键值对。
_时间复杂度。_O(1)
-
大小:返回索引优先级队列中的键值对的数量。
_实现:跟踪队列中的元素数量,并在调用size()函数时返回该变量。_保持跟踪类中队列中的元素数量,并在调用size()函数时返回该变量。
_时间复杂度。_O(1)
-
空:: 当索引优先级队列为空时,返回true。
_实现:当元素数变量等于零时,返回真。_当元素数变量等于零时返回真。
_时间复杂度。_O(1)
-
changeAtKey:这个函数将索引优先级队列与标准优先级队列区分开来。它从用户那里得到两个参数,第一个是键,第二个是新值,它将与键相关的旧值更新为提供的新值,并根据新值的优先级更新其位置。
_实现。保_持一个哈希映射,其键是键值对中的键,它指向容器中键的索引。当函数被调用时,更新所需索引的值,并根据其优先级定位当前元素,最后改变哈希图中的索引值。
_时间复杂度。_O( log(n) )
索引式优先级队列的实现。
索引式优先级队列是用二进制堆实现的,但是它也可以用斐波那契堆或K-ary堆实现。
在定义索引优先级队列的实例时,有四个参数需要传递(两个必须的,两个可选的),它们是:。
- 键的数据类型。 这是定义中的第一个参数,它应该是可以在哈希图中被哈希的数据类型,或者用户可以把自己的哈希函数作为第四个参数。要了解更多关于哈希图中的哈希函数,请看这篇文章。
- 值的数据类型。这是定义中的第二个参数。
- 比较器。这是第三个参数,也是可选参数。默认情况下,索引优先级队列将使用最大堆来实现,用户必须将不同的比较器与它的参数(即比较器的参数)作为值的数据类型。
- 哈希函数。这是第四个参数,只有当用户为键传递自定义数据类型(如类)时才需要,然后用户必须传递自己的哈希函数。
下面是索引优先队列的实现。
C++
// C++ program for the above approach#include <bits/stdc++.h>using namespace std;template <class T1,class T2,class Comparator = less<T2>,class Hash = hash<T1> >class indexed_priority_queue {// Storing indices of values using keyunordered_map<T1,long long int, Hash> m;// Containervector<pair<T1, T2> > v;// Sizelong long numberOfElement;// Creating a instance of Comparator classComparator comp;// Max Capacitylong long capacity = LLONG_MAX;// Obtaing the index value from hash maplong long int getValueIndex(T1 key){if (m[key] == 0) {cout <<"No Such Key Exist";return -1;}return v[m[key] - 1];}// heapify the containervoid heapify(vector<pair<T1, T2> >& 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 valuepair<T1, T2> temp = v[index];v[index] = v[suitableNode];v[suitableNode] = temp;// updating the mapm[v[index].first] = index + 1;m[v[suitableNode].first]= suitableNode + 1;// heapify other affected nodesheapify(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 elementv.push_back(make_pair(key, value));numberOfElement++;m[key] = numberOfElement;long long index = numberOfElement - 1;// Comparing to parent nodewhile (index != 0&& comp(v[(index - 1) / 2].second,v[index].second)) {// swap the valuepair<T1, T2> temp = v[index];v[index] = v[(index - 1) / 2];v[(index - 1) / 2] = temp;// updating the mapm[v[index].first] = index + 1;m[v[(index - 1) / 2].first]= (index - 1) / 2 + 1;// updating index in mapindex = (index - 1) / 2;}}void pop(){if (numberOfElement == 0) {cout <<"UnderFlow";return;}// Removing elementv.erase(v.begin());numberOfElement--;heapify(v, numberOfElement, 0);}pair<T1, T2> top() {return v[0]; }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 nodesheapify(v, numberOfElement, index);// Comparing to Parent Nodewhile (index != 0&& comp(v[(index - 1) / 2].second,v[index].second)) {// swap the valuepair<T1, T2> temp = v[index];v[index] = v[(index - 1) / 2];v[(index - 1) / 2] = temp;// updating the mapm[v[index].first] = index + 1;m[v[(index - 1) / 2].first]= (index - 1) / 2 + 1;// updating index in mapindex = (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 Codeint 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 emptycout <<"Checking if initially the IPQ is empty\n";if (IPQ.empty())cout <<"IPQ is empty\n";elsecout <<"IPQ is not empty\n";// Insertioncout <<"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 IPQcout <<"IPQ: ";display(IPQ);cout <<'\n';// Checking size and top after pushingcout <<"Size: " << IPQ.size() << endl;cout <<"Top: " << IPQ.top().first<<", " << IPQ.top().second<<"\n\n";// Replace operationcout <<"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 replacementcout <<"Size: " << IPQ.size() << endl;cout <<"Top: " << IPQ.top().first<<", " << IPQ.top().second<<"\n\n";// Deleting 2 elements from IPQcout <<"Poping an element from IPQ: ";IPQ.pop();cout <<"\nPoping an element from IPQ: ";IPQ.pop();cout <<'\n\n';// Printing the contents of IPQ after deletioncout <<"IPQ: ";display(IPQ);cout <<'\n';// Checking size and top after pushingcout <<"Size: " << IPQ.size() << endl;cout <<"Top: " << IPQ.top().first<<", " << IPQ.top().second<<"\n\n";return 0;} |
输出。
检查最初IPQ是否为空
IPQ为空插入对(2,1),(3,7),(1,0)和(4,5)
IPQ: ( 3,7 ) ( 4,5 ) ( 2,1 ) ( 1,0 )大小:4
顶部:3, 7将与键3相关的值改为2,将1改为9
大小:4
顶部:1,9从IPQ弹出一个元素:
从IPQ弹出一个元素。IPQ: ( 3, 2 ) ( 2, 1 )
大小: 2
顶部: 3, 2
读者请注意!现在不要停止学习。掌握所有重要的DSA概念。 DSA自学课程以适合学生的价格获得所有重要的DSA概念,并成为行业的准备者。 要完成从学习语言到DS Algo以及更多的准备工作,请参考 完整的面试准备课程.
如果你想参加专家的现场课程 ,请参考 面向在职人士的DSA现场课程 和 面向学生的竞争性编程直播.
我的个人笔记 arrow_drop_up
保存