数据结构课程设计报告.docx

上传人:b****6 文档编号:4116705 上传时间:2022-11-28 格式:DOCX 页数:11 大小:19.08KB
下载 相关 举报
数据结构课程设计报告.docx_第1页
第1页 / 共11页
数据结构课程设计报告.docx_第2页
第2页 / 共11页
数据结构课程设计报告.docx_第3页
第3页 / 共11页
数据结构课程设计报告.docx_第4页
第4页 / 共11页
数据结构课程设计报告.docx_第5页
第5页 / 共11页
点击查看更多>>
下载资源
资源描述

数据结构课程设计报告.docx

《数据结构课程设计报告.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计报告.docx(11页珍藏版)》请在冰豆网上搜索。

数据结构课程设计报告.docx

数据结构课程设计报告

《数据结构》课程设计报告

 

课题名称:

快速排序的优化

 

课题负责人(学号):

印耶蓬(1043111122)

指导教师:

杨秋辉

评阅成绩:

评阅意见:

 

提交报告时间:

2011年12月8日

Project4:

快速排序的优化

1.Goal:

EmpiricalstudytocomparerunningtimesofdifferentQuicksortoptimizationstrategies

Task:

StartingwiththecodeforQuicksortgiveninchapter7,writeaseriesofQuicksortimplementationstotestthefollowingoptimizationsonawiderangeofinputdatasizesN.TrytheseoptimizationsinvariouscombinationstotryanddevelopthefastestpossibleQuicksortimplementationthatyoucan.

(a)Lookatmorevalueswhenselectingapivot.

(b)Donotmakearecursivecalltoqsortwhenthelistsizefallsbelowagiventhreshold,anduseInsertionSorttocompletethesortingprocess.Testvariousvaluesforthethresholdsize.

(c)Eliminaterecursionbyusingastack.

Inyourmainprogram,firstyoucangenerateNdifferentrandomvaluestobesorted.ItthenexecutesQuicksortindifferentways:

nooptimizations,withoptimization(a)or(b)or(c)ortheirvariouscombinations(suchas(a)combine(b),(a)combine(c),(b)combine(c),(a)combine(b)and(c)).ItwritesoutN,optimizationstrategy,andtherunningtime.ItrepeatsthisforN=10,100,1000,10000,100000,1000000.

Pleaseensurethatyougeneratereallyrandomnumber.You’dbetterusinganappropriate‘seed’:

thisisusedtoinitializetherandomnumbergenerationprocess.

2.Design

●系统设计思想:

由于此次项目是检测快速排序的三种优化方式,所以大部分结构由函数构成。

有一个数据类用来表示子数组的状态,用于栈模拟递归调用。

C++类:

classData

{

public:

inti;//数组的左端

intj;//数组的右端

intmode;//使用的模式

Data(inti,intj,intmode)//构造函数

{

this->i=i;

this->j=j;

this->mode=mode;

}

};

C:

//在数组A中交换下标为i和j的值

voidswap(int*A,inti,intj);

//原始的查找轴中值的函数,返回数组A中间的一个数的下标

intfindpivot1(int*A,inti,intj);

//优化的查找轴中值的函数,采用三者取中法,返回数组A中

//第一个、最后一个以及中间一个数的中间数的下标

intfindpivot2(int*A,inti,intj);

//分段函数,将数组A分为两部分,前部分的数小于轴中值,

//后部分的数大于等于轴中值。

返回后部分数组的第一个数下标

intpartition(int*A,intl,intr,int&pivot);

//递归快速排序的主函数,i、j分别表示数组A的首尾数的下标,

//mode参数表示采用哪种优化组合方式

voidqsort(int*A,inti,intj,intmode);

//栈模拟的快速排序的主函数,i、j分别表示数组A的首尾数的//下标,mode参数表示采用哪种优化组合方式

voidstackqsort(int*A,inti,intj,intmode);

//插入排序,l、r分别表示数组A的收尾数的下标

voidinssort(int*A,intl,intr);

函数调用说明:

在递归快速排序中将调用插入排序和查找轴中值的函数,具体调用根据mode的数值决定。

Mode=1:

不采用优化措施

Mode=2:

采用优化取值

Mode=3:

采用插入排序(数组长度小于9)

Mode=4:

采用优化取值+插入排序

在栈模拟递归的快速排序中将调用插入排序和查找轴中值的函数,具体调用根据mode的数值决定。

Mode=1:

不采用优化措施

Mode=2:

采用优化取值

Mode=3:

采用插入排序(数组长度小于9)

Mode=4:

采用优化取值+插入排序

总共共有8种模式,分别来模拟

(1)优化取值

(2)插入排序(3)栈模拟递归3种优化快速排序的组合方式对快速排序的影响。

●主要文件设计说明

1.Quicksort.h主要存放本次项目所用的函数及类的声明,头文件的包含等。

2.Quicksort.cpp主要存放所有在Quicksort.h中声明的函数的实现

3.Main.cpp存放函数的主程序,运行界面以及随机数的生成,时间的计算等。

3.Implementation

C++类:

classData

{

public:

inti;//数组的左端

intj;//数组的右端

intmode;//使用的模式

Data(inti,intj,intmode)//构造函数

{

this->i=i;

this->j=j;

this->mode=mode;

}

};

C:

//在数组A中交换下标为i和j的值

voidswap(int*A,inti,intj)

{

inttemp;

temp=A[i];

A[i]=A[j];

A[j]=temp;

}

//原始的查找轴中值的函数,返回数组A中间数的下标

intfindpivot1(int*A,inti,intj)

{

return(i+j)/2;

}

//优化的查找轴中值的函数,采用三者取中法,返回数组A中

//第一个、最后一个以及中间一个数的中间数的下标

intfindpivot2(int*A,inti,intj)

{

if((A[(i+j)/2]>A[i]&&A[(i+j)/2]A[j]))

return(i+j)/2;

elseif((A[i]>A[j]&&A[i]A[(i+j)/2]))

returni;

else

returnj;

}

//分段函数,将数组A分为两部分,前部分的数小于轴中值,

//后部分的数大于等于轴中值。

返回后部分数组的第一个数下标

intpartition(int*A,intl,intr,int&pivot)

{

do

{

//从数组左边开始找,直到遇到比轴中值大或等于轴中值的数

while(A[++l]

//从数组右边开始找,直到遇到比轴中值小或者已经到数组顶端

while((r!

=0)&&A[--r]>pivot);

//交换刚才的两个数

swap(A,l,r);

}while(l

swap(A,l,r);//反转交换

returnl;

}

//递归快速排序的主函数,i、j分别表示数组A的首尾数的下标,

//mode参数表示采用哪种优化组合方式

voidqsort(int*A,inti,intj,intmode)

{

//根据模式选择是否使用插入排序

if(mode==3||mode==5||mode==7||mode==8)

if(j-i<=8)

{

inssort(A,i,j);

return;

}

if(j<=i)return;//当数组只有0或1个元素时返回

intpivotindex;

//根据模式选择采用哪种方式查找轴中值

if(mode==1||mode==3||mode==4||mode==7)

pivotindex=findpivot1(A,i,j);

else

pivotindex=findpivot2(A,i,j);

swap(A,pivotindex,j);

intk=partition(A,i-1,j,A[j]);

swap(A,k,j);

//递归调用

qsort(A,i,k-1,mode);

qsort(A,k+1,j,mode);

}

//栈模拟的快速排序的主函数,i、j分别表示数组A的首尾数的//下标,mode参数表示采用哪种优化组合方式

voidstackqsort(int*A,inti,intj,intmode)

{

stackst;

intpivotindex;

Data*tmp;

intk;

st.push(newData(i,j,mode));

while(!

st.empty())

{

tmp=st.top();

st.pop();

i=tmp->i;

j=tmp->j;

mode=tmp->mode;

if(mode==3||mode==4)

if(j-i<=8)

{

inssort(A,i,j);

continue;

}

if(j<=i)

continue;

if(mode==1||mode==3)

pivotindex=findpivot1(A,i,j);

else

pivotindex=findpivot2(A,i,j);

swap(A,pivotindex,j);

k=partition(A,i-1,j,A[j]);

swap(A,k,j);

//将长度较大的数组先压栈,以此保证栈的深度最小

if(k-i>j-k)

{

st.push(newData(i,k-1,mode));

st.push(newData(k+1,j,mode));

}

else

{

st.push(newData(k+1,j,mode));

st.push(newData(i,k-1,mode));

}

}

}//插入排序,l、r分别表示数组A的收尾数的下标

voidinssort(int*A,intl,intr)

{

for(inti=l+1;i

{

for(intj=i;(j>l)&&(A[j]

{

swap(A,j,j-1);

}

}

}

4.Testing

●测试数据选择

实验采用随机生成N=10,100,1000,10000,100000,1000000个数(范围在0-10000),用8种模式对这些数进行排序,并计算时间。

总共测试4次,取平均值。

测试数据及图表在测试数据统计.xlsx文件中。

●测试结果及其分析((覆盖率报告单独提交)

结果分析:

从图表中明显可以看出使用了插入排序的模式时间都大大缩短,而使用了栈模拟递归调用的模式时间都大大增加。

其中插入排序+优化取值模式使用时间与只使用插入排序的模式时间大致一致,而单独看使用了优化取值的模式与使用了插入排序的模式,可以发现使用了插入排序的模式更加出色,特别市在加入了栈模拟递归后对比更见明显。

可以得出结论:

对小数组使用插入排序可以大大提高快速排序的运行效率。

单独看使用了优化取值和没有使用优化取值的快速排序可以发现,优化取值模式只有很少的提高,有时甚至比不适用更慢。

通过分析,如果数组中间值就是轴中值的话,不使用优化取值会效率更高。

我们可以得出结论,优化取值只能在一定程度上提高快速排序的效率,效果并不明显。

最后可以看到使用了栈模拟递归的模式都远远慢于不适用的模式。

通过分析我们可以知道,一般来说递归调用的栈会由程序自动生成,这些栈里包含了函数调用时的参数和函数中的局部变量。

如果局部变量很多或者函数内部又调用了其他函数,则栈会很大。

每次递归调用都要操作很大的栈,效率自然会下降。

而本程序所包含的信息很少,所以自己用栈模拟递归调用效率不一定会高,恰恰相反,由于是自己模拟递归调用,时间上比程序内部自动生成要慢。

5.Analysis

由于课本上已经有了原始快速排序的算法分析了,这里就不再赘述,主要说一下优化后的运行效率的提高。

首先就是在对于小数组使用插入排序。

因为对于个数较小的数组,由于快速排序的性质,可以知道数组是基本有序的。

对于基本有序的数组,使用插入排序的效率会比继续使用快速排序高很多。

对于三者取中法找轴中值的方法,一定程度上能避免快速排序进入最差情况,但是由于只对三个数进行取中,不能很好地代表多数情况,特别在排序规模很大的情况下,所以提升空间很小。

最后对于栈的模拟递归调用,在结果分析中已经提到,因为这个项目栈所存取的信息量很少,所以程序自动生成栈会比程序员自己生成栈要快。

但是当递归调用的函数所要存取的信息量很大时,栈模拟递归调用会比递归调用要快。

在项目的最后,我还另外写了一个栈模拟递归调用的函数(见附),在这个函数中将数组首尾的下标分别压入压出栈,运行后发现时间更慢,这是由于在栈模拟递归调用时,使用栈的pop()和push()时也会占用大量的时间,如果大量使用栈函数,则会降低运行效率,这也是栈模拟递归调用比递归调用要慢的原因。

附:

voidstackqsort1(intA[],inti,intj,intmode)

{

intpivotindex;

stackS;

S.push(j);

S.push(i);

while(!

S.empty())

{

i=S.top();

S.pop();

j=S.top();

S.pop();

if(mode==3||mode==4)

if(j-i<=8)

{

inssort(A,i,j);

continue;

}

if(j<=i)

continue;

if(mode==1||mode==3)

pivotindex=findpivot1(A,i,j);

else

pivotindex=findpivot2(A,i,j);

swap(A,pivotindex,j);

intk=partition(A,i-1,j,A[j]);

swap(A,k,j);

if(k-i>j-k)

{

S.push(k-1);

S.push(i);

S.push(j);

S.push(k+1);

}

else

{

S.push(j);

S.push(k+1);

S.push(k-1);

S.push(i);

}

}

}

当排序规模为1000000时

原始快速排序:

0.575秒

较少使用栈函数的模拟递归函数:

4.219秒

较多使用栈函数的模拟递归函数:

8.205秒

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育 > 政史地

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1