优先级队列
前言
- 用最大堆实现的最大优先级队列一般用来进行作业调度的问题
- 用最小堆实现的最小优先级队列一般用于贪心等
概念
优先级队列是一种用来维护一组元素构成的集合S的数据结构,这一组元素中的每一个都有一个关键字key。
这里以最大堆实现的最大优先级队列为例,支持如下操作:
- extract_max(A, n) : 去掉并返回A中的具有最大关键字的元素
- increase_key(A, i, key) : 将元素A[i]关键字变为key并且保持最大优先级队列的性质
实现
extract_max
/** * Description:从节点i开始,维护以i为根节点的子树,使以i为根的子树为最大堆(非递归) */ void maxHeapIfy(int *A, int i, int n) { int l, r, largest, temp, loc; for(largest = i; largest <= n;) { l = 2 * largest; r = 2 * largest + 1; loc = largest; if(l <= n && A[l] > A[largest]) { largest = l; } if(r <= n && A[r] > A[largest]) { largest = r; } //如果最大值不是根节点,那么交换A[loc], A[largest] if(largest != loc) { temp = A[largest]; A[largest] = A[loc]; A[loc] = temp; }else { break; } } } /** * Description:去掉并返回A中具有最大关键字的元素 */ int heapExtractMax(int *A, int n) { int max = A[1]; A[1] = A[n]; MaxHeapIfy(A, 1, n - 1); return max; }
heap_increase_key
/** * Description:将元素x的关键字的值增加到k * heapIncreaseKey && maxHeapIfy 区别: * heapIncreaseKey : 是当前结点的值增大了,因此要向上将父结点与该结点交换 * maxHeapIfy : 是保持当前结点为根的树是对,因此将当前结点与两个子结点比较,向下逐层恢复堆的性质。 */ void heapIncreaseKey(int *A, int i, int key) { int parent, exchange; for(A[i] = key, parent = i / 2; i >= 1 && A[parent] < A[i] && parent >= 1) { exchange = A[parent]; A[i] = A[parent]; A[i] = exchange; i = parent; parent = i / 2; } }
练习(哈夫曼树)
用最小堆实现求哈夫曼树的wpl
题目
题目描述: 哈夫曼树,第一行输入一个数n,表示叶结点的个数。需要用这些叶结点生成哈夫曼树,根据哈夫曼树的概念,这些结点有权值,即weight,题目需要输出所有结点的值与权值的乘积之和。 输入: 输入有多组数据。 每组第一行输入一个数n,接着输入n个叶节点(叶节点权值不超过100,2<=n<=1000)。 输出: 输出权值。 样例输入: 5 1 2 2 5 9 样例输出: 37
ac代码
#include <stdio.h> #include <string.h> #include <stdlib.h> #define MAX 1001 void minHeapIfy(int *A, int i, int n); void buildMinHeap(int *A, int n); int heapExtractMin(int *A, int n); void minHeapInsert(int *A, int i, int key); int main() { int i, j, n, huff[MAX], power, lchild, rchild, parent; while(scanf("%d", &n) != EOF) { //接收参数输入 for(i = 1; i <= n; i ++) scanf("%d", &huff[i]); //构建一个最小堆 buildMinHeap(huff, n); //获取wpl for(i = 1, j = n, power = 0; i < n; i ++) { lchild = heapExtractMin(huff, j); j -= 1; rchild = heapExtractMin(huff, j); parent = lchild + rchild; power += parent; minHeapInsert(huff, j, parent); } printf("%d\n", power); } return 0; } /** * Description:构建最小堆 */ void buildMinHeap(int *A, int n) { int i; for(i = n / 2; i >= 1; i --) { minHeapIfy(A, i, n); } } /** * Description:调整以i为根的最小堆 */ void minHeapIfy(int *A, int i, int n) { int l, r, min, loc, temp; for(min = i; min <= n;) { l = min * 2; r = min * 2 + 1; loc = min; if(l <= n && A[l] < A[min]) min = l; if(r <= n && A[r] < A[min]) min = r; if(min != loc) { temp = A[min]; A[min] = A[loc]; A[loc] = temp; }else { break; } } } int heapExtractMin(int *A, int n) { int min = A[1]; A[1] = A[n]; minHeapIfy(A, 1, n); return min; } /** * Description: * (1)将元素插入到最小优先队列 * (2)因为每次i == length(A),都是在对尾插入,因此只考虑i的parent,不考虑i的children */ void minHeapInsert(int *A, int i, int key) { int parent, change; for(A[i] = key, parent = i / 2; parent >= 1 && A[parent] > A[i];) { change = A[parent]; A[parent] = A[i]; A[i] = change; i = parent; parent = i / 2; } }