堆排序报告Word文档格式.docx
《堆排序报告Word文档格式.docx》由会员分享,可在线阅读,更多相关《堆排序报告Word文档格式.docx(12页珍藏版)》请在冰豆网上搜索。
以该结点为根的子树再进行递归调用MAX-HEAPIFY.
伪代码:
程序设计:
voidMAX_HEAPIFY(intA[],inti,intlength)
{intl,r;
intlargest;
inttemp;
l=2*i;
r=2*i+1;
if((l<
=length)&
&
(A[l]>
A[i]))largest=l;
elselargest=i;
if((r<
(A[r]>
A[largest]))largest=r;
if(largest!
=i)
{temp=A[largest];
A[largest]=A[i];
A[i]=temp;
MAX_HEAPIFY(A,largest,length);
}
时间分析:
MAX-HEAPIFY作用在一棵以结点i为根的、大小为n的子树上时,其运行时间为调整元素A[i]、A[LEFT(i)],A[RIGHT(i)]的关系时所用时间为O
(1),再加上,对以i的某个子结点为根的子树调用MAX-HEAPIFY所需的时间,且i结点的子树大小至多为2n/3,所以,MAX-HEAPIFY的运行时间为T(n)≤T(2n/3)+Θ
(1)(最坏情况下在最底层恰好半满的时候).通过主方法解得递归T(n)=O(lgn);
(2)建立堆
BUILD_MAX_HEAP(intA[],intlength)采用“自底向上”用MAX-HEAPIFY算法,使得每个结点调用一次MAX-HEAPIFY,将无序的二叉树调整为大根堆,直到i=0;
最终的结点1就是最大堆的根。
voidBUILD_MAX_HEAP(intA[],intlength)
{intj;
inti;
j=(length/2);
for(i=j;
i>
=1;
i--)
MAX_HEAPIFY(A,i,length);
因为每次调用MAX-HEAPIFY的时间为O(lgn),而共有O(n)次调用,所以BUILD-MAX-HEAP的简单上界为O(nlgn),由于,MAX-HEAPIFY在树中不同高度的结点处运行的时间不同,且大部分结点的高度都比较小,而我们知道,n个元素的堆的高度为
(向下取整),且在任意高度h上,至多有
(向上取整)个结点。
因此,MAX-HEAPIFY作用在高度为h的结点上的时间为O(h),所以,BUILD-MAX-HEAP的上界为:
O(n)。
(3)堆排序
通过,顶端最大的元素与最后一个元素不断的交换,交换后又不断的调用MAX-HEAPIFY以重新维持最大堆的性质,最后,一个一个的,从大到小的,把堆中的所有元素都清理掉,也就形成了一个有序的序列。
voidHEAPSORT(intA[],intlength)//堆排序算法
{BUILD_MAX_HEAP(A,length);
intd;
doublet;
for(d=length;
d>
=2;
d--)
{temp=A[d];
A[d]=A[1];
A[1]=temp;
length--;
MAX_HEAPIFY(A,1,length);
}
MAX-HEAPIFY的运行时间为O(lgn),而要完成整个堆排序的过程,共要经过O(n)次这样的MAX-HEAPIFY操作。
所以,才有堆排序算法的运行时间为O(n*lgn)。
(4)不同条件下的排序时间(在100000个数据情况下):
每次建立大根堆时,以i为根的子树的叶子节点的路径上,有可能每个节点都要与其左右孩子进行比较、调换。
而调换之后又有可能还要与下一级的左右孩子进行比较、调换。
如此循环下去,时间耗费就逐渐增加。
(理论值为O(
))。
最好情况下:
为了使时间花费最小,猜想如果在某个中间过程中,结点i不会小于其左右孩子,那么以i为根的子树的循环结束,i以下各结点不用再调用MAX-HEAPIFY函数,节省了时间。
voidbest_case(intA[],intlength)
{inti=1;
for(;
i<
=length;
i++)
A[i]=1;
HEAPSORT(A,length);
printf("
最好情况下排序时间:
%f\n"
(double)((finish-start)/C);
}//C=CLOCK_PER_SEC;
一般情况下:
voidgeneral_case(intA[],intlength)
{inti=1;
random(A,length);
一般情况下排序时间:
(double)(finish-start)/C);
最坏情况排序:
需满足在算法运行过程中,每个结点都循环调用MAX-HEAPIFY函数,使得时间增加。
由此,构造有序数据组(从小到大),
voidworst_case(intA[],intlength)
A[i]=i;
最坏情况下排序时间:
输出每个元素所运行的时刻;
voidsingle_case(intA[],intlength)
{random(A,length);
output1(A,length);
BUILD_MAX_HEAP(A,length);
start=clock();
inttemp,d,n=0;
{n++;
finish=clock();
temp=A[d];
A[d]=A[1];
A[1]=temp;
length--;
MAX_HEAPIFY(A,1,length);
排序给出第%d个数据为:
%d\t"
n,A[1]);
时刻值:
%f\n\n"
(double)finish-start);
3算法分析
最差时间复杂度:
,最优时间复杂度:
,平均时间复杂度:
,由上可以看出,最坏情况和一般情况时间耗费相差不大。
最差空间复杂度:
,主要时间是建立初始堆和反复重建堆过程,所以堆排序不适宜记录数较少的文件,堆排序是就地排序,是不稳定排序。
4.完整算法代码
#include<
stdio.h>
stdlib.h>
time.h>
#defineCCLOCKS_PER_SEC
clock_tstart,finish;
voidMAX_HEAPIFY(intA[],inti,intlength)//保证最大堆性质,即使得以“i”为根的子树成为最大堆
{
temp=A[largest];
voidBUILD_MAX_HEAP(intA[],intlength)//将一个数组建成大根堆,实际上是采用“自底向上”的顺序将无序的二叉树调整为大根堆
i--)MAX_HEAPIFY(A,i,length);
{start=clock();
voidrandom(intA[],intlength)
A[i]=int(rand()%1000000);
intoutput1(intA[],intlength)
排序前的的数据:
\n"
);
%d%c"
A[i],(i%5==0)?
'
\n'
:
\t'
return0;
intoutput2(intA[],intlength)
\t排好序后的的数据:
\t%d%c"
%fseconds\n"
printf("
{random(A,length);
\t排序给出第%d个"
n);
数据为:
%d"
A[1]);
(double)(finish-start));
}
intmain()
{intA[100001];
intlength=100000;
intchoice;
do
{A[0]=0;
----------------堆排序演示:
--------------\n\n"
\t\t1:
最好情况:
\n\n"
\t\t2:
一般情况:
\t\t3:
最坏情况:
\t\t4:
一般情况下每个元素的时刻值:
\t\t0:
退出:
请输入你的选择:
\t"
scanf("
&
choice);
switch(choice)
{case1:
1:
best_case(A,length);
break;
case2:
2:
general_case(A,length);
case3:
3:
worst_case(A,length);
case4:
single_case(A,length);
case0:
exit(0);
}while(choice!
=0);