#include<stdio.h>
#include<iostream.h>
#include<stdlib.h>
#include<time.h>
#define N 1000000
void swap(long A[],long x,long y)
{
long t;
t=A[x];
A[x]=A[y];
A[y]=t;
}
long Partition(long A[],long p,long r)
{
long x=A[r];
long i=p-1;
long j;
for(j=p;j<=r-1;j++)
{
if (A[j]<=x)
{
i=i+1;
swap(A,i,j);
}
}
swap(A,i+1,r);
return i+1;
}
void QuickSort(long A[],long p,long r)
{
if(p<r)
{
int q=Partition(A,p,r);
QuickSort(A,p,q-1);
QuickSort(A,q+1,r);
}
}
void main()
{
long *A,i;
clock_t x,y;
double t;
A=new long[N];
srand((unsigned int)time(0));//随机取种 以当前时间取种
for(i=0;i<N;i++)
A[i]=rand();//随机生成a数组
x=clock();//开始计时
QuickSort(A,0,N-1);
y=clock();//计时结束
t=double(y-x)/CLOCKS_PER_SEC;
printf("The number is %d/n",N);
printf("The time is %f seconds/n",t);
}
另附报告:
QuickSort算法实验性能分析
u 需求分析
利用随机数生成函数生成大量数据,按不同规模调用快速排速算法,记录所花费的时间,作出运行时间(time)—输入规模(size)图,以反映及分析快速排序的时间复杂度随输入规模不断变化的变化情况,并观察是否符合O(nlgn)的时间复杂度。
u 算法设计
² 设计思想
算法所用的数据结构:
数组long型A[N],调用快排序算法时对数组中元素进行就地重排并输出排序规模及排序时间。
算法基本思想:
用随机函数生成的大量随机数初始化数组,算法运行时调用快速排序算法,并对所产生的随机数进行排序并输出随机数的规模及每次排序花费的时间
² 概要设计
对每个函数的说明:
(1) void swap(long A[],long x,long y)
该函数用来交换数组A中两个元素x和y的位置;
(2) long Partition(long A[],long p,long r)
对子数组A[p……r]进行就地重排;
(3) void QuickSort(long A[],long p,long r)
递归调用进行快速排序;
² 详细设计
主要算法思想及描述:
#include<stdio.h>
#include<iostream.h>
#include<stdlib.h>
#include<time.h>
#define N 1000000
void QuickSort(long A[],long p,long r) //分治法实现快速排序
long Partition(long A[],long p,long r) //对子数组A[p……r]进行就地重排
(1) 主函数main()先产生N个随机数放进数组A,然后调用快排序算法QuickSort实现对数组元素的就地排序,并输出排序所花费的时间;设计如下:
void main()
{
long *A,i;
clock_t x,y;
double t;
A=new long[N];//随机动态分配空间
srand((unsigned int)time(0));//随机取种(以当前时间取种)
for(i=0;i<N;i++)
A[i]=rand();//随机生成A数组
x=clock();//开始计时
QuickSort(A,0,N-1); //进行快速排序
y=clock();//计时结束
t=double(y-x)/CLOCKS_PER_SEC;//排序时间
printf("The number is %d/n",N);//输出数组规模
printf("The time is %f seconds/n",t);//输出排序时间
}
(2) 函数Partition(long A[],long p,long r)采用分治算法对子数组A[p .. r ]就地重排;有三个步骤:
Ø 分解:数组A[ p .. r ]被划分成两个(可能空)子数组A[p .. q-1]和A[q+1 .. r],使得A[p .. q-1]中的每个元素都小于等于A[q],而且,小于等于A[q+1 .. r]中的元素。下标q也在这个划分过程中进行计算。
Ø 解决:通过递归调用快速排序,对子数组A[p .. q-1]和A[q+1 .. r]排序。
Ø 合并:因为两个子数组是就地排序的,将它们的合并不需要操作:整个数组A[ p .. r ]已排序。
设计如下:
void QuickSort(long A[],long p,long r)
{
if(p<r)
{
int q=Partition(A,p,r);
QuickSort(A,p,q-1);
QuickSort(A,q+1,r);
}
}
(3) 快速排序算法的关键是Partition过程,它对子数组就地重排,并返回划分元位置。
设计如下:
long Partition(long A[],long p,long r)
{
long x=A[r]; //主元值
long i=p-1; //i为数组A[p……q-1]中最大元素下标
long j;
for(j=p;j<=r-1;j++) //j代表当前未划分元素下标
{
if (A[j]<=x)
{
i=i+1;
swap(A,i,j);
}
}
swap(A,i+1,r);
return i+1;
}
其中:
void swap(long A[],long x,long y) //交换数组A中两个元素x和y的位置
{
long t;
t=A[x];
A[x]=A[y];
A[y]=t;
}
v 注:快速排序也可采用随机化版本,在一定意义上更符合其时间复杂度为O(nlgn)的理论值;但对于本次实验,数组有很强的随机性,所以即使固定了主元值,该主元值的随机性也很强,即不需要采用随机化版本,从实验结果看来,很好的符合其时间复杂度为O(nlgn)的理论值。
u 三.测试数据及结果分析
测试环境: 内存:1G Windows Vista操作系统
运行结果( 单位:s )--数据及曲线图如下:
| t/1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 平均 |
X/1 | 1.1 | 1.097 | 1.085 | 1.109 | 1.265 | 1.078 | 1.069 | 1.521 | 1.263 | 1.168 | 1.1755 |
2 | 3.447 | 3.837 | 3.853 | 3.609 | 3.19 | 3.265 | 3.804 | 3.32 | 3.267 | 3.445 | 3.5037 |
3 | 6.956 | 6.758 | 6.515 | 7.06 | 6.624 | 7.06 | 7.032 | 6.562 | 7.268 | 7.245 | 6.908 |
4 | 11.441 | 10.731 | 11.771 | 11.461 | 11.439 | 11.652 | 10.308 | 11.76 | 10.741 | 10.834 | 11.2138 |
5 | 15.859 | 15.636 | 16.597 | 15.644 | 16.54 | 15.656 | 17.57 | 15.659 | 15.807 | 16.941 | 16.1909 |
6 | 21.716 | 22.375 | 21.931 | 21.223 | 23.488 | 21.595 | 23.791 | 21.836 | 22.269 | 21.61 | 22.1834 |
7 | 28.822 | 29.827 | 30.219 | 29.545 | 29.894 | 29.545 | 29.782 | 29.7 | 30.264 | 29.712 | 29.731 |
8 | 37.454 | 37.47 | 36.906 | 37.802 | 37.445 | 38.151 | 38.832 | 38.089 | 37.476 | 38.08 | 37.7705 |
9 | 46.695 | 46.091 | 48.396 | 45.843 | 47.089 | 47.67 | 46.462 | 46.398 | 48.248 | 46.257 | 46.9149 |
10 | 58.938 | 57.856 | 57.294 | 57.546 | 56.453 | 59.284 | 57.646 | 56.77 | 56.727 | 57.421 | 57.5935 |
X单位:百万
由上图易知,实验结果很好的符合了快速排序时间复杂度为O(nlgn)。符合理论。
u 时间及空间性能分析:
该程序执行时需要动态随机调用空间(用new函数),否则计算机的硬件无法满足一次几百万随机数的空间。采用动态随机分配空间,空间复杂度不高。
另一方面,采用分治思想的快速排序,时间复杂度为O(nlgn)。