堆是一种完全二叉树,不适合链式存储。由根结点的数据可以分为大顶堆(大根堆)和小顶堆(小根堆),大顶堆的根节点比左右子树大;相反,小顶堆的根节点比左右子树小。在实际应用中,堆可以实现优先队列的效果。
#define TYPE int
#define swap(a,b) {typeof(a) t=(a); (a)=(b); (b)=t;}
注意上面定义的宏表示两个数据的交换,格式只适用Linux系统,下面来设计一下堆结构:
typedef struct Heap
{
TYPE *arr;
int cap;
int cnt;
}Heap;
根据堆的特性我们有下面多个操作:
创建
//创建
Heap *create_heap(int cap)
{
Heap *heap=malloc(sizeof(Heap));
heap->arr=malloc(sizeof(TYPE)*cap+1);
heap->cap=cap;
heap->cnt=0;
return heap;
}
空堆
//空堆
bool empty_heap(Heap *heap)
{
return !heap->cnt;
}
满堆
//满堆
bool full_heap(Heap *heap)
{
return heap->cnt==heap->cap;
}
添加
//添加
bool add_heap(Heap *heap,TYPE data)
{
if(full_heap(heap)) return false;
heap->arr[++heap->cnt]=data;
//添加后调整为堆
int i=heap->cnt;
while(i>1)
{
if(heap->arr[i/2]<heap->arr[i])
{
swap(heap->arr[i/2],heap->arr[i]);
}
i/=2;
}
return true;
}
删除
//删除
bool del_heap(Heap *heap)
{
if(empty_heap(heap)) return false;
//堆顶与末尾交换
swap(heap->arr[1],heap->arr[heap->cnt]);
//删除末尾
heap->cnt--;
//从上往下进行调整为堆
int i=1;
while(i<heap->cnt)
{
//保证有右子树,比较左右根,谁大谁与根交换,然后继续调整交换后的一边
if(i*2+1<heap->cnt)
{
//假如左右相等,把其中一个交换到根即可
if(heap->arr[i*2+1]>=heap->arr[i*2] && heap->arr[i*2+1]>heap->arr[i])
{
swap(heap->arr[i*2+1],heap->arr[i]);
i=i*2+1;
}
else if(heap->arr[i*2]>heap->arr[i*2+1] && heap->arr[i*2]>heap->arr[i])
{
swap(heap->arr[i*2],heap->arr[i]);
i=i*2;
}
else break;
}
//保证有左子树,比较根与左,如果左大,交换左和根,调整左边
else if(i*2<heap->cnt)
{
if(heap->arr[i*2]>heap->arr[i])
{
swap(heap->arr[i*2],heap->arr[i]);
i=i*2;
}
else break;
}
//没有左右子树,说明调整结束
else break;
}
return true;
}
查看全部
//查看全部
void show_heap(Heap *heap)
{
for(int i=1;i<=heap->cnt;i++)
{
printf("%d ",heap->arr[i]);
}
printf("\n");
}
堆顶
//堆顶
TYPE top_heap(Heap *heap)
{
return heap->arr[1];
}
堆排序(循环迭代)
//堆排序 循环实现
void sort_heap(int *arr,int len)
{
//把数组调整为堆结构
for(int i=1;i<=len;i++)
{
int j=i;
while(j>1)
{
if(arr[j/2]<arr[j])
{
swap(arr[j / 2], arr[j]);
j=j/2;
}
else break;
}
}
//删除堆顶,直到堆为空
while(len>=1)
{
swap(arr[1],arr[len]);
len--;
int i=1;
//从上向下调整
while(i<=len)
{
if(i*2+1<=len)
{
if(arr[i*2+1]>=arr[i*2] && arr[i*2+1]>arr[i])
{
swap(arr[i*2+1],arr[i]);
i=i*2+1;
}
else if(arr[i*2]>arr[i*2+1] && arr[i*2]>arr[i])
{
swap(arr[i*2],arr[i]);
i=i*2;
}
}
else if(i*2<=len)
{
if(arr[i*2]>arr[i])
{
swap(arr[i*2],arr[i]);
i=i*2;
}
else break;
}
else break;
}
}
}
堆排序(递归)
//从top下标调整到end下标,向下调整成堆结构
void _sort_heap_recursion(int *arr,int top,int end)
{
if(top>=end) return;
int max=top;//假设top为最大值,max为左右根中最大值的编号
int l=max*2;//左子树编号
int r=max*2+1;//右子树编号
if(l<=end && arr[l]>arr[max])
{
//有左子树,且左比最大值大,更新最大值编号
max=l;
}
if(r<=end && arr[r]>arr[max])
{
//有右子树,且右比最大值大,更新最大值编号
max=r;
}
if(top!=max)
{
//最大值不是根,则交换根与最大值,继续对最大值位置向下调整
swap(arr[max],arr[top]);
_sort_heap_recursion(arr,max,end);
}
}
//堆排序 递归实现
void sort_heap_recursion(int *arr,int len)
{
for(int i=1;i<=len;i++)
{
//从头遍历每个值,从下向上调整
int j=i;
while(j>1)
{
if(arr[j/2]<arr[j])
{
swap(arr[j/2],arr[j]);
j=j/2;
}
else break;
}
}
for(int i=len;i>0;i--)
{
swap(arr[1],arr[i]);
//从上到下递归调整,从0调整到i-1
_sort_heap_recursion(arr,1,i-1);
}
}
综上所述,堆也是一种排序算法,在实际应用中很有参考价值。
over