堆排序属于选择排序,单列出来是因为比较重要和比较困难。。
先说一下,筛选过程是将一段序列通过元素交换使得该段序列的元素构成一个大顶堆。然后,堆的初始化过程,就是从最后一个非叶子结点开始筛选直到根结点,这样多次筛选之后就是一个大顶堆了。 初始化之后,那么根结点的元素一定是最大的元素,然后跟最后一个位置的元素交换。然后,再重建大顶堆(范围逐渐缩小,有序的元素不再参与),交换,直到只有堆顶元素无序。这就是堆排序。
如下图所示,当90和20交换之后,再次调整大顶堆的时候,范围是前8个元素了。所以,范围逐渐缩小,80又成为堆顶元素。
void HeapAdjust(SqList &H, int s, int m)
{
//H.r[s..m]中,除了H.r[s]外均满足大顶堆的条件。调整H.r[s]的位置,使得H.r[s..m]为大顶堆。
int rc = H.r[s];
for(int j=2*s; j<=m; j*=2)
{
if(j<m && H.r[j]<H.r[j+1]) j++; //寻找较大的孩子
if(rc>=H.r[j]) break; //发现孩子的值更小,则应该插入(比孩子的值大,双亲的值小)
H.r[s] = H.r[j]; //比孩子的值小,则孩子替换双亲的位置
s = j;
}
H.r[s] = rc;
}
void HeapSort(SqList &H)
{
//初始化建堆
//令所有元素都满足大顶堆的要求,这样堆顶元素才必定是最大元素,并且再次建堆时筛选出来的元素才是次大的元素
for(int i=H.Length/2; i>0; i--)
HeapAdjust(H,i,H.Length);
for(int i=H.Length; i>1; i--)
{
//堆顶元素交换
int tmp = H.r[1];
H.r[1] = H.r[i];
H.r[i] = tmp;
//重新调整为大顶堆
HeapAdjust(H,1,i-1);
}
}
起初,我也没怎么理解。然后,就画图画图。 如果不初始化,选出来的堆顶元素不一定是最大的。只有所有元素都满足大顶堆的条件时,重建时堆顶元素才是次大的。。。多画画图,就比较容易明白。
上个例子
这是将序列初始化为大顶堆的过程。然后,进行元素交换和调整的过程。
那么,经过堆排序后,所得到的序列为:
堆排序也不是很难理解,就是通过筛选过程建成大顶堆,交换元素,之后就是过程的不断重复了。。。