实现优先列队的最普遍的工具是二叉堆,有时也只叫做堆。
二叉堆有两个性质:结构性和堆序性。
结构性:堆是一颗被完全填满的二叉树,底层除外,底层元素从左到右依次填入,对于一个完全二叉树,用一个数组来表示一棵树,发现对于数组的任意位置i的元素,他的左儿子在2i处,右儿子在2i+1出,父亲在i/2向下取整处。
堆序性:如果想要快速找出最小元素,那么任意节点就应该小于它所有的后裔,如果想要快速找到最大的元素,则相反。
二叉堆在概念上抽象为一颗二叉树,满足上面的两个性质,在程序中则实际上为一个数组,同样满足上面的两个性质。
下面给出最小堆(即可以以常数时间找出最小元素)的一个代码实现:
#include<iostream> using namespace std; #define MinPQSize 10 #define MinData -1 struct Heapstruct; typedef struct Heapstruct* PriorityQueue; struct Heapstruct { int Capacity; int Size; int *Elements; }; PriorityQueue Init_priorityqueue(int MaxElements) //创建并初始化一个优先列队 { PriorityQueue H; if(MaxElements < MinPQSize) cout << "Priority queue size is too small" << endl; H = (PriorityQueue)malloc(sizeof(Heapstruct)); if(H == NULL) cout << "out of space" << endl; H->Elements = (int*)malloc(sizeof(int) * MaxElements + 1); if(H->Elements == NULL) cout << "out of space" << endl; H->Capacity = MaxElements; H->Size = 0; H->Elements[0] = MinData; for(int i = 1; i <= H->Capacity; ++i) { H->Elements [i] = 0; //全部幅值为0 } return H; } void Destroy(PriorityQueue H) //释放一个优先列队 { free(H->Elements); free(H); } void MakeEmpty (PriorityQueue H) { for(int i = 1; i <= H->Capacity; ++i) { H->Elements[i] = 0; } H->Size = 0; } bool IsEmpty (PriorityQueue H) { if(H->Size == 0) return true; else return false; } bool IsFull (PriorityQueue H) { if(H->Size == H->Capacity ) return true; else return false; } void Insert(int Key,PriorityQueue H) { int i; if(IsFull(H)) { cout << "Priority queue is full" << endl; return; } //优先列队的队首元素一定为最下元素,插入时先在最后创建一个空穴,在把这个空穴上滤 //对于优先列队的任意位置i的元素,他的左儿子在2i处,右儿子在2i+1出,父亲在i/2向下取整处 for (i = ++H->Size; H->Elements[i/2] > Key; i /= 2) H->Elements[i] = H->Elements[i/2]; H->Elements[i] = Key; } int DeleteMin(PriorityQueue H) { int i, Child; int MinElement, LastElement; if(IsEmpty(H)) { cout << "Priority queue if Empty" << endl; return H->Elements[0]; } MinElement = H->Elements[1]; LastElement = H->Elements[H->Size--]; //思想很巧妙,空穴从最低一个位子一直下滤 for(i = 1; i * 2 <= H->Size; i = Child) { //寻找小的儿子 Child = i * 2; if(Child != H->Size && H->Elements[Child + 1] < H->Elements[Child]) Child ++; if(LastElement > H->Elements[Child]) H->Elements[i] = H->Elements[Child]; else break; } H->Elements[i] = LastElement; return MinElement; } int main () { PriorityQueue H = Init_priorityqueue(11); Insert(16, H); Insert(26, H); Insert(13, H); Insert(14, H); Insert(19, H); Insert(69, H); Insert(32, H); Insert(21, H); Insert(31, H); for (int i = 0; i <= 9; ++i) { cout << DeleteMin(H) << endl; } return 0; }
因为二叉堆的堆序性,所以可以用来排序,即堆排序,以后会具体论述。
夜深了,,,
从未提起,从未忘记。