五种排序算法分析课件

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

深圳大学实验报告
课程名称:算法分析与复杂性理论
实验项目名称:实验一排序算法性能分析
学院:计算机与软件学院
专业:软件工程
指导教师:杨烜
报告人:赖辉学号:班级:软工学术型实验时间:2015-10-15
实验报告提交时间:2015-11-24
教务部制
一.实验目的
1.掌握选择排序、冒泡排序、合并排序、快速排序、插入排序算法原理
2.掌握不同排序算法时间效率的经验分析方法,验证理论分析与经验分析的一致性。

二.实验步骤与结果
实验总体思路:
根据实验要求,需要用while循环控制用户选择相应算法(选择通过switch实现)或者选择输入0跳出while循环,退出程序。

Switch中选择相应的算法后需要通过一个for(int j=0;j<5;j++)循环更改数组大小MAX的值(MAX *= 10),从而控制输入不同问题规模的耗时。

再通过一个for(int i=0;i<20;i++)循环控制20组随机数组。

为了使得程序输出更加直观,部分数据后面没有输出。

相应结果和过程如下所示(代码和结果如下图所示)。

各排序算法的实现及实验结果:
1、随机数产生
代码1:
srand((unsigned)time(NULL));
For i=0 to 19
randNum(MAX,array);
当问题规模较小时,生成随机函数randNum()在for循环下运行时间短,每次产生的随机数组都是一样的,将srand((unsigned)time(NULL))语句放在for循环外面,就产生了20组不同的随机数组。

图1、产生20组随机数组
2、选择排序
代码2:
for i=0 to n-2
min=i
for j= i+1 to n-1
if ele[min]>ele[j] min=j
swap(ele[i],ele[min]) //交换元素
图2、选择排序在不同数据规模下排序所消耗的时间3、冒泡排序
代码3:
for i= 0 to n-1
for j=0 to n-1-i
if a[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
create arrays L[1 ‥n1 + 1] and R[1 ‥n2 + 1]
for i ←1 to n1
do L[i] ←A[p + i - 1]
for j ←1 to n2
do R[j] ←A[q + j]
L[n1 + 1] ←∞
R[n2 + 1] ←∞
i ←1
j ←1
for k ←p to r
do if L[i] ≤R[j]
then A[k] ←L[i]
i ←i + 1
else A[k] ←R[j]
j ←j + 1
图4、合并排序在不同数据规模下排序所消耗的时间4、快速排序
代码5:
quick(ele[0...n-1],left,right)
if l<r
l←left r←right x←ele[l];
while l<r
while l<r && x<=ele[r] //比x小则之后交换到前面的部分
r--
if l<r
ele[l]←ele[r] l++
while l<r && x>ele[l] //比x大则前面交换到后面部分
ll++
if l<r
ele[r]←ele[l] r--
ele[l]←x;
quick(ele,left,l-1) // 递归调用
quick(ele,l+1,right)
图5、快速排序在不同数据规模下排序所消耗的时间5、插入排序
代码6:
for i=1→n-1
if ele[i]<ele[i-1] temp=ele[i]
for j= i-1 to 0 && ele[j]>temp
ele[j+1]←ele[j]
ele[j+1]←temp
图6、插入排序在不同数据规模下排序所消耗的时间
三.实验分析
选择排序:
图7、由图2数据整合而成的折线图
表1、选择排序在不同数据规模下排序所消耗的时间
数据规模:10 100 1000 10000 100000
耗时(ms)0 0 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、冒泡排序在不同数据规模下排序所消耗的时间
数据规模:10 100 1000 10000 100000
耗时(ms)0 0.1 2 194.15 19708
图形上:
形状基本符合n2(二次增长)
数据上:
我们发现当数据规模增大10倍时:
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、合并排序在不同数据规模下排序所消耗的时间
数据规模:10 100 1000 10000 100000
耗时(ms)0 0.1 0.7 6.05 59.2
图形上:
形状基本符合n(线性增长)
数据上:
我们发现当数据规模增大10倍时:
100→1000::0.7/0.1=7 ≈10(误差较大)
1000→10000: 6.05/0.7=8.64 ≈10
10000→100000:59.2/6.05=9.78 ≈10
其他倍数也可得到类似的结果。

结论:
根据该算法的伪代码,可以计算出时间复杂度为o(nlog2n),当数据规模扩大10倍时,耗时呈线性增长,逐渐接近于n。

当数据规模扩大n倍时,相应的在时间的消耗上会扩大nlog2n倍,同时我们发现,理论上乘以nlog2n后的数据普遍会略小于实际数据,这主要原因快速排序需要递归调用,递归调用需要花费额外的时间。

快速排序:
图10、由图5数据整合而成的折线图
表4、快速排序在不同数据规模下排序所消耗的时间
数据规模:10 100 1000 10000 100000
耗时(ms)0 0 1.5 12.15 137.95
图形上:
形状基本符合n(线性增长)
数据上:
我们发现当数据规模增大10倍时:
1000→10000::12.15/1.5=8.1 ≈ 10
10000→100000: 137.95/12.15=10.1 ≈10
其他倍数也可得到类似的结果。

结论:
根据快速排序算法的伪代码,可以分析出该算法的时间复杂度是o(nlog2n),当数据规模扩大n倍时,相应的在时间的消耗上会扩大nlog2n倍。

从实验的数据上,可以看出随着问题规模的增大,耗时上面也呈线性增长,但累积起来的误差也使得程序的结果略微高于实验值。

总体上的实验结果和预期还是很接近的。

插入排序:
图11、由图6数据整合而成的折线图
表5、插入排序在不同数据规模下排序所消耗的时间
数据规模:10 100 1000 10000 100000 耗时(ms)0 0 1.2 112.85 11329.5
图形上:
形状基本符合n2(二次增长)
数据上:
我们发现当数据规模增大10倍时:
1000→10000: 112.85/1.2=94 ≈100
10000→100000: 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>
#include<iostream>
#include<windows.h>
#include <Mmsystem.h>
using namespace std;
#include <ctime>
#include <fstream>
using namespace std;
#define ARRAY_MAX 100000
/*****************************生成随机函数*************************/ void randNum(int MAX,int *array){
//srand((unsigned)time(NULL));
//cout<<"生成的随机数为:"<<endl;;
for(int i=0;i<MAX;i++){
array[i] = rand()%100;
//cout<<array[i]<<" ";
}
//cout<<"\t\t耗时:";
}
/*****************************选择排序*************************/ void select_sort(int MAX,int *array){
int i, j, k;
for (i = 0; i < MAX; i++){
k = i;
for (j = i + 1; j < MAX; j++){
if (array[j] < array[k]){
k = j;
}
}
if (k != i){
int temp = array[k];
array[k] = array[i];
array[i] = temp;
}
}
}
/***************************冒泡排序*************************/
void buddle_sort(int MAX,int *array){
int i, j;
for(i=0;i<MAX;i++){
for(j=i+1;j<MAX;j++){
if(array[i]>array[j]) swap(array[i],array[j]);
}
}
}
/***************************合并排序*************************/ void Merge(int *array, int p, int q, int r){
int n1 = q - p + 1;
int n2 = r - q;
int *L, *R, i, j, k;
L = new int[n1 + 1];
R = new int[n2 + 1];
for (i = 0; i < n1; i++)
L[i] = array[p + i];
for (i = 0; i < n2; i++)
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;
}
void merge_sort(int *array, int p, int r){
if (p < r){
int q = (p + r) / 2;
merge_sort(array, p, q); //递归调用
merge_sort(array, q + 1, r);
Merge(array, p, q, r);
}
else{
return;
}
}
/***************************快速排序*************************/ void quick_sort(int a[], int low, int high){
if(low >= high){
return;
}
int first = low;
int last = high;
int key = a[first];
while(first < last){
while(first < last && a[last] >= key){
--last;
}
a[first] = a[last]; //将比第一个小的数移到后面
while(first < last && a[first] <= key){
++first;
}
a[last] = a[first]; //将比第一个大的数移到前面
}
a[first] = key; //记录当前位置
quick_sort(a, low, first-1);
quick_sort(a, first+1, high);
}
/***************************插入排序*************************/ void insert_sort(int MAX,int *array){
int i, j, temp;
for (i = 1; i < MAX; i++){
temp = array[i];
for(j=i;j > 0 && array[j-1] > temp;j--){
array[j] = array[j-1];
}
array[j] = temp;
}
}
int main(){
int n,loop = 1;
while(loop != 0){
//产生随机数组
clock_t time_start,time_end;
double time_used = 0,count = 0;
int MAX = 10;
int array[ARRAY_MAX];
cout<<"\n\t\t请输入序号选择相应的操作:"<<endl;
cout<<"1.选择排序 2.冒泡排序 3.合并排序 4.快速排序 5.插入排序0.退出程序"<<endl;
cout<<"******************************************************************"< <endl;
cin>>n;
switch(n){
case 0: loop = 0;break;
case 1:
for(int j=0;j<5;j++){ //控制问题规模MAX从10-100000
cout<<"数组规模MAX="<<MAX<<" 时,耗时:"<<endl;
srand((unsigned)time(NULL));
for(int i=0;i<20;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<<endl;
count += time_used;
}
cout<<"\n选择排序平均耗时:"<<count/20<<"毫秒"<<endl<<endl;
count = 0;
MAX *= 10;
}
break;
case 2:
for(int j=0;j<5;j++){ //控制问题规模MAX从10-100000
cout<<"数组规模MAX="<<MAX<<" 时,耗时:"<<endl;
srand((unsigned)time(NULL));
for(int i=0;i<20;i++){ //控制20组随机数产生
randNum(MAX,array);
time_start = clock();
buddle_sort(MAX,array);
time_end = clock();
time_used = time_end - time_start;
cout<<time_used<<" ";
//cout<<endl;
count += time_used;
}
cout<<"\n冒泡排序平均耗时:"<<count/20<<"毫秒"<<endl<<endl;
count = 0;
MAX *= 10;
}
break;
case 3:
for(int j=0;j<5;j++){ //控制问题规模MAX从10-100000
cout<<"数组规模MAX="<<MAX<<" 时,耗时:"<<endl;
srand((unsigned)time(NULL));
for(int i=0;i<20;i++){ //控制20组随机数产生
randNum(MAX,array);
time_start = clock();
merge_sort(array,0,MAX-1);
time_end = clock();
time_used = time_end - time_start;
cout<<time_used<<" ";
//cout<<endl;
count += time_used;
}
cout<<"\n合并排序平均耗时:"<<count/20<<"毫秒"<<endl<<endl;
count = 0;
MAX *= 10;
}
break;
case 4:
for(int l=0;l<5;l++){ //控制问题规模MAX从10-100000
cout<<"数组规模MAX="<<MAX<<" 时,耗时:"<<endl;
srand((unsigned)time(NULL));
for(int i=0;i<20;i++){ //控制20组随机数产生
randNum(MAX,array);
time_start = clock();
quick_sort(array,0,MAX);
time_end = clock();
time_used = time_end - time_start;
cout<<time_used<<" ";
//cout<<endl;
count += time_used;
}
cout<<"\n快速排序平均耗时:"<<count/20<<"毫秒
"<<endl<<endl;
count = 0;
MAX *= 10;
}
break;
case 5:
for(int j=0;j<5;j++){ //控制问题规模MAX从10-100000
cout<<"数组规模MAX="<<MAX<<" 时,耗时:"<<endl;
srand((unsigned)time(NULL));
for(int i=0;i<20;i++){ //控制20组随机数产生
randNum(MAX,array);
time_start = clock();
insert_sort(MAX,array);
time_end = clock();
time_used = time_end - time_start;
cout<<time_used<<" ";
//cout<<endl;
count += time_used;
}
cout<<"\n插入排序平均耗时:"<<count/20<<"毫秒"<<endl<<endl;
count = 0;
MAX *= 10;
}
break;
default: cout<<"请输入合法的序号!";
}
}
return 0;
}。

相关文档
最新文档