我们前面已经了解过什么是堆,现在我们来根据它的特征来研究如何建一个堆。
初始化,申请空间,给堆赋值
代码实现 typedef int Datatype; //创建堆的结构体 typedef struct Heap { Datatype* array; int capacity; int size; }Heap; //初始化堆 void InitHeap(Heap* hp,Datatype* array, int size) { assert(hp); hp->array = (Datatype*)malloc(sizeof(Datatype)* size); if (hp->array == NULL) { return; } hp->capacity = size; for (int i = 0; i < size; i++) { hp->array[i] = array[i]; } hp->size = size; //调整该二叉树;使其满足堆的性质 //找倒数第一个非叶子节点,开始向下调整,调用AdjustDown int leaflast = ((size - 2) >> 1); for (; leaflast >= 0;leaflast--) { AdjustDown(hp->array, size, leaflast); } } //交换 int Swap(int* a,int* b) { int tmp; tmp = *a; *a = *b; *b = tmp; } //向下调整 void AdjustDown(Datatype* array, int size, int parent) { int child = parent * 2 + 1; //默认标记左孩子 while (child < size) { //找左右孩子中的小孩子,右孩子要想存在 if (child+1<size && array[child + 1] < array[child]) { child += 1; //右比左小 child标记的小孩子更换 } if (array[child] < array[parent]) { Swap(&array[child], &array[parent]); parent = child; child = parent * 2 + 1; } else { return; } } }以上,我们的堆已经建成功,如果需要建大堆,我们可以左右孩子中的较大的孩子,与父母做出比较 ,判断是否需要交换。
那么如何利用堆的结构实现排序的功能。首先,将 N N N个元素建堆,如果升序排列建大堆,降序排列建小堆。然后将堆顶元素与最后一个元素交换,在将剩下的元素重新调整得到满足堆的新的堆顶元素,重复之前的步骤,每次元素的数量减一。最后,就可以得到我们要求的序列。
代码实现 //为实现排序调整堆(向下调整) void HeapAdjust(int* array,int size,int parent) { int child = parent * 2 + 1; //默认标记左孩子 while (child < size) { //找左右孩子中的小孩子,右孩子要想存在 if (child + 1 < size && array[child + 1] < array[child]) { child += 1; //右比左小 child标记的小孩子更换 } if (array[child] < array[parent]) { Swap(&array[child], &array[parent]); parent = child; child = parent * 2 + 1; } else { return; } } } //排序 void HeapSort(int* array, int size) { //找倒数第一个非叶子节点,得到小堆 int leaflast = ((size - 2) >> 1); for (; leaflast >= 0; leaflast--) { HeapAdjust(array, size, leaflast); } //堆顶元素与最后一个元素交换,再调整 int end = size - 1; while (end) { Swap(&array[0], &array[end]); HeapAdjust(array, end, 0); end--; } }时间复杂度: N l o g N Nlog{N} NlogN 以上,实现了降序的排列方式,若要实现升序,只需要建立大堆即可。
TOP k 问题:在 N N N个数据中找最大的或者最小的前 k k k个元素。求最大建小堆,求最小建大堆。(此处以找最大的前K各元素为例) 具体做法:
先遍历得到前 k k k个元素,建立堆。用剩下 N − k N-k N−k个元素与堆顶元素比较,比堆顶大就替换,比堆顶小就丢弃,再调整当前堆, 直到结束,就找到了最大的前 K K K个元素。时间复杂度 N l o g K NlogK NlogK