堆排,复杂度O(n*lgn)
用数组的话,数组第一个元素,即零开始的不能排序。
主要思想:用一棵二叉树维护最大堆的性质:根节点比左右儿子都大,左右儿子大小不区分。递归生成此树。
#include<stdio.h>
void HEAPIFY(int *num,int i,int heap_size)//维护最大堆的函数
{
//我们看一个小单元,一个根和左右子树。找出最大的节点
int r,l;
l=i<<1;
r=i<<1|1;
int largest=i;
if(l<=heap_size&&num[l]>num[i])//必须有====啊 ,至于为啥有他,看看是不是树的节点,万一那个节点为空呢?
{
largest=l;
}
if(r<=heap_size&&num[r]>num[largest])
{
largest=r;
}
if(largest!=i)//此处发现,最大的节点不是根节点,那我们把最大节点放到根上,(就是互换此节点和根节点。因为节点有变化,所以可能后续节点也不满足最大堆的性质,所以我们继续维护最大堆的性质)
{
int t=num[largest];
num[largest]=num[i];
num[i]=t;
HEAPIFY(num,largest,heap_size);
}
}
void MAKE_MAX_HEAP(int *num,int heap_size)//建立最大堆的函数
{
for(int i=heap_size>>1; i>=1; i--)//这里我们从有叶节点的根开始,从下往上维护最大堆的性质
//如果我们从上往下,不能确保根节点是小单元中最大的节点。
{
HEAPIFY(num,i,heap_size);
}
}
void HEAP_SORT(int *num,int n)//堆排
{
int heap_size=n;
MAKE_MAX_HEAP(num,heap_size);
for(int i=n; i>=2; i--)
{
int t=num[1];//树根节点总是最大的,我们把它和树的最后一个节点交换。
num[1]=num[i];
num[i]=t;
heap_size--;
HEAPIFY(num,1,heap_size);//因为交换,所以我们要从树根节点重新维护最大堆的性质
}
}
int main(void)
{
int num[50]= {0,96,1,2,3,66,805,45,63,67,59,57,50,52,23,24,24}; //16个,注意,堆排中num[0]不能排序
int n=16;
printf("排序前\n");
for(int j=1; j<=16; j++)
{
printf("%d ",num[j]);
}
putchar('\n');
HEAP_SORT(num,n);
printf("排序后\n");
for(int j=1; j<=16; j++)
{
printf("%d ",num[j]);
}
putchar('\n');
return 0;
}
如果是降序,我们只需把最大堆换成最小堆,只需处理void HEAPIFY(int *num,int i,int heap_size)此函数即可。