今天早上起来完成了一个完整的基于二叉堆实现的优先队列,其中包含最小优先和最大优先队列。
上篇说了优先队列的特性,通过建堆和堆排序操作,我们就已经看到了这种数据结构中的数据具有某种优先级别,要么非根节点大于他的子节点,要么就相反,在最大优先队列中最大优先级别就是指节点值最大的数据为根节点,每次出队时肯定是最大的先出去,反之则是最小优先队列,但要注意插入时的数据不一定是最大或最小的,优先队列会通过一点小技巧找到所有节点之间的关系并对应起来,重新使得你随意插入的数据满足优先队列的特性,因而这种数据结构的使用很普遍。比如:操作系统中的任务调度等。
用线性表实现这种数据结构并不难,下面是代码:
/** * 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! "); 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! "); 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("请输入小于当前节点值的数据 "); 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("请输入大于当前节点值的数据 "); 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 ", Heap_Extract_Max(heap)); break; case '3' : Build_Max_Heap(heap); printf("显示数据: "); for(i = 0; i < cont; i++) printf("%d ", heap -> arr[i]); printf("NULL "); break; } } // Destroy_Heap(); return 0; }
参考资料:1.《算法导论》- 堆排序 (84~93)。
3.百度百科 - 堆