下面是自己手写的优先队列模板(默认是大顶堆,可通过重载小于号改变)
用法说明如下:
1)priority_queue部分(用法参照stl)
c-free库函数帮助里提供的priority_queue用法说明如下:
C++优先队列类似队列,但是在这个数据结构中的元素按照一定的断言排列有序。
empty() | 如果优先队列为空,则返回真 |
pop() | 删除第一个元素 |
push() | 加入一个元素 |
size() | 返回优先队列中拥有的元素的个数 |
top() | 返回优先队列中有最高优先级的元素 |
2)堆的基本堆操作部分。
用法如下:
set_size() | 设置堆的大小 |
set_value() | 设置堆中第id个元素的值 |
creat_heap() | 创建一个初始堆 |
heap_sort() | 堆排序,默认从小到大排,可通过重载小于号实现按指定规则排序 |
is_heap() | 判断是否构成一个堆 |
模板如下:
#define MAXN 25500 typedef struct RedType { int left, right; int weight; bool friend operator < (const RedType &a, const RedType &b) { return a.weight > b.weight; } }Edge; class priority_queue { private : RedType r[MAXN]; int length; void heap_adjust(int s, int m) { RedType rc = r[s]; for (int j = s << 1; j <= m; j <<= 1) { if (j < m && r[j] < r[j+1]) j++; if (!(rc < r[j])) break; r[s] = r[j]; s = j; } r[s] = rc; } public : priority_queue() { length = 0; } /*===========下面是堆操作部分,建堆,堆排等=============*/ void creat_heap() { for (int i = length >> 1; i > 0; i--) { heap_adjust(i, length); } } void set_size(int length) { this->length = length; } void set_value(int id, RedType value) { r[id] = value; } void heap_sort() { for (int i = length; i > 1; i--) { RedType tmp = r[1]; r[1] = r[i]; r[i] = tmp; heap_adjust(1, i - 1); } } bool is_heap() { int len = length >> 1 - 1, j; if (len < 1) { if (length == 1 || (!(r[1] < r[length]) && !(r[1] < r[length - 1]))) return true; return false; } for (int i = 1; i <= len; i++) { j = i << 1; if (r[j] < r[j + 1]) j++; if (r[i] < r[j]) return false; } return true; } /*==下面函数虽无stl强大,但用法类似(用堆实现的priority_queue)==*/ void push(RedType rc) { ++length; r[length] = rc; int s = length >> 1; for (int j = length; j > 1; j >>= 1) { if (!(r[s] < r[j])) break; RedType tmp = r[s]; r[s] = r[j]; r[j] = tmp; s >>= 1; } } void pop() { RedType tmp = r[1]; r[1] = r[length]; r[length] = tmp; heap_adjust(1, --length); } RedType top() { return r[1]; } int size() { return length; } bool empty() { if (length <= 0) return true; return false; } };
基本函数说明及复杂度分析如下:
heap_adjust()从第一个不满足堆的结点s开始向下做调整,使得维护一个堆。
--------log(n)
push()从尾部增加一个叶子节点到堆中,因为原本是满足堆的,所以只需要从下至上不断跟父结点进行交换,直至已满足堆退出
--------log(n)
pop()把start跟end做交换,然后[start,end-1]从新做一次调整,使得[start,end-1]维护成一个堆,堆大小length随之-1。
--------log(n)
creat_heap() 从第一个非终端结点开始->根节点不断做heap_adjust(),使之构成一个初始堆。
--------n / 2 * log(n)
heap_sort() 相当于重复n次pop()操作,但length不改变。
--------n * log(n)
is_heap() 判断是否构成堆,堆大小小于4时由外面的if判定,避免for循环内增加多余判断
--------n / 2.
模板使用举例:
http://acm.hdu.edu.cn/showproblem.php?pid=3371 最小生成树
3358493 | 2010-12-23 21:34:41 | Accepted | 3371 | 500MS | 484K | 3659 B | C++ | Slave_wc |
#include <stdio.h> #include <string.h> #define MAXN 25500 #define MAXN 25500 typedef struct RedType { int left, right; int weight; bool friend operator < (const RedType &a, const RedType &b) { return a.weight > b.weight; } }Edge; class priority_queue { private : RedType r[MAXN]; int length; void heap_adjust(int s, int m) { RedType rc = r[s]; for (int j = s << 1; j <= m; j <<= 1) { if (j < m && r[j] < r[j+1]) j++; if (!(rc < r[j])) break; r[s] = r[j]; s = j; } r[s] = rc; } public : priority_queue() { length = 0; } /*===========下面是堆操作部分,建堆,堆排等=============*/ void creat_heap() { for (int i = length >> 1; i > 0; i--) { heap_adjust(i, length); } } void set_size(int length) { this->length = length; } void set_value(int id, RedType value) { r[id] = value; } void heap_sort() { for (int i = length; i > 1; i--) { RedType tmp = r[1]; r[1] = r[i]; r[i] = r[1]; heap_adjust(1, i - 1); } } bool is_heap() { int len = length >> 1 - 1, j; if (len < 1) { if (length == 1 || (!(r[1] < r[length]) && !(r[1] < r[length - 1]))) return true; return false; } for (int i = 1; i <= len; i++) { j = i << 1; if (r[j] < r[j + 1]) j++; if (r[i] < r[j]) return false; } return true; } /*==下面函数虽无stl强大,但用法类似(用堆实现的priority_queue)==*/ void push(RedType rc) { ++length; r[length] = rc; int s = length >> 1; for (int j = length; j > 1; j >>= 1) { if (!(r[s] < r[j])) break; RedType tmp = r[s]; r[s] = r[j]; r[j] = tmp; s >>= 1; } } void pop() { RedType tmp = r[1]; r[1] = r[length]; r[length] = tmp; heap_adjust(1, --length); } RedType top() { return r[1]; } int size() { return length; } bool empty() { if (length <= 0) return true; return false; } }; priority_queue heap; int set[MAXN]; bool hash[MAXN]; int find(int x) { int r = x; while (r != set[r]) r = set[r]; int i = x, j; while (i != r) { j = set[i]; set[i] = r; i = j; } return r; } bool merge(int x, int y) { int fx = find(x); int fy = find(y); if (fx != fy) { set[fx] = fy; return true; } return false; } void Init(int n) { for (int i = 0; i <= n; i++) { set[i] = i; hash[i] = false; } } void kruscal(int n, int num); void input() { int test, n, m, k; Edge cur; scanf("%d", &test); while (test--) { scanf("%d %d %d", &n, &m, &k); Init(n); heap.set_size(m); for (int i = 1; i <= m; i++) { scanf("%d %d %d", &cur.left, &cur.right, &cur.weight); heap.set_value(i, cur); } heap.creat_heap(); int t, a, b, num = 0, nn = 0, nk = 0; for (int i = 1; i <= k; i++) { scanf("%d %d", &t, &a); hash[a] = true; for (int j = 2; j <= t; j++) { scanf("%d", &b); merge(a, b); hash[b] = true; } } for (int i = 1; i <= n; i++) if (hash[i]) nn++; for (int i = 1; i <= n; i++) { if (hash[i] && set[i] == i) nk++; } num = nn - nk; kruscal(n, num); } } void kruscal(int n, int num) { int sum = 0; while (!heap.empty() && num < n - 1) { Edge cur = heap.top(); heap.pop(); if (merge(cur.left, cur.right)) { sum += cur.weight; num++; } } if (num == n - 1) { printf("%d\n", sum); } else { puts("-1"); } } int main() { input(); return 0; }
效率分析:
上面代码是通过creat_heap()建堆,如果通过push逐个压入,则由上面复杂度分析可知,建堆过程复杂度提高一倍。
(n/2*log(n)到n*log(n))
经检测,上面代码改成通过push逐个压入建堆的方式,效率在700+ms。
如果改成用#include <queue>头文件自带的priority_queue, 则同样是通过push完成建堆,效率在800+ms以上。
原创文章如转载请注明:转自¥忘%风 {http://www.cnblogs.com/slave_wc}
本文地址:
堆实现的优先队列模板 {http://www.cnblogs.com/slave_wc/archive/2010/12/23/1915293.html }