堆排序是对选择排序的优化,利用选择排序中的相对关系,减少比较次数。堆排序主要分为两个部分,初始建堆过程和堆定点更替后堆的调整部分。
最好,最坏,平均时间复杂度都为O(nlogn),尽管如此,平均情况下,快排表现还是要好于堆排序。
本文以数组为堆的存储结构,数组从0下标开始。将数组非降序排序,其中使用大顶堆,每次最大元素换到最后,最后数组即为升序。
main部分
int main()
{
const int iNum = 10;
int iarry[] = {10,9,8,7,6,5,4,3,2,1};
Run(iarry,iNum);
for(int i=0; i<iNum; ++i)
{
printf("%d\t",iarry[i]);
}
printf("\n");
return 0;
}
sort主体,其中iNum为数组长度,即最后元素下一位置。非叶子节点从iNum/2-1到0,需要调整堆结构。
void Run(int iarry[],int iNum)
{
/*建堆过程,0下标即为最大值*/
for(int i=iNum/2-1; i>=0; --i)
{
HeapAdjust(iarry,i,iNum);
}
int itmp;
for(int i=iNum-1; i>0; --i)
{
/*最大值和i下标交换,次大值放到尾部,调整以新0下标元素为顶的堆*/
itmp = iarry[0];
iarry[0] = iarry[i];
iarry[i] = itmp;
HeapAdjust(iarry,0,i);
}
}
调整推,很自然想到递归方式:下标0开始,ilen是数组长度。
void HeapAdjust(int iarry[],int ipos, int ilen)
{
int j=(ipos+1)*2-1;
if(j >= ilen)
return;//递归终止
if(j<ilen-1 && iarry[j]<iarry[j+1])
{
j++;
}
if(iarry[ipos] >= iarry[j])
return;//递归终止
//swap
int itmp = iarry[j];
iarry[j] = iarry[ipos];
iarry[ipos] = itmp;
HeapAdjust(iarry, j, ilen);
}
非递归方式:
void HeapAdjust(int iarry[],int ipos, int ilen)
{
int rc = iarry[ipos];
for(int j=2*(ipos+1)-1; j<ilen; j*=2)
{
if(j<ilen-1 && iarry[j]<iarry[j+1])
++j;
if( rc>=iarry[j])
break;
iarry[ipos] = iarry[j];
ipos = j;
}
iarry[ipos] = rc;
}
非递归方式除了本身就比利用栈的递归快外,非递归相对递归方式还减少了赋值次数,递归方式最后需要交换对象。