一 问题描述
对一个较大规模的数组进行排序,分别使用冒泡,快速,和堆排序,比较这三种方法的效率.
二 算法分析与设计
三种算法要比较哪一个效率更高,必须使用相同的数组进行排序,而且数组的元素个数要相当大,这样才能够看处它们执行效率的差别。要输入一个很大的数组显然不符合现实,因为工程太庞大了,所以我们用随机产生函数:rang()来产生所要的数组,虽然每次产生的数组都不一样,但是随机性更能体现出一个算法执行的好和坏。我们并不是就执行一次,而是通过多次的执行得出结论。
数组产生了以后,接下来的事情就是用每一种排序方法对产生的数组进行排序,同时记录下排序所需要的时间,我们通过所花时间的多少来比较哪个算法的效率高。记录时间我们用:
t=clock()这个函数,开始排序的时间:t1=clock();和结束排序后的时间:t2=clock().两者相减得到:t=t2-t1,t就是所花的时间,t/CLOCKS_PER_SEC就把所花的时间转化为秒数。
这样,我们只要再程序运行的时候输入数组的大小,就可以通过不同的排序得出不同的排序所花的时间,从而得出比较的结果。
三 时间复杂度分析
冒泡排序的时间复杂度为: T(n) = O(n^2)
快速排序的时间复杂度为: T(n) = O(n*log n) (前面的报告中已经有分析说明)
堆 排序的时间复杂度为 : T(n) = O(n*log n) ( 在最坏的情况下)
堆排序的运行时间主要是耗费在建立初始堆和调整建立新堆的反复筛选上面,在建立初始堆的时候,需要的时间是0(n);因为在建初始堆的时候,调用Heapify() n/2次,有Heapify()所需要的时间可知道,当i在n/2的到n/4+1的范围内时,每次调用耗费时间为C,C为一常数,当i在n/4到n/8+1的范围内时,耗费的时间为2C,………。所以
C(n/4+2*n/8+3*n/16+……..)=O(n)
在调整堆的时候,调用Heapify共n-1次,每次调用所需要的时间为O(n)的时间,所以整个算法在最坏的情况下只需要:T(n) = O(n*log n) 的时间。
四 运行结果和分析
1)当数组的规模都为10000个元素的时候:
冒泡排序所需的时间是:0.625秒;快速排序和堆排序基本上不需要时间(因为规模比较小所以看不出来)。
2)当数组的规模都为100000个元素的时候:
冒泡排序所需要的时间为:69.875秒;
快速排序所需要的时间为:0.047 秒;
堆 排序所需要的时间为:0.031 秒;
从上面的比较不难看出堆排序要比快速好,快速又要比冒泡排序好。但这时候堆排序和快速排序所花的时间相差不时很多。
3)当数组规模为1000000个元素的时候:
这主要是比较快速排序和堆排序之间的差距,因为当规模这么大时,冒泡排序要花太多时间所以就没有进行比较测试。从结果中可以看到,当数组规模很大的时候,堆排序的优势就彻底的体现出来了,比快速排序要块很多。所以证明了一点,当数组元素很大的时候,用堆排序时最优的。
--------------------------------------------------------------------------------
附 源程序
// 主程序 (.cpp文件)
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <malloc.h>
#include <conio.h>
#include "BobbleSort.h"
#include "QuickSort.h"
#include "HeapSort.h"
int main()
{
int N;
int *a;
time_t start ,end;
double usetime;
int i,j;
i=1;
while(i<=3)
{
if(i==1)
printf("--------------------冒 泡 排 序--------------------\n");
else if(i==2)
printf("--------------------快 速 排 序--------------------\n");
else if(i==3)
printf("-------------------- 堆 排 序 --------------------\n");
printf("输入数组元素N的值: ");
scanf("%d",&N);
if(i==3)
a=(int *)malloc((N+1)*sizeof(int));
else
a=(int *)malloc(N*sizeof(int));
if(!a)exit(1);
srand(time(NULL));
if(i==3)
for(j=1;j<=N;j++)
a[j]=rand()%1000;
else
for(j=0;j<N;j++)
a[j]=rand()%1000;
start=clock();
if(i==1)
BobbleSort(a,N);
else if(i==2)
QuickSort(a,0,N-1);
else if(i==3)
HeapSort(a,N);
end=clock();
usetime=(end-start)*1.0/CLOCKS_PER_SEC;
printf("该排序所花的时间为:");
printf("%lf 秒\n",usetime);
free(a);
i++;
}
getch();
return 0;
}
//********************************* BobbleSort.h文件
void BobbleSort(int a[],int N) //冒泡排序的算法
{
int k,flag,m,j;
flag=1; //设置一个标志位用来表示在每一轮的比较中是否有元素交换.
m=N-1;
while(flag>0)
{
flag=0;
k=m;
for(j=0;j<k;j++)
if(a[j]>a[j+1])
{
int t;
t=a[j];a[j]=a[j+1];a[j+1]=t;
flag=1;
m=j;
}
}
}
//************************************* QuickSort.h文件
int Partion(int a[],int low,int high) //找出分割位置
{
int key;
key=a[low];
while(low<high)
{
while(low<high&&a[high]>=key)high--;
a[low]=a[high];
while(low<high&&a[low]<=key)low++;
a[high]=a[low];
}
a[low]=key;
return low;
}
void QuickSort(int a[],int low,int high)
{
int po;
if(low<high)
{
po=Partion(a,low,high);
QuickSort(a,low,po-1); //递归调用
QuickSort(a,po+1,high);
}
else return ;
}
//***************************************** HeapSort.h 文件
void swap(int &a,int &b)
{
a=a+b;
b=a-b;
a=a-b;
}
void Heapify(int a[],int k,int m) //整理堆
{
int k1=2*k;
int k2=2*k+1;
if(k2<=m)
{
if((a[k1]>a[k2]&&a[k2]>a[k])||(a[k1]>a[k]&&a[k2]<a[k]))
{
swap(a[k1],a[k]);
Heapify(a,k1,m);
}
else if((a[k1]<a[k2]&&a[k1]>a[k])||(a[k2]>a[k]&&a[k]>a[k1]))
{
swap(a[k2],a[k]);
Heapify(a,k2,m);
}
}
else if(k1<=m)
{
if(a[k1]>a[k])
{
swap(a[k1],a[k]);
Heapify(a,k1,m);
}
}
else return ;
}
void HeapSort(int a[],int m)
{
int i;
for(i=m/2;i>=1;i--)
Heapify(a,i,m);
for(i=m;i>1;i--)
{
swap(a[i],a[1]);
Heapify(a,1,i-1);
}
}