堆实现的优先队列模板

下面是自己手写的优先队列模板(默认是大顶堆,可通过重载小于号改变)

用法说明如下:

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 }

你可能感兴趣的:(优先队列)