都说数据结构是算法的加速剂,这句话在优先队列的身上得到了很好的体现。
我们看名字就知道,优先队列肯定和队列是同一个家族的,只不过不同的是,队列的出队是按照位置来的,每次都是前面的第一个元素出队。而优先队列的出队顺序是按照优先级来的,在有些情况下,我们需要进行大量的取集合中最大或最小值的操作,那么就可以用优先队列来完成。优先队列支持插入和取最大或最小值操作并将其删除。
优先队列是由堆来实现的,堆是一种二叉树:儿子的值一定不小于/不大于爸爸的值,堆的例子:(挑战程序设计上的,这里的堆是小顶堆 ,就是取最小值很快)
heap取最大值或最小值的速度特别快,看图就可以知道,最小值就是top的位置,所以其取最大值/最小值时间复杂度低至O(1)
实现 | 插入 | 删除 | 寻找最值 |
无序数组 | O(1) | O(n) | O(n) |
无序列表 | O(1) | O(n) | O(n) |
有序数组 | O(n) | O(1) | O(1) |
有序列表 | O(n) | O(1) | O(1) |
二叉搜索树 | O(log n) | O(log n) | O(lon g) |
平衡二叉搜索树 | O(log n) | O(log n) | O(log n) |
堆 | O(log n) | O(log n) | O(1) |
在c++中使用优先队列:
在实际做题的过程中,并不需要我们实现堆,C++中的stl已经封装好了,我们只需要会用就行,这样可以帮助我们把更多的精力放在算法的设计上。
首先需要引用头文件: include<queue>
我们可以使用如下操作:
name.empty() | 判断队列是否为空,为空返回1 |
name.size() | 返回队列中的元素个数 |
name.pop() | 删除堆顶,不返回值,类似dequeue |
name.top() | 取堆顶的值,不删除 |
name.push(Elem) | 插入elem到队列中,类似enqueue |
由于优先级队列默认为高优先级,而有时候我们想自定义其优先级。priority_queue的模板带三个参数:priority_queue<Type, Container, Function>,分别是元素类型,存储的容器和比较的方式,注意这里的container不能用list,最好用vector。
使用priority_queue需要注意的:
1、由于priority_queue默认为高优先级,所以如果我们省略后面两个参数:priority_queue<Type>,则就是大顶堆。
2、如果要使用小顶堆,则需要将模板的三个参数都带进去,STL里面定义了仿函数greater< >,使用这个可以声明小顶堆:priority_queue<int, vector, greater<int>>。
3、如果是自定义,则需要重载operator<来实现:
#include <iostream> #include <queue> using namespace std; struct Node{ int x, y; Node( int a= 0, int b= 0 ): x(a), y(b) {} }; bool operator<( Node a, Node b ){//升序 if( a.x== b.x ) return a.y> b.y; return a.x> b.x; } int main(){ priority_queue<Node> q; for( int i= 0; i< 10; ++i ) q.push( Node( rand(), rand() ) ); //构造函数 while( !q.empty() ){ cout << q.top().x << ' ' << q.top().y << endl; q.pop(); } getchar(); return 0; }
4、自定义cmp
struct cmp{ bool operator() ( Node a, Node b ){ if( a.x== b.x ) return a.y> b.y; return a.x> b.x; } }; priority_queue<int, vector<int>, cmp>
优先级队列是一种特别重要的数据结构,在许多算法中都可以看到它的影子,比如哈夫曼编码、 Dijkstra算法、Prim算法、寻找第k个最小元素等等...所以需要好好掌握。
3.27更新手写堆:
#include<iostream> #include<algorithm> #define LE(X) ((X) << 1) #define RT(X) ((X) << 1 | 1) #define DAD(X) ((X) >> 1) using namespace std; struct heap { int w[400005]; int tot; int top() { return w[1]; } void modify(int x) { if(x == 1) return; if(w[x] > w[DAD(x)]) { swap(w[x] , w[DAD(x)]); modify(DAD(x)); } } void push(int key) { w[++tot] = key; modify(tot); } void repair(int x) { int tar = w[LE(x)] > w[RT(x)] ? LE(x) : RT(x); if(w[x] < w[tar]) { swap(w[x] , w[tar]); repair(tar); } } void pop() { swap(w[1] , w[tot]); w[tot--] = 0; repair(1); } }; int main() { heap hp; hp.push(1); hp.push(2); cout << hp.top() << endl; hp.pop(); cout << hp.top() << endl; return 0; }
Comments NOTHING