快速排序.docx
- 文档编号:3656389
- 上传时间:2022-11-24
- 格式:DOCX
- 页数:9
- 大小:68.59KB
快速排序.docx
《快速排序.docx》由会员分享,可在线阅读,更多相关《快速排序.docx(9页珍藏版)》请在冰豆网上搜索。
快速排序
算法设计与分析实验报告
实验一快速排序
院系:
班级:
计算机科学与技术
学号:
姓名:
任课教师:
成绩:
湘潭大学
2016年5月
实验一快速排序
一.实验内容
运用分治递归思想,编程实现快速排序算法。
通过不同实例测试,分析最坏、最好、平均情况下的时间复杂度,并设计实验程序验证分析结果。
二.实验目的
1、理解递归的概念及实现方法;
2、掌握分治策略的基本思想以及用分治法解决问题的一般技巧;
3、掌握求解递归算法时间复杂度的一般方法。
三.算法描述
/*递归形式的快速排序算法*/
VoidQSort(SqList&L,intlow,inthigh){
//对顺序表L中的子序列L.r[low..high]作快速排序
If(low pivotloc=Partition(L,low,high);//将L.r[low..high]一分为二 QSort(L,low,pivotloc-1);//对低子表递归排序 QSort(L,pivotloc+1,high);//对高子表递归排序 } }//QSort VoidQuickSort(SqList&L){ //对顺序表L作快速排序 QSort(L,1,L.length); }//QuickSort 四.算法实现 1.数据结构及函数说明 基本思想: 通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。 intPartition(SqList&L,intlow,inthigh){ //交换顺序表L中子表r[low..high]的记录,枢轴记录到位,并返回其所 //在位置,此时在它之前的记录均不大于它。 L.r[0]=L.r[low];//用子表的第一个记录作枢轴记录 pivotkey=L.r[low].key;枢轴记录关键字 while(low while(low L.r[low]=L.r[high];//将比枢轴记录小的记录移到低端 while(low L.r[high]=L.r[low];//将比枢轴记录大的记录移到高端 } L.r[low]=L.r[0];//枢轴记录到位 returnlow;//返回枢轴位置 } 函数说明: intchoose_pivot(inti,intj) { return((i+j)/2);//取中轴数 } 2.源程序代码 #include #include #include intchoose_pivot(inti,intj) { return((i+j)/2); } voidquicksort(intlist[],intm,intn) { intkey,i,j,k; if(m { k=choose_pivot(m,n); swap(&list[m],&list[k]); key=list[m]; i=m+1; j=n; while(i<=j) { while((i<=n)&&(list[i]<=key)) i++; while((j>=m)&&(list[j]>key)) j--; if(i swap(&list[i],&list[j]); } swap(&list[m],&list[j]); quicksort(list,m,j-1); quicksort(list,j+1,n); } } voidprintlist(intlist[],intn) { inti; for(i=0;i printf("%d\t",list[i]); } voidmain() { clock_tstart,finish; start=clock(); floatduration; intn; printf("******************************************************************\n"); printf("数组长度: "); scanf("%d",&n); constintMAX_ELEMENTS=n; intlist[MAX_ELEMENTS]; inti=0; srand((unsigned)time(NULL)); for(i=0;i list[i]=rand()%100; } printf("排序之前的序列: \n"); printlist(list,MAX_ELEMENTS); quicksort(list,0,MAX_ELEMENTS-1); printf("\n排序之后的序列: \n"); printlist(list,MAX_ELEMENTS); finish=clock(); duration=(float)(finish-start); printf("\n所需时间: %fms\n",duration); printf("******************************************************************\n"); returnmain(); } voidswap(int*x,int*y) { inttemp; temp=*x; *x=*y; *y=temp; } 五.程序运行结果 随机产生十组长度为10的数组,随机产生的数组和排序后以及排序所需时间的结果如截图所示: 六.实验结果分析 最好情况: 每次都能均匀的划分序列,时间复杂度为O(nlogn)和平均情款时间复杂度一样; 最坏情况: 枢轴元为最大或者最小数字,那么所有数字会划分到一个序列中,时间复杂度为O(n^2); 分析: (由于是随机产生的数组不一定能产生最好或最坏情款就随便举例一组数据分析) 最好情款: 例如: 4,1,3,2,6,5,7,每次使用序列的第一个元素做枢轴.比较总次数为10次,交换3次,具体如下: 第一次枢轴为4,序列划分为{2,1,3},4,{6,5,7} 比较6次(4与每个元素比较一次),交换1次(4与2交换) 第二次的两个序列枢轴分别为2和6,此时划分序列得{1},2,{3},4,{5},6,{7} 比较4次(两个序列各比较两次),交换两次(1和2,6和5) 第三次由于各个序列的元素都为1,因此排序完成得1,2,3,4,5,6,7 最坏情款: 例如: 4,1,3,2,6,5,7,每次使用序列的第一个元素做枢轴,具体如下: (每次选择最大的数为枢轴) 第一次枢轴为7,序列划分为{4,1,3,2,6,5},7 比较6次(7与每个元素比较一次),不交换 第二次的序列枢轴为6,此时划分序列得{4,1,3,2,5},6,{7} 比较5次(6与每个元素比较一次),不交换 第三次序列枢轴为5,此时划分序列得{4,1,3,2},5,{6,7} 比较4次(5与每个元素比较一次),不交换 第四次序列枢轴为4,此时划分序列得{1,3,2},4,{5,6,7} 比较3次(4与每个元素比较一次),不交换 第五次序列枢轴为3,此时划分序列得{1,2},3,{4,5,6,7} 比较2次(3与每个元素比较一次),不交换 第六次序列枢轴为2,此时划分序列得{1},2,{3,4,5,6,7} 比较1次(3与每个元素比较一次),不交换 最后排序完成得{1,2,3,4,5,6,7} 七.结论 影响算法时间复杂度的关键因素是每次枢轴元素的选择,选择基准数据时我们不再总是选择第一个划分的第一个元素,而是随机的从划分中选择一个。 假设我们排序一个数列,然后把它分为四个部份。 在中央的两个部份将会包含最好的基准值;他们的每一个至少都会比25%的元素大,且至少比25%的元素小。 如果我们可以一致地从这两个中央的部份选出一个元素,在到达大小为1的数列前,我们可能最多仅需要把数列分区2log2 n次,产生一个 O(nlogn)算法。 不幸地,乱数选择只有一半的时间会从中间的部份选择。 出人意外的事实是这样就已经足够好了。 想像你正在翻转一枚硬币,一直翻转一直到有 k 次人头那面出现。 尽管这需要很长的时间,平均来说只需要 2k 次翻动。 且在 100k 次翻动中得不到 k 次人头那面的机会,是像天文数字一样的非常小。 借由同样的论证,快速排序的递归平均只要2(2log2 n)的调用深度就会终止。 但是如果它的平均调用深度是O(log n)且每一阶的调用树状过程最多有 n 个元素,则全部完成的工作量平均上是乘积,也就是O(n log n)。 这样就不会出现上述中最坏的情况。 为了更加减少上面的概率一般可以随机三个数选择中间一个,这样就会大大减少最坏情况的发生。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 快速 排序
![提示](https://static.bdocx.com/images/bang_tan.gif)