您的位置:首页 > 其它

非递归方法的堆排序实现

2014-09-03 16:50 148 查看

引言

首先需要明确,如何根据父亲结点的位置得知孩子结点的位置,以及如何根据孩子结点的位置得知父亲结点的位置。

假设数列索引从0开始,如果父亲结点的索引为i,那么左孩子索引为2i+1,右孩子索引为2i+2;如果孩子结点的索引为j,那么父亲结点的索引为(j-1)/2。

堆排序的核心在于函数voidadjustdown(int*arr,inti,intend),其中第i+1个元素到最后一个元素均已满足堆结构,每次adjustdown可以使当前位置i的元素也满足堆结构。如果是大堆,则经过adjustdown后当前位置的元素最大;如果是小堆,则经过adjustdown后当前位置的元素最小。

以下代码,将数列从小到大排序。采用大堆,并且使用了非递归的方法。函数adjustdown中的五个if语句实际上有一部分是可以合并的,但是为了逻辑清晰,在本代码中,完整保留下来了。注释我写的很用心,相信读者可以看懂。

代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>

staticvoidshow(int*arr,intlen)
{
intindex;
for(index=0;index<len;index++)
{
printf("%d",arr[index]);
}
printf("\n");
}

staticvoidswap(int*left,int*right)
{
inttmp=*left;
*left=*right;
*right=tmp;
}

voidadjustdown(int*arr,inti,intend)
{
intkey=arr[i];
intp=i;
intleft=2*p+1;
/*越界就是没孩子*//*只要能进循环,一定有左孩子*/
while(left<=end)
{
/*有右孩子的情况下,大于等于左右孩子不用换*/
if((key>=arr[left])&&(left+1<=end&&key>=arr[left+1]))
{
break;
}elseif(key>=arr[left]&&left+1>end)/*没有右孩子,只有左孩子,且大于等于左孩子不用换*/
{
break;
}elseif(left+1<=end&&arr[left+1]>=arr[left]&&key<arr[left+1])/*与右孩子换。要保证有右孩子,且右孩子大于等于左孩子,父亲小于右孩子*/
{
swap(arr+p,arr+left+1);
p=left+1;//父亲与谁换,就到谁的位置了
left=2*p+1;//父亲新的左孩子的位置
}elseif(left+1<=end&&arr[left]>arr[left+1]&&key<arr[left])/*与左孩子换。有右孩子的情况下,右孩子小于左孩子,父亲小于左孩子*/
{
swap(arr+p,arr+left);
p=left;
left=2*p+1;
}elseif(left+1>end&&arr[left]>key)/*与左孩子换。没右孩子的情况下,只需父亲小于左孩子*/
{
swap(arr+p,arr+left);
p=left;
left=2*p+1;
}
}
}

voidheap_sort(int*arr,intlen)
{
intp;//最后一个父亲
intend;//最后一个有效下标
/*建一个大顶堆,从最后一个父亲开始调*/
for(p=(len-1-1)/2;p>=0;p--)
{
adjustdown(arr,p,len-1);
}
/*根结点的值最大,与末尾交换,并继续建立堆结构,再交换...*/
for(end=len-1;end>=1;end--)
{
swap(arr,arr+end);//end已经是最大值
adjustdown(arr,0,end-1);//从arr+1到end-1位置都是满足堆结构的
}
}

intmain(intargc,char*argv[])
{
intindex;
intarr[10];
memset(arr,0,10);
srand(time(NULL));
for(index=0;index<10;index++)
{
arr[index]=rand()%20+1;
}
show(arr,10);

heap_sort(arr,10);
show(arr,10);

system("pause");
return0;
}

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: