五种排序算法分析课件Word格式.docx
《五种排序算法分析课件Word格式.docx》由会员分享,可在线阅读,更多相关《五种排序算法分析课件Word格式.docx(21页珍藏版)》请在冰豆网上搜索。
代码1:
srand((unsigned)time(NULL));
Fori=0to19
randNum(MAX,array);
当问题规模较小时,生成随机函数randNum()在for循环下运行时间短,每次产生的随机数组都是一样的,将srand((unsigned)time(NULL))语句放在for循环外面,就产生了20组不同的随机数组。
图1、产生20组随机数组
2、选择排序
代码2:
fori=0ton-2
min=i
forj=i+1ton-1
ifele[min]>
ele[j]min=j
swap(ele[i],ele[min])//交换元素
图2、选择排序在不同数据规模下排序所消耗的时间
3、冒泡排序
代码3:
fori=0ton-1
forj=0ton-1-i
ifa[j]>
a[j+1]
swap(a[j],a[j+1])//交换
图3、冒泡排序在不同数据规模下排序所消耗的时间
3、合并排序
代码4:
MERGE(A,p,q,r)
n1←q-p+1
n2←r-q
createarraysL[1‥n1+1]andR[1‥n2+1]
fori←1ton1
doL[i]←A[p+i-1]
forj←1ton2
doR[j]←A[q+j]
L[n1+1]←∞
R[n2+1]←∞
i←1
j←1
fork←ptor
doifL[i]≤R[j]
thenA[k]←L[i]
i←i+1
elseA[k]←R[j]
j←j+1
图4、合并排序在不同数据规模下排序所消耗的时间
4、快速排序
代码5:
quick(ele[0...n-1],left,right)
ifl<
r
l←leftr←rightx←ele[l];
whilel<
r
whilel<
r&
&
x<
=ele[r]//比x小则之后交换到前面的部分
r--
ifl<
ele[l]←ele[r]l++
x>
ele[l]//比x大则前面交换到后面部分
ll++
ifl<
ele[r]←ele[l]r--
ele[l]←x;
quick(ele,left,l-1)//递归调用
quick(ele,l+1,right)
图5、快速排序在不同数据规模下排序所消耗的时间
5、插入排序
代码6:
fori=1→n-1
ifele[i]<
ele[i-1]temp=ele[i]
forj=i-1to0&
ele[j]>
temp
ele[j+1]←ele[j]
ele[j+1]←temp
图6、插入排序在不同数据规模下排序所消耗的时间
三.实验分析
选择排序:
图7、由图2数据整合而成的折线图
表1、选择排序在不同数据规模下排序所消耗的时间
数据规模:
10
100
1000
10000
100000
耗时(ms)
2.05
195.25
19868.5
图形上:
形状基本符合n2(二次增长)
数据上:
我们发现当数据规模增大10倍时:
1000→10000:
195.25/2.05=95.24≈100
10000→100000:
19868.5/195.25=101.75≈100
其他倍数也可得到类似的结果。
结论:
当数据规模为10和100时因为数据太小,耗时约为0。
但当数据规模为1000增大到10000时,并10000到100000时,规模增大10倍耗时都增大约100倍,可以计算出,选择排序的时间复杂度为o(n2)。
冒泡排序:
图8、由图3数据整合而成的折线图
表2、冒泡排序在不同数据规模下排序所消耗的时间
0.1
2
194.15
19708
100→1000:
2/0.1=20(误差太大)
1000→10000:
194.15/2=97.075≈100
10000→100000:
19708/194.15=101.5≈100
由于开始问题规模较小,产生误差较大,但随着问题规模的按10的倍数增大,耗时逐渐呈100的倍数增大,分析伪代码也可以算出该算法的时间复杂度为o(n2)。
随着问题规模的增大,多种误差会逐渐累积,耗时会超过o(n2)的倍数,但是整体上不会相差太大。
与此相比,电脑等其他因素造成轻微的误差可以忽略不计。
合并排序:
图9、由图4数据整合而成的折线图
表3、合并排序在不同数据规模下排序所消耗的时间
0.7
6.05
59.2
形状基本符合n(线性增长)
:
0.7/0.1=7≈10(误差较大)
6.05/0.7=8.64≈10
59.2/6.05=9.78≈10
根据该算法的伪代码,可以计算出时间复杂度为o(nlog2n),当数据规模扩大10倍时,耗时呈线性增长,逐渐接近于n。
当数据规模扩大n倍时,相应的在时间的消耗上会扩大nlog2n倍,同时我们发现,理论上乘以nlog2n后的数据普遍会略小于实际数据,这主要原因快速排序需要递归调用,递归调用需要花费额外的时间。
快速排序:
图10、由图5数据整合而成的折线图
表4、快速排序在不同数据规模下排序所消耗的时间
1.5
12.15
137.95
12.15/1.5=8.1≈10
137.95/12.15=10.1≈10
根据快速排序算法的伪代码,可以分析出该算法的时间复杂度是o(nlog2n),当数据规模扩大n倍时,相应的在时间的消耗上会扩大nlog2n倍。
从实验的数据上,可以看出随着问题规模的增大,耗时上面也呈线性增长,但累积起来的误差也使得程序的结果略微高于实验值。
总体上的实验结果和预期还是很接近的。
插入排序:
图11、由图6数据整合而成的折线图
表5、插入排序在不同数据规模下排序所消耗的时间
1.2
112.85
11329.5
112.85/1.2=94≈100
11329.5/112.85=100.4≈100
根据插入算法的伪代码,可以计算出该算法的时间复杂度是o(n2),当数据规模扩大n倍时,相应的在时间的消耗上会扩大n2倍,理论上,如果数据大具有特殊性,那此算法被影响的程度会比较大,他的的比较次数可以从线性次数,到n2次,赋值次数也可能由常数次变成n2总的来说,受数据影响较大。
将五种排序的实验汇总在一起,如下图12所示
图12、由图7、8、9、10、11整合而来
从图中以及之前的分析中我们可以得到以下结论
1、在平均时间复杂度上面,冒泡排序、插入排序和选择排序都最差为o(n2)。
其主要原因是:
随着问题规模的增大,冒泡排序在比较次数上达到了o(n2),但这种排序同时也受交换次数的影响,而且最多时间复杂度也是o(n2)。
如此,同样是o(n2),但冒泡排序的二次项系数会比另外两个大不少,所以最为耗时。
2、快速排序和合并排序都表现出比较好的复杂度。
但这两者中,合并排序表现更好。
其原因是:
在最坏情况下,即整个序列都已经有序且完全倒序的情况下,快速排序呈o(n2)的增长,而归并排序不管在什么情况下都呈o(nlog2n),随着问题规模的增大,快速排序逐渐体现出这种弊端。
四.实验心得
本次实验虽然花费很大的心思,但确实让我对这几种排序的认识更加深刻,同样的数据,排序的时间可以相差如此之大,这可能会改变我每次都使用冒泡排序的这一习惯,同时,对算法的优良性不同而导致的结果差异之大,感觉到好的算法是多么的重要,当然合理利用算法也是不可忽视的。
这次实验虽然花了很大精力,却收获累累。
指导教师批阅意见:
成绩评定:
指导教师签字:
年月日
备注:
注:
1、报告内的项目或内容设置,可根据实际情况加以调整和补充。
2、教师批改学生实验报告时间应在学生提交实验报告时间后10日内。
附录:
代码
#include<
stdio.h>
iostream>
windows.h>
#include<
Mmsystem.h>
usingnamespacestd;
ctime>
fstream>
#defineARRAY_MAX100000
/*****************************生成随机函数*************************/
voidrandNum(intMAX,int*array){
//srand((unsigned)time(NULL));
//cout<
<
"
生成的随机数为:
endl;
;
for(inti=0;
MAX;
i++){
array[i]=rand()%100;
//cout<
array[i]<
"
}
\t\t耗时:
}
/*****************************选择排序*************************/
voidselect_sort(intMAX,int*array){
inti,j,k;
for(i=0;
i<
MAX;
i++){
k=i;
for(j=i+1;
j<
j++){
if(array[j]<
array[k]){
k=j;
}
}
if(k!
=i){
inttemp=array[k];
array[k]=array[i];
array[i]=temp;
/***************************冒泡排序*************************/
voidbuddle_sort(intMAX,int*array){
inti,j;
for(i=0;
for(j=i+1;
j++){
if(array[i]>
array[j])swap(array[i],array[j]);
/***************************合并排序*************************/
voidMerge(int*array,intp,intq,intr){
intn1=q-p+1;
intn2=r-q;
int*L,*R,i,j,k;
L=newint[n1+1];
R=newint[n2+1];
n1;
i++)
L[i]=array[p+i];
n2;
R[i]=array[q+1+i];
L[n1]=INT_MAX;
R[n2]=INT_MAX;
for(i=0,j=0,k=p;
k<
=r;
k++){
if(L[i]<
=R[j]){
array[k]=L[i++];
else{
array[k]=R[j++];
delete[]L;
delete[]R;
voidmerge_sort(int*array,intp,intr){
if(p<
r){
intq=(p+r)/2;
merge_sort(array,p,q);
//递归调用
merge_sort(array,q+1,r);
Merge(array,p,q,r);
else{
return;
/***************************快速排序*************************/
voidquick_sort(inta[],intlow,inthigh){
if(low>
=high){
return;
intfirst=low;
intlast=high;
intkey=a[first];
while(first<
last){
last&
a[last]>
=key){
--last;
a[first]=a[last];
//将比第一个小的数移到后面
a[first]<
++first;
}
a[last]=a[first];
//将比第一个大的数移到前面
a[first]=key;
//记录当前位置
quick_sort(a,low,first-1);
quick_sort(a,first+1,high);
/***************************插入排序*************************/
voidinsert_sort(intMAX,int*array){
inti,j,temp;
for(i=1;
temp=array[i];
for(j=i;
j>
0&
array[j-1]>
temp;
j--){
array[j]=array[j-1];
array[j]=temp;
intmain(){
intn,loop=1;
while(loop!
=0){
//产生随机数组
clock_ttime_start,time_end;
doubletime_used=0,count=0;
intMAX=10;
intarray[ARRAY_MAX];
cout<
\n\t\t请输入序号选择相应的操作:
1.选择排序2.冒泡排序3.合并排序4.快速排序5.插入排序0.退出程序"
******************************************************************"
cin>
>
n;
switch(n){
case0:
loop=0;
break;
case1:
for(intj=0;
j++){//控制问题规模MAX从10-100000
cout<
数组规模MAX="
MAX<
时,耗时:
srand((unsigned)time(NULL));
for(inti=0;
i++){//控制20组随机数产生
randNum(MAX,array);
time_start=clock();
select_sort(MAX,array);
time_end=clock();
time_used=time_end-time_start;
cout<
time_used<
//cout<
count+=time_used;
}
\n选择排序平均耗时:
count/20<
毫秒"
endl<
count=0;
MAX*=10;
}
break;
case2:
buddle_sort(MAX,array);
\n冒泡排序平均耗时:
case3:
for(intj=0;
merge_sort(array,0,MAX-1);
\n合并排序平均耗时:
break;
case4:
for(intl=0;
l<
l++){//控制问题规模MAX从10-100000
quick_sort(array,0,MAX);
\n快速排序平均耗时:
case5: