各种算法的性能分析Word文档下载推荐.docx
《各种算法的性能分析Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《各种算法的性能分析Word文档下载推荐.docx(14页珍藏版)》请在冰豆网上搜索。
通过对待排序序列从后向前(从下标较大的元素开始),依次比较相邻元素的排序码,若发现逆序则交换,使排序码较小的元素逐渐从后部移向前部(从下标较大的单元移向下标较小的单元),就象水底下的气泡一样逐渐向上冒。
冒泡排序算法如下:
voidbubblesort(inta[],intn)//冒泡排序C语言描述,待排序的元素放在数组a中
{
inti,j;
inttemp;
for(i=0;
i<
n-1;
i++)
{
for(j=n-1;
j>
i;
j--)
if(a[j-1]>
a[j])
{
temp=a[j-1];
a[j-1]=a[j];
a[j]=temp;
}
}
}
2.快速排序
任取待排序序列中的某个元素作为基准(一般取第一个元素),通过一趟排序,将待排元素分为左右两个子序列,左子序列元素的排序码均小于或等于基准元素的排序码,右子序列的排序码则大于基准元素的排序码,然后分别对两个子序列继续进行排序,直至整个序列有序。
voidquicksort(inta[],intstart,intend)//快速排序
inti,j,mid;
i=start;
j=end;
mid=a[i];
while(start>
=end)return;
while(i<
j)
j&
&
a[j]>
mid)j--;
if(i<
j){a[i]=a[j];
i++;
a[i]<
mid)i++;
if(i<
j){a[j]=a[i];
j--;
a[i]=mid;
quicksort(a,start,i-1);
//递归调用快速排序继续对前半部分的元素进行排序
quicksort(a,i+1,end);
//递归调用快速排序继续对后半部分的元素进行排序
3.选择排序
假设待排序的列表的n个数据元素放在数组a中,第一次从n个数据元素中找出最小的元素与a[0]交换,第二次从剩下的n-1个元素中找出最小的元素与a[1]交换,……直到第n-1次在剩下的两个元素中找出最小的元素与a[n-1]交换,剩下的最后一个元素的位置就在a[n].
选择排序算法如下:
voidselectsort(inta[],intn)//选择排序
intmin,temp;
min=i;
for(j=i+1;
j<
n;
j++)
if(a[j]<
a[min])
min=j;
temp=a[min];
a[min]=a[i];
a[i]=temp;
第三章:
测试结果(TestingResults)
算法
随机数组元素个数(个)
算法排序时间(seconds)
冒泡排序
1000
0.00300
2000
0.009000
3000
0.021000
4000
0.039000
5000
0.069000
10000
0.269000
快速排序
0.008000
0.014000
0.028000
0.041000
0.022000
0.002000
选择排序
0.005000
0.042000
0.049000
0.035000
0.159000
三种算法排序时间散点图
注:
横轴为随机数个数,纵轴为排序时间(1/100)
第4章:
分析和讨论
如果有n个数,则要进行n-1趟比较。
在第1趟比较中要进行n-1次相邻元素的两两比较,在第j趟比较中要进行n-j次两两比较。
比较的顺序从前往后,经过一趟比较后,将最值沉底(换到最后一个元素位置),最大值沉底为升序,最小值沉底为降序。
(1)算法的最好时间复杂度
若文件的初始状态是正序的,一趟扫描即可完成排序。
所需的关键字比较次数J和记录移动次数I均达到最小值:
Jmin=n-1
Imin=0。
冒泡排序最好的时间复杂度为O(n)。
(2)算法的最坏时间复杂度
若初始文件是反序的,需要进行n-1趟排序。
每趟排序要进行n-i次关键字的比较(1≤i≤n-1),且每次比较都必须移动记录三次来达到交换记录位置。
在这种情况下,比较和移动次数均达到最大值:
Jmax=n(n-1)/2=O(n2)
Imax=3n(n-1)/2=O(n2)
冒泡排序的最坏时间复杂度为O(n2)。
(3)算法的平均时间复杂度为O(n2)
虽然冒泡排序不一定要进行n-1趟,但由于它的记录移动次数较多,故平均时间性能比直接插入排序要差得多。
(4)算法稳定性
冒泡排序是就地排序,且它是稳定的。
(1)算法的最坏时间复杂度
无论适用哪一种方法来选择基准pivot,由于我们不知道各个元素间的相对大小关系(若知道就已经排好序了),所以我们无法确定pivot的选择对划分造成的影响。
因此对各种pivot选择法而言,最坏情况和最好情况都是相同的。
我们从直觉上可以判断出最坏情况发生在每次划分过程产生的两个区间分别包含n-1个元素和1个元素的时候(设输入的表有n个元素)。
下面我们暂时认为该猜测正确,在后文我们再详细证明该猜测。
对于有n个元素的表p[i],由于函数Partition的计算时间为θ(n),所以快速排序在序坏情况下的复杂性有递归式如下:
T
(1)=θ
(1),T(n)=T(n-1)+T
(1)+θ(n)
(1)
用迭代法可以解出上式的解为T(n)=θ(n2)。
这个最坏情况运行时间与插入排序是一样的。
下面我们来证明这种每次划分过程产生的两个区间分别包含n-1个元素和1个元素的情况就是最坏情况。
设T(n)是过程quicksort作用于规模为n的输入上的最坏情况的时间,则
T(n)=max(T(i)+T(n-i))+θ(n),其中1≤i≤n-1
(2)
我们假设对于任何k<
n,总有T(k)≤ck,其中c为常数;
显然当k=1时是成立的。
将归纳假设代入
(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)。
每趟选出一个最值和无序序列的第一个数交换,n个数共选n-1趟。
第i趟假设i为最值下标,然后将最值和i+1至最后一个数比较,找出最值的下标,若最值下标不为初设值,则将最值元素和下标为i的元素交换。
选择排序不关心表的初始次序,它的最坏情况的排序时间与其最佳情况没多少区别,其比较次数为n(n-1)/2,时间复杂度为O(n2)。
所以有:
(1)算法的最好时间复杂度为O(n2)
(2)算法的最坏时间复杂度为O(n2)
对于序列初始状态基本有正序,可选择对有序性较敏感的如冒泡排序、选择排序等方法
对于序列长度比较大的随机序列,应选择平均时间复杂度较小的快速排序方法。
各种排序算法都有各自的优缺点,适应于不同的应用环境,因此在选择一种排序算法解决实际问题之前,应当先分析实际问题的类型,再结合各算法的特点,选择一种合适的算法。
附录:
源代码(基于C语言的)
#include"
stdio.h"
time.h"
stdlib.h"
#defineSIZE10000//待排序数组的规模
#definePRT_RT0//控制是否显示排序后的数组的常量
//PRT_RT=1,则显示输出,为0则不输出
voidbubblesort(intm[],intn)//冒泡排序算法,待排序元素存放在数组m中
for(j=n-1;
{
if(m[j-1]>
m[j])
{
temp=m[j-1];
m[j-1]=m[j];
m[j]=temp;
}
}
voidselectsort(intk[],intn)//选择排序算法,待排序元素存放在数组k中
if(k[j]<
k[min])
temp=k[min];
k[min]=k[i];
k[i]=temp;
voidquicksort(intp[],intstart,intend)//快速排序算法,待排序元素存放在数组p中
mid=p[i];
=end)
return;
while(i<
p[j]>
mid)
j--;
p[i]=p[j];
i++;
p[i]<
p[j]=p[i];
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));
//设置时间作为随机函数的种子
SIZE;
i++)//随机赋值
a[i]=rand()%SIZE;
/取[0,SIZE]间的随机整数
//如果PRT_RT==1,则输出待排序的序列,否则输出:
“不输出待排序序列”
if(PRT_RT==1)
printf("
%d"
a[i]);
//输出这个数组
else
不输出待排序序列"
);
printf("
\n"
printf("
各种算法排序时间及排序后序列如下:
"
//以下统计冒泡排序时间
start=clock();
bubblesort(a,SIZE);
//在这里插入你要计算时间的算法,这里计算的是冒泡排序算法当规模为SIZE的时候的算法的时间
end=clock();
duration=(double)(end-start)/CLOCKS_PER_SEC;
thebubblesorttimeis:
%fseconds"
duration);
//输出冒泡排序时间
//以下显示冒泡排序结果,如果PRT_RT==1,则输出排序后的序列,否则输出:
“不输出冒泡排序后序列”
if(PRT_RT==1)
for(i=0;
i<
i++)
a[i]);
else
不输出冒泡排序后的序列"
system("
pause"
//以下统计快速排序时间
start=clock();
quicksort(a,0,SIZE-1);
//在这里插入你要计算时间的算法,这里计算的是快速排序算法当规模为SIZE的时候的算法的时间
duration=(double)(end-start)/CLOCKS_PER_SEC;
printf("
thequicksorttimeis:
//输出统计最后时间
if(PRT_RT==1)
不输出快速排序后的序列"
//以下统计选择排序时间
selectsort(a,SIZE);
//在这里插入你要计算时间的算法,这里计算的是选择排序算法当规模为SIZE的时候的算法的时间
theselectsorttimeis:
//输出选择排序时间
“不输出选择排序后序列”
%d"
不输出选择排序后的序列"
}
return0;
声明
我们在此声明,这个题为“各种排序算法的性能测试”的项目的所有工作是由作为一组的我们的成员的各自的努力而完成的。
人员安排:
程序员:
余武丹
测试员:
李红波
报告书写员:
刘红梅
完成日期:
2013年9月4日
THANKS!
!
致力为企业和个人提供合同协议,策划案计划书,学习课件等等
打造全网一站式需求
欢迎您的下载,资料仅供参考