将归纳假设代入
(2),得到:
T(n)≤max(ci2+c(n-i)2)+θ(n)=c*max(i2+(n-i)2)+θ(n)
因为在[1,n-1]上i2+(n-i)2关于i递减,所以当i=1时i2+(n-i)2有最大值n2-2(n-1)。
于是有:
T(n)≤cn2-2c(n-1)+θ(n)≤cn2
只要c足够大,上面的第二个小于等于号就可以成立。
于是对于所有的n都有T(n)≤cn。
这样,排序算法的最坏情况运行时间为θ(n2),且最坏情况发生在每次划分过程产生的两个区间分别包含n-1个元素和1个元素的时候,时间复杂度为O(n2)。
(2)算法的最好时间复杂度
如果每次划分过程产生的区间大小都为n/2,则快速排序法运行就快得多了。
这时有:
T(n)=2T(n/2)+θ(n),T
(1)=θ
(1)(3)
解得:
T(n)=θ(nlogn)
由于快速排序法也是基于比较的排序法,其运行时间为Ω(nlogn),所以如果每次划分过程产生的区间大小都为n/2,则运行时间θ(nlogn)就是最好情况运行时间。
(3)算法的平均时间复杂度
要想对快速排序的平均情况有个较为清楚的概念,我们就要对遇到的各种输入作个假设。
通常都假设输入数据的所有排列都是等可能的。
当我们对一个随机的输入数组应用快速排序时,要想在每一层上都有同样的划分是不太可能的。
我们所能期望的是某些划分较对称,另一些则很不对称。
平均情况下,Partition产生的划分中既有“好的”,又有“差的”。
这时,与Partition执行过程对应的递归树中,好、差划分是随机地分布在树的各层上的。
为与我们的直觉相一致,假设好、差划分交替出现在树的各层上,且好的划分是最佳情况划分,而差的划分是最坏情况下的划分。
在表p[i]处,划分的代价为n,划分出来的两个子表的大小为n-1和1,即最坏情况。
在表的下一层p[n-1]处,大小为n-1的子表按最佳情况划分成大小各为(n-1)/2的两个子表。
在一个差的划分后接一个好的划分后,产生出三个子表,大小各为1,(n-1)/2和(n-1)/2,代价共为2n-1=θ(n)。
从直觉上看,差的划分的代价θ(n)可被吸收到好的划分的代价θ(n)中去,结果是一个好的划分。
这样,当好、差划分交替分布划分都是好的一样:
仍是θ(nlogn),但θ记号中隐含的常数因子要略大一些,快速算法的平均时间复杂度为O(nlogn)。
3.选择排序:
每趟选出一个最值和无序序列的第一个数交换,n个数共选n-1趟。
第i趟假设i为最值下标,然后将最值和i+1至最后一个数比较,找出最值的下标,若最值下标不为初设值,则将最值元素和下标为i的元素交换。
选择排序不关心表的初始次序,它的最坏情况的排序时间与其最佳情况没多少区别,其比较次数为n(n-1)/2,时间复杂度为O(n2)。
所以有:
(1)算法的最好时间复杂度为O(n2)
(2)算法的最坏时间复杂度为O(n2)
(3)算法的平均时间复杂度为O(n2)
对于序列初始状态基本有正序,可选择对有序性较敏感的如冒泡排序、选择排序等方法
对于序列长度比较大的随机序列,应选择平均时间复杂度较小的快速排序方法。
各种排序算法都有各自的优缺点,适应于不同的应用环境,因此在选择一种排序算法解决实际问题之前,应当先分析实际问题的类型,再结合各算法的特点,选择一种合适的算法。
附录:
源代码(基于C语言的)
#include"stdio.h"
#include"time.h"
#include"stdlib.h"
#defineSIZE10000//待排序数组的规模
#definePRT_RT0//控制是否显示排序后的数组的常量
//PRT_RT=1,则显示输出,为0则不输出
voidbubblesort(intm[],intn)//冒泡排序算法,待排序元素存放在数组m中
{
inti,j;
inttemp;
for(i=0;i{
for(j=n-1;j>i;j--)
{
if(m[j-1]>m[j])
{
temp=m[j-1];
m[j-1]=m[j];
m[j]=temp;
}
}
}
}
voidselectsort(intk[],intn)//选择排序算法,待排序元素存放在数组k中
{
inti,j;
intmin,temp;
for(i=0;i{
min=i;
for(j=i+1;j{
if(k[j]min=j;
}
temp=k[min];
k[min]=k[i];
k[i]=temp;
}
}
voidquicksort(intp[],intstart,intend)//快速排序算法,待排序元素存放在数组p中
{
inti,j,mid;
i=start;
j=end;
mid=p[i];
while(start>=end)
return;
while(i{
while(imid)
j--;
if(i{
p[i]=p[j];
i++;
}
while(ii++;
if(i{
p[j]=p[i];
j--;
}
}
p[i]=mid;
quicksort(p,start,i-1);//递归调用快速排序对数组前半部分元素进行排quicksort(p,i+1,end);//递归调用快速排序继续对数组后半部分元素进行排序
}
intmain()//返回值类型为整型的主函数
{
inti;
longstart,end;//定义两个存放时间的变量
doubleduration;//定义一个存放计算时间的变量
int*a;//定义指针变量为随机数分配存储空间
a=(int*)malloc(sizeof(int)*SIZE);//分配SIZE字节的存储空间
srand((unsigned)time(NULL));//设置时间作为随机函数的种子
for(i=0;i{
a[i]=rand()%SIZE;/取[0,SIZE]间的随机整数
}
//如果PRT_RT==1,则输出待排序的序列,否则输出:
“不输出待排序序列”
if(PRT_RT==1)
{
printf("%d",a[i]);//输出这个数组
}
else
{
printf("不输出待排序序列");
printf("\n");
}
printf("各种算法排序时间及排序后序列如下:
");
printf("\n");
//以下统计冒泡排序时间
start=clock();
bubblesort(a,SIZE);//在这里插入你要计算时间的算法,这里计算的是冒泡排序算法当规模为SIZE的时候的算法的时间
end=clock();
duration=(double)(end-start)/CLOCKS_PER_SEC;
printf("thebubblesorttimeis:
%fseconds",duration);//输出冒泡排序时间
printf("\n");
//以下显示冒泡排序结果,如果PRT_RT==1,则输出排序后的序列,否则输出:
“不输出冒泡排序后序列”
if(PRT_RT==1)
{
for(i=0;i{
printf("%d",a[i]);
}
}
else
{
printf("不输出冒泡排序后的序列");
printf("\n");
}
printf("\n");
system("pause");
//以下统计快速排序时间
start=clock();
quicksort(a,0,SIZE-1);//在这里插入你要计算时间的算法,这里计算的是快速排序算法当规模为SIZE的时候的算法的时间
end=clock();
duration=(double)(end-start)/CLOCKS_PER_SEC;
printf("thequicksorttimeis:
%fseconds",duration);//输出统计最后时间
printf("\n");
//以下显示冒泡排序结果,如果PRT_RT==1,则输出排序后的序列,否则输出:
“不输出冒泡排序后序列”
if(PRT_RT==1)
{
for(i=0;i{
printf("%d",a[i]);
}
}
else
{
printf("不输出快速排序后的序列");
printf("\n");
}
system("pause");
//以下统计选择排序时间
start=clock();
selectsort(a,SIZE);//在这里插入你要计算时间的算法,这里计算的是选择排序算法当规模为SIZE的时候的算法的时间
end=clock();
duration=(double)(end-start)/CLOCKS_PER_SEC;
printf("theselectsorttimeis:
%fseconds",duration);//输出选择排序时间
//以下显示冒泡排序结果,如果PRT_RT==1,则输出排序后的序列,否则输出:
“不输出选择排序后序列”
if(PRT_RT==1)
{
for(i=0;i{
printf("%d",a[i]);
}
}
else
{
printf("不输出选择排序后的序列");
printf("\n");
}
printf("\n");
system("pause");
return0;
}
声明
我们在此声明,这个题为“各种排序算法的性能测试”的项目的所有工作是由作为一组的我们的成员的各自的努力而完成的。
人员安排:
程序员:
余武丹
测试员:
李红波
报告书写员:
刘红梅
完成日期:
2013年9月4日
THANKS!
!
!
致力为企业和个人提供合同协议,策划案计划书,学习课件等等
打造全网一站式需求
欢迎您的下载,资料仅供参考