1.头文件
#pragma once
#include <stdio.h>
#include <malloc.h>
#include <assert.h>
#include <stdlib.h>
#define N 1000
typedef int HPDataType;
typedef struct Heap
{
HPDataType* _a;
int size;
int capacity;
}Heap;
void HeapInit(Heap* hp, HPDataType* a, int n); //初始化
void HeapDestory(Heap* hp); //销毁
void PrintHeap(Heap* hp, int n); //打印
void PushHeap(Heap* hp, HPDataType x); //添加
void PopHeap(Heap* hp); //删除
int HeapSize(Heap* hp);
int HeapEmpty(Heap* hp);
HPDataType HeapTop(Heap* hp); //堆顶
void HeapSort(HPDataType* a, int n); //堆排序
void HeapTopK(HPDataType* a, int n, int k); //TopK问题
void AdJustUp(HPDataType* a, int n, int child); //从child元素,向上调整成大(小)堆
void AdJustDown(HPDataType* a, int n, int child); //从parent元素,向下调整成大(小)堆
2.调堆
void AdJustUp(HPDataType* a, int n, int child) //三个参数:数组,元素个数,要调整元素的下标
{
int parent = (child - 1) / 2; //算出它的父亲节点的下标
while (child > 0)
{
if (a[parent] > a[child])
{
Swap(&a[parent], &a[child]);
child = parent;
parent = (child - 1) / 2;
}
else
break;
}
}
void AdJustDown(HPDataType* a,int n, int parent) //从第一个非叶节点进行调整
{
int child = parent * 2 + 1; //左孩子
while (child < n)
{
if ((child + 1)<n && a[child] > a[child + 1])
child++;
if (a[child] < a[parent]) //出来之后child总是较大孩子的下标
{
Swap(&a[child], &a[parent]);
parent = child;
child = parent * 2 + 1;
}
else
break;
}
}
3.初始化数组成为大(小)堆
void HeapInit(Heap* hp, HPDataType* a, int n) //初始化 n是数组元素个数
{
assert(hp && a);
hp->_a = (HPDataType*)malloc(sizeof(HPDataType)*n*2); //_a是指针,用来维护数组a
hp->capacity = n*2;
hp->size = 0;
int i = 0;
for (i=0; i < n; i++) //把数组复制到开辟的内存中去
{
hp->_a[i] = a[i];
hp->size++;
}
//调堆
for (i = (n-2)/2; i >= 0;i--) //(n-2)/2是最后一个非叶节点的双亲节点的下标
{
AdJustDown(hp->_a,hp->size, i);
}
}
4.堆排序
void HeapSort(HPDataType* a, int n) //堆排序
{
assert(a);
int i = 0;
int end = n - 1;
//调堆
for (i = (n - 2) / 2; i >= 0; i--)
{
AdJustDown(a, n, i);
} //先将数组调整成大(小)堆
while (end > 0)
{
Swap(&a[0], &a[end]); //(大堆)其首元素为最大的 ;(小堆)反之
AdJustDown(a, end, 0); //再将剩下的元素再调整成大(小)堆;
end--;
}
for (i = 0; i < n; i++)
{
printf("%d ", a[i]);
}
}
5.TopK问题
思想:海量数据选K个最大值,则建一个容量为K的小堆,遍历数组,将每个元素和堆顶元素比较,大的压入堆,小的跳过,最后堆剩下的就是最大的K个元素。若选K个最小值,则建一个容量为K的大堆
void HeapTopK(HPDataType* arr, int n, int k) //TopK问题
{
assert(arr);
Heap hp;
hp._a = (HPDataType*)malloc(sizeof(HPDataType)*k); //_a是指针,用来维护数组a
hp.capacity = k;
hp.size = 0;
int i;
for ( i = 0; i < k; i++)
{
hp._a[i] = arr[i];
hp.size++;
}
for (i = (k - 2) / 2; i >= 0; i--)
{
AdJustDown(hp._a, k, i);
}
//小堆
for (i = k; i < n; i++)
{
if (arr[i]>HeapTop(&hp))
{
PopHeap(&hp); //从堆顶pop
PushHeap(&hp, arr[i]);
}
}
HeapSort(hp._a, k);
printf("\n");
PrintHeap(&hp, k);
}