下面是自己手写的优先队列模板(默认是大顶堆,可通过重载小于号改变)
用法说明如下:
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 }
浙公网安备 33010602011771号