今天为大家介绍的是堆的另一种应用,优先队列,之前也为大家介绍过堆排序,今天则主要介绍优先队列,优先队列和堆一样也有两种形式:最大优先队列和最小优先队列,这里,我们关注于如何基于最大堆实现最大优先队列。优先队列(priority queue)是一种用来维护由一组元素构成的集合S的数据结构,其中的每一个元素都有一个相关的值,称为关键字(key),一个最大优先队列支持以下操作:
heap_maximum(int *data,int n):返回集合中具有最大键值的元素。
heap_extract_max(int *data,int n):去掉并返回集合中具有最大键值的元素。
heap_increase_key(int *data,int i,int key):将元素i的关键字值增加到key,这里假设i的值不小于i的原关键字值。
最大优先队列的应用有很多,其中一个就是共享计算机系统的作业调度,最大优先队列记录将要执行各个作业以及它们之间的相对优先级。当一个作业完成或者被中断后,调度器调用heap_maximum从所有等待作业中,选出具有最高优先级的作业来执行。在任何时候,调度器可以调用插入操作把一个新的作业加入到队列来。
现在,我们来讨论如何实现最大优先队列的操作:
其中pri_queue.h和pri_queue.c 的具体实现如下:
#ifndef _MAXQU_H_ #define _MAXQU_H_ #define N 10 //接口声明 //大根堆的生成过程 //调整为大根堆的过程 void Max_heapify(int *data,int i ,int n); //从无序的输入数据数组中构造一个最大堆 void Build_max_heap(int *data,int n); //对一个无序数组进行原址排序 void Heap_sort(int *data,int n); //打印数组 void print_array(int *data,int n); //对于优先队列的接口声明 //返回集和中具有最大键值的元素 int heap_maximum(int *data,int n); //去掉并返回集和中具有最大键值的元素 int heap_extract_max(int *data,int n); //将元素的关键字值增加到k,(假设k的值不小于原关键字值) void heap_increase_key(int *data,int i,int key); #endif接口的实现:
#include <stdio.h> #include <stdlib.h> #include "tools.h" #include "max_queue.h" static void swap(int *a,int *b) { int temp; temp = *a; *a = *b; *b = temp; } static int Left(int i) { return 2 * i; } static int Right(int i) { return 2 * i + 1; } static int Parent(int i) { return i / 2; } //调整为大根堆 void Max_heapify(int *data,int i,int n) { int left = Left(i); int right = Right(i); int largest = 0; int length = n; if(left <= length && data[left - 1] > data[i - 1]){ largest = left; }else{ largest = i; } if(right <= length && data[right - 1] > data[largest - 1]){ largest = right; } if(largest != i){ swap(&data[i - 1],&data[largest - 1]); Max_heapify(data,largest,n); } } void Build_max_heap(int *data,int n) { int i = 0; for(i = n / 2;i >= 1;i--){ Max_heapify(data,i,n); } } void Heap_sort(int *data,int n) { int length = n; int i = 0; Build_max_heap(data,n); for(i = length;i >= 1;--i){ swap(&data[i - 1], &data[0]); n--; Max_heapify(data,1,n); } } void print_array(int *data,int n) { int i = 0; for( i = 0; i < n; ++i){ printf("%5d",data[i]); } printf("\n"); } //对于优先队列的接口声明 //返回集和中具有最大键值的元素 int heap_maximum(int *data,int n) { //步骤:将数据集和调整成大根堆后 //只用返回A[0],利用大根堆的性质 return data[0]; } //去掉并返回集和中具有最大键值的元素 int heap_extract_max(int *data,int n) { int max = 0; max = data[0]; data[0] = data[n - 1]; n = n - 1; Max_heapify(data,1,n); return max; } //将元素的关键字值增加到k,(假设k的值不小于原关键字值) void heap_increase_key(int *data,int i,int key) { if(key < data[i - 1]){ return; } data[i - 1] = key; while(i > 1 && (data[Parent(i) - 1] < data[i - 1])){ swap(&data[Parent(i) - 1],&data[i - 1]); i = Parent(i); } }
#ifndef _TOOLS_H_ #define _TOOLS_H_ #include <stdio.h> #include <stdlib.h> //定义布尔类型 #define TRUE (1) #define FALSE (0) typedef unsigned char Boolean; //定义接口 void *Malloc(size_t size); void *Realloc(void * ptr,size_t size); void print_int(void *value); #endif工具文件接口的实现过程:
#include <stdio.h> #include <stdlib.h> #include "tools.h" void *Malloc(size_t size) { void *result = malloc(size); if(result == NULL){ fprintf(stderr,"the memory is full!\n"); exit(1); } return result; } void *Realloc(void * ptr,size_t size) { void *result = realloc(ptr,size); if(result == NULL){ fprintf(stderr,"the memory is full!\n"); exit(1); } return result; } void print_int(void *value) { int *p = (int *)value; printf("%5d",*p); }
#include <stdio.h> #include <stdlib.h> #include "max_queue.h" int main(int argc,char **argv) { int data[N]; int i = 0; int t = 0; srand(time(0)); for(i = 0;i < N;++i){ data[i] = rand() % 100; } //将数据集和逻辑生成大根堆 Build_max_heap(data,N); printf("大根堆:\n"); print_array(data,N); printf("大根堆的根元素:\n"); printf("%5d\n",heap_maximum(data,N)); t = heap_extract_max(data,N); printf("删除最大元素:\n"); print_array(data,N); printf("将队头元素增加至100:\n"); heap_increase_key(data,1,100); print_array(data,N); return 0; }