实现堆排序需要解决两个问题:①如何由一个无序序列建成一个堆。②如何在输出堆顶元素之后,调整剩余元素成为一个新的堆。
自堆顶至叶子的调整过程为“筛选”。假设输出堆顶元素之后,以队中最后一个元素替代之,此时根节点的左右子树均为堆,仅需要自上至下进行调整即可。首先以堆顶元素和其左右子树根结点的值比较之,假设右子树根节点的值小于左子树根节点的值且小于根节点的值,则将根节点与右子树根节点交换。此时,破坏了右子树的堆,则进行相同的调整。直至叶子节点。
从一个无序序列建堆的过程就是一个反复“筛选”的过程。若将此序列看成一个完全二叉树,则最后一个非终结点是第 (n/2)(下取整)个元素开始。
#include <stdio.h>
void heapAdjust(int *h, int s, int m) //h[s...m]中除了h[s]外其余均满足堆的定义。调整h[s],使h成为一个大顶堆。
{
int rc = h[s];
for (int j = 2*s; j<=m; j*=2)
{
if (j<m && h[j]<h[j+1])
{
++j; //j为较大记录的下标
}
if (rc >= h[j]) //rc应插入在位置s上
{
break;
}
h[s]=h[j];
s=j;
}
h[s]=rc;
}
void heapSort(int *h, int n)
{
for (int i=n/2; i>=0; i--)
{
heapAdjust(h,i,n-1); //初始建堆
}
for (i=n-1; i>0; i--)
{
int temp = h[0]; //将堆顶和当前未经排序子序列中的最后一个记录相互交换
h[0]=h[i];
h[i] = temp;
heapAdjust(h,0,i-1); //重新调整
}
}
int main(int argc, char* argv[])
{
int a[5]={3,5,2,7,4};
heapSort(a,5);
for (int i=0; i<5; i++)
{
printf("%d ",a[i]);
}
printf("\n");
return 0;
}