今天早上起来完成了一个完整的基于二叉堆实现的优先队列,其中包含最小优先和最大优先队列。
上篇说了优先队列的特性,通过建堆和堆排序操作,我们就已经看到了这种数据结构中的数据具有某种优先级别,要么非根节点大于他的子节点,要么就相反,在最大优先队列中最大优先级别就是指节点值最大的数据为根节点,每次出队时肯定是最大的先出去,反之则是最小优先队列,但要注意插入时的数据不一定是最大或最小的,优先队列会通过一点小技巧找到所有节点之间的关系并对应起来,重新使得你随意插入的数据满足优先队列的特性,因而这种数据结构的使用很普遍。比如:操作系统中的任务调度等。
用线性表实现这种数据结构并不难,下面是代码:
/**
* PrioityQueue(优先队列)
*/
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
typedef int ElemType;
typedef struct
{
ElemType * arr;
int size;
}Heap;
/* 全局函数 */
Heap * Initialize_Heap();
void Build_Min_Heap();
void Build_Max_Heap();
void Heap_Sort();
int Heap_Minimum();
int Heap_Maximum();
int Heap_Extract_Min();
int Heap_Extract_Max();
void Heap_Insert_Max();
void Heap_Insert_Min();
void Destroy_Heap();
/* 静态函数 */
static int HeapParent();
static int HeapLeft();
static int HeapRight();
static void Min_Heapify();
static void Max_Heapify();
static void Heap_Increase_Min_Key();
static void Heap_Increase_Max_Key();
/*
* 初始化堆
* 参数说明:无参数
*
* 返回堆
*/
Heap * Initialize_Heap(void)
{
Heap * heap;
heap = (Heap *)malloc(sizeof(Heap));
heap -> arr = (ElemType *)malloc(sizeof(ElemType));
heap -> size = -1;
return heap;
}
/*
* 节点i的双亲
*/
static int HeapParent(int i)
{
return i/2;
}
/*
* 节点i的左孩子
*/
static int HeapLeft(int i)
{
return 2*i + 1;
}
/*
* 节点i的右孩子
*/
static int HeapRight(int i)
{
return 2*(i + 1);
}
/*
* 维护最小堆的性质
*/
static void Min_Heapify(Heap * heap, int i)
{
int l = HeapLeft(i);
int r = HeapRight(i);
int smallest;
int temp;
if(l < heap -> size && heap -> arr[l] < heap -> arr[i])
smallest = l;
else
smallest = i;
if(r < heap -> size && heap -> arr[r] < heap -> arr[i])
smallest = r;
if(smallest != i)
{
temp = heap -> arr[i];
heap -> arr[i] = heap -> arr[smallest];
heap -> arr[smallest] = temp;
Min_Heapify(heap, smallest);
}
}
/*
* 维护最大堆的性质
*/
static void Max_Heapify(Heap * heap, int i)
{
int _L = HeapLeft(i);
int _R = HeapRight(i);
int largest;
int temp;
if(_L < heap -> size && heap -> arr[_L] > heap -> arr[i])
largest = _L;
else
largest = i;
if(_R < heap -> size && heap -> arr[_R] > heap -> arr[largest])
largest = _R;
if(largest != i)
{
temp = heap -> arr[i];
heap -> arr[i] = heap -> arr[largest];
heap -> arr[largest] = temp;
Max_Heapify(heap, largest);
}
}
/*
* 建最小堆
*/
void Build_Min_Heap(Heap * heap)
{
int i;
for(i = heap -> size/2; i >= 0; i--)
Min_Heapify(heap, i);
}
/*
* 建最大堆
*/
void Build_Max_Heap(Heap * heap)
{
int i;
for(i = heap -> size/2; i >= 0; i--)
Max_Heapify(heap, i);
}
/*
* 最大优先队列 - 排序
*/
void Heap_Sort(Heap * heap)
{
int i;
int temp;
Build_Max_Heap(heap);
for(i = heap -> size; i >= 0; i--)
{
temp = heap -> arr[0];
heap -> arr[0] = heap -> arr[i];
heap -> arr[i] = temp;
-- heap -> size;
Max_Heapify(heap, 0);
}
}
/*
* 最小优先队列 - 最小值
*/
int Heap_Minimum(Heap * heap)
{
return heap -> arr[0];
}
/*
* 最大优先队列 - 最大值
*/
int Heap_Maximum(Heap * heap)
{
return heap -> arr[0];
}
/*
* 最小优先队列 - 去除最小值节点
*/
int Heap_Extract_Min(Heap * heap)
{
int min;
if(heap -> size < 0)
{
fprintf(stderr, "Heap underflow!\n");
return 0;
}
min = heap -> arr[0];
heap -> arr[0] = heap -> arr[heap -> size];
heap -> arr[heap -> size] = min;
-- heap -> size;
Min_Heapify(heap, 0);
return min;
}
/*
* 最大优先队列 - 去除最大值节点
*/
int Heap_Extract_Max(Heap * heap)
{
int max;
if(heap -> size < 0)
{
fprintf(stderr, "Heap underflow!\n");
return 0; //提前退出
}
max = heap -> arr[0];
heap -> arr[0] = heap -> arr[heap -> size];
-- heap -> size;
Max_Heapify(heap, 0);
return max;
}
/*
* 将key的值赋给节点i。此处将key值插入最小堆中
*
* 参数说明:
* 1.接收一个已存在的堆
* 2.节点位置
* 3.与堆节后数据相同类型的键值
*/
static void Heap_Increase_Min_Key(Heap * heap, int i, ElemType key)
{
int temp;
if(key > heap -> arr[i])
{
printf("请输入小于当前节点值的数据\n");
return ;
}
heap -> arr[i] = key;
while(i > 0 && heap -> arr[HeapParent(i)] > heap -> arr[i])
{
temp = heap -> arr[i];
heap -> arr[i] = heap -> arr[HeapParent(i)];
heap -> arr[HeapParent(i)] = temp;
i = HeapParent(i);
}
}
/*
* 将key的值赋给节点i。此处将key值插入最大堆中
*
* 参数说明:
* 1.接收一个已存在的堆
* 2.节点位置
* 3.与堆节后数据相同类型的键值
*/
static void Heap_Increase_Max_Key(Heap * heap, int i, ElemType key)
{
int temp;
if(key < heap -> arr[i])
{
printf("请输入大于当前节点值的数据\n");
return ;
}
heap -> arr[i] = key;
while(i > 0 && heap -> arr[HeapParent(i)] < heap -> arr[i])
{
temp = heap -> arr[i];
heap -> arr[i] = heap -> arr[HeapParent(i)];
heap -> arr[HeapParent(i)] = temp;
i = HeapParent(i);
}
}
/*
* 将key值插入最小堆
*/
void Heap_Insert_Min(Heap * heap, ElemType key)
{
++ heap -> size;
heap -> arr[heap -> size] = 65533;
Heap_Increase_Min_Key(heap, heap -> size, key);
}
/*
* 将key值插入最大堆
*/
void Heap_Insert_Max(Heap * heap, ElemType key)
{
++ heap -> size;
heap -> arr[heap -> size] = -65533;
Heap_Increase_Max_Key(heap, heap -> size, key);
}
/*
* 如果堆存在则销毁堆
*
* 无参数/返回值
*/
void Destroy_Heap(Heap * heap)
{
if(heap && heap -> arr)
{
free(heap -> arr);
free(heap);
heap = NULL;
}
}
// 主函数
int main(void)
{
ElemType val;
Heap * heap;
char c;
int i, cont = 0;
heap = Initialize_Heap();
puts("1) Insert Heap 2) Extract Max");
puts("3) Display 4) Exit");
while((c = getch()) != '4')
{
switch(c)
{
case '1' : cont ++;
printf("Enter key:");
scanf("%d", &val);
Heap_Insert_Max(heap, val);
break;
case '2' : cont --;
printf("Max key = %d\n", Heap_Extract_Max(heap));
break;
case '3' : Build_Max_Heap(heap);
printf("显示数据:\n");
for(i = 0; i < cont; i++)
printf("%d ", heap -> arr[i]);
printf("NULL\n");
break;
}
}
// Destroy_Heap();
return 0;
}
参考资料:1.《算法导论》- 堆排序 (84~93)。
3.百度百科 - 堆