中科大软件学院算法实验报告.docx
- 文档编号:30488488
- 上传时间:2023-08-15
- 格式:DOCX
- 页数:37
- 大小:87.28KB
中科大软件学院算法实验报告.docx
《中科大软件学院算法实验报告.docx》由会员分享,可在线阅读,更多相关《中科大软件学院算法实验报告.docx(37页珍藏版)》请在冰豆网上搜索。
中科大软件学院算法实验报告
算法实验报告
快速排序
1.问题描述:
实现对数组的普通快速排序与随机快速排序
(1)实现上述两个算法
(2)统计算法的运行时间
(3)分析性能差异,作出总结
2.算法原理:
2.1快速排序
快速排序是对冒泡排序的一种改进。
它的基本思想是:
选取一个基准元素,通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比基准元素小,另外一部分的所有数据都要比基准元素大,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
设要排序的数组是A[0]……A[N-1],首先选取一个数据(普通快速排序选择的是最后一个元素,随机快速排序是随机选择一个元素)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。
一趟快速排序的算法是:
1)设置两个变量i、j,排序开始的时候:
i=0,j=N-1;
2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];
3)从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于key的值A[j],将A[j]赋给A[i];
4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]赋给A[j];
5)重复第3、4步,直到i=j;(3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。
找到符合条件的值,进行交换的时候i,j指针位置不变。
另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。
2.2随机快速排序
快速排序的最坏情况基于每次划分对主元的选择。
基本的快速排序选取第一个或者最后一个元素作为主元。
这样在数组已经有序的情况下,每次划分将得到最坏的结果。
一种比较常见的优化方法是随机化算法,即随机选取一个元素作为主元。
这种情况下虽然最坏情况仍然是O(n^2),但最坏情况不再依赖于输入数据,而是由于随机函数取值不佳。
实际上,随机化快速排序得到理论最坏情况的可能性仅为1/(2^n)。
所以随机化快速排序可以对于绝大多数输入数据达到O(nlogn)的期望时间复杂度。
3.实验数据
本实验采用对80,000个随机数据进行十次排序,并取出平均值。
分别用普通快速排序和随机快速排序对数据排序。
用毫秒作为运行计数单位,观测两种算法所用的时间的不同。
4.实验截图
如下图所示的时间,普通快速排序所用的平均时间为181毫秒,而随机化版本的快速排序所用时间仅仅为119毫秒。
5.结果分析
5.1时间分析
从实验截图得到的结果来看,随机化版本的快速排序所用时间比普通快速排序所用的平均时间少。
快速排序的平均时间复杂度为O(nlogn),最坏时间时间可达到O(n^2),最坏情况是当要排序的数列基本有序的时候。
根据快速排序的工作原理我们知道,选取第一个或者最后一个元素作为主元,快速排序依次将数列分成两个数列,然后递归将分开的数列进行排序。
当把数列平均分成两个等长的数列时,效率是最高的,如果相差太大,效率就会降低。
我们通过使用随机化的快速排序随机的从数列中选取一个元素与第一个,或者最后一个元素交换,这样就会使得数列有序的概率降低。
随机化快速排序的平均时间复杂度为O(nlogn),最坏时间时间也会达到O(n^2),这种机率已经降得很小。
5.2空间分析
普通快速排序与随机快速排序在对序列的操作过程中都只需花费常数级的空间。
空间复杂度S
(1)。
但需要注意递归栈上需要花费最少logn最多n的空间
6源码
快速排序源码C++实现
#include
#include
usingnamespacestd;
voidQuickSort(intarr[],intlo,inthi)
{
//这里的lo和hi是数组的下标;
if(lo>=hi){return;}
intfi=lo;//0开始
intla=hi;//最大下标开始
intkey=arr[fi];
while(fi { while(fi --la; arr[fi]=arr[la]; while(fi ++fi; arr[la]=arr[fi]; } arr[fi]=key; QuickSort(arr,lo,fi-1); QuickSort(arr,fi+1,hi); } intmain() { intarr[100000],n; cout<<"请输入要排序的个数(您不能够超过100000个数字): "< cin>>n; for(inti=0;i { arr[i]=rand(); } FILETIMEbeg,end; GetSystemTimeAsFileTime(&beg); QuickSort(arr,0,n-1); GetSystemTimeAsFileTime(&end); for(inti=0;i cout< cout< cout<<"当输入"< "<<100*(end.dwLowDateTime-beg.dwLowDateTime)<<"us"< return0; } 随机快速排序源码C++实现 #include #include #include usingnamespacestd; voidRadomQuickSort(intarr[],intlo,inthi) { if(lo>=hi)return; intram=(int)(rand()%(hi-lo+1))+lo; intkey=arr[ram]; arr[ram]=arr[hi]; arr[hi]=key; intx=arr[hi]; inti=lo-1; for(intj=lo;j { if(x>=arr[j]) { i++; intt=arr[i]; arr[i]=arr[j]; arr[j]=t; } } intt=arr[i+1]; arr[i+1]=x; arr[hi]=t; RadomQuickSort(arr,lo,i); RadomQuickSort(arr,i+2,hi); } intmain() { intarr[100000],n; cout<<"请输入要排序的个数(您不能够超过100000个数字): "< cin>>n; for(inti=0;i { arr[i]=rand(); } FILETIMEbeg,end; GetSystemTimeAsFileTime(&beg); RadomQuickSort(arr,0,n-1); GetSystemTimeAsFileTime(&end); for(inti=0;i cout< cout< cout<<"当输入"< "<<100*(end.dwLowDateTime-beg.dwLowDateTime)<<"us"< return0; } 背包问题 1.问题描述: 0-1背包问题,部分背包问题 1)实现0-1背包的动态规划算法求解 给定N中物品和一个背包。 物品i的重量是Wi,其价值位Vi ,背包的容量为C。 问应该如何选择装入背包的物品,使得转入背包的物品的总价值为最大。 在选择物品的时候,对每种物品i只有两种选择,即装入背包或不装入背包。 不能讲物品i装入多次,也不能只装入物品的一部分。 因此,该问题被称为0-1背包问题。 2)实现部分背包的贪心算法求解 每一个物品都可以分割成单位块,单位块的利益越大显然总收益越大,所以它局部最优满足全局最优,可以用贪心法解答 2.算法原理: 2.10-1背包问题 令V(i,j)表示在前i(1<=i<=n)个物品中能够装入容量为就j(1<=j<=C)的背包中的物品的最大价值,则可以得到如下的动态规划函数: (1)V(i,0)=V(0,j)=0 (2)V(i,j)=V(i-1,j) j V(i,j)=max{V(i-1,j),V(i-1,j-wi)+vi)}j>wi (1)式表明: 如果第i个物品的重量大于背包的容量,则装人前i个物品得到的最大价值和装入前i-1个物品得到的最大价是相同的,即物品i不能装入背包。 (2)个式子表明: 如果第i个物品的重量小于背包的容量,则会有一下两种情况: (a)如果把第i个物品装入背包,则背包物品的价值等于第i-1个物品装入容量位j-wi 的背包中的价值加上第i个物品的价值vi; (b)如果第i个物品没有装入背包,则背包中物品价值就等于把前i-1个物品装入容量为j的背包中所取得的价值。 显然,取二者中价值最大的作为把前i个物品装入容量为j的背包中的最优解。 2.2部分背包问题 因为每一个物品都可以分割成单位块,单位块的利益越大显然总收益越大,所以它局部最优满足全局最优,可以用贪心法解答。 (1)先将单位块收益按从大到小进行排序; (2)初始化背包的剩余体积和当前价值; (3)从前到后考虑所有物品: a.如果可以完全放入,当前价值加上物品总价值,剩余体积减去物品总体积;b.如果可以部分放进,当前价值加上物品价值*剩余体积,使剩余体积为0. 3.实验数据 对于部分背包问题与0-1背包问题我们给定相同的物品情况与包的容量。 给定物品: [weight: 10value: 60][weight: 20value: 100][weight: 30value: 120] 给定包的容量: 50 4.实验截图 4.10-1背包问题 4.2部分背包问题 5.结果分析 5.1正确性分析 (1)0-1背包问题 因为物品不能拆分,所以对于只有50kg容量的背包可以放的物品,列出所有的情况为: [weight: 10value: 60][weight: 20value: 100]总价值为160 [weight: 10value: 60][weight: 30value: 120]总价值为180 [weight: 20value: 100][weight: 30value: 120]总价值为220 所有结果中,选取[weight: 20value: 100][weight: 30value: 120]时的总价值最大,为220.与我们用动态规划做出来的数据是一致的。 所以我们的算法正确。 (2)部分背包问题 物品可以拆分,所以首先选取单位价格最大的物品放入包中,在给出的物品中可知: [weight: 10value: 60]平均价值60 [weight: 20value: 100]平均价值50 [weight: 30value: 120]平均价值40 所以先放平均价值高的物品,将[weight: 10value: 60],[weight: 20value: 100]装进去以后,还能装20kg的[weight: 30value: 120]。 所以总的价值为240.与我们用贪心算法做出来的结果是一样的。 5.2时间复杂度 5.2.1动态规划法求解0-1背包的问题 主要的方法solve()。 如下图所示包含两重循环,totalWeight是指背包的总重量,n表示拥有物品的个数。 所以对于动态规划法求解0-1背包的问题的时间复杂度为O(Cn)与背包的容量和物品的个数有关,所以如果背包的重量很大的时候,用的时间会很大。 5.2.2贪心算法求解部分背包问题 在贪心算法中,需要时间最多的就是对平均价值量进行排序,用快速排序的方法时间复杂度为O(nlgn). 所以在时间上他比动态规划的时间要短。 速度会更快一点。 6实验代码: #include usingnamespacestd; #defineN7//物品的个数为N-1,6 #defineC16//背包的容量为C-1,15 intmax(intnumber1,intnumber2);//声明所需函数 intKSA(intw[],intv[]);//声明0/1背包问题算法 voidmain() { intv[N]={0,6,4,3,2,8}; intw[N]={0,2,3,6,2,4}; cout<<"背包容量为: "< cout<<"物品的价值分别是: "; for(intj=0;j<=5;j++) { cout<<""< } cout< cout<<"物品的重量分别是: "; for(inti=0;i<=5;i++) { cout<<""< } cout< cout<<"最大价值为: "; cout< system("pause"); } intmax(intnumber1,intnumber2)//所需函数max { if(number1>number2) returnnumber1; else returnnumber2; } intKSA(intw[],intv[])//0/1背包问题算法 { intV[N][C]; intx[N]; inti; intj; for(i=0;i<=N-1;i++)//初始化第0列 { V[i][0]=0; } for(j=0;j<=C-1;j++)//初始化第0行 { V[0][j]=0; } for(i=1;i<=N-1;i++)//计算第i行,进行第i次迭代 { for(j=1;j<=C-1;j++) { if(j V[i][j]=V[i-1][j]; else V[i][j]=max(V[i-1][j],V[i-1][j-w[i]]+v[i]); } } intk=C-1;//求装入背包的物品 for(i=N-1;i>0;i--) { if(V[i][k]>V[i-1][k]) { x[i]=1; k=k-w[i]; } else x[i]=0; } returnV[N-1][C-1];//返回背包取得的最大值 } 一个任务调度问题 1.问题描述: 在单处理器上具有期限和惩罚的单位时间任务调度问题 (1)实现这个问题的贪心算法 (2)将每个Wi替换为max{W1,W2,W3,…,Wn}-Wi,运行算法比较结果. 2.算法原理: 考虑一个给定的调度.我们说一个任务调度迟了,也就是说它在规定的时间之后完成;否则,这个任务在该调度中是早的.一个任意的调度总可以安排成早任务优先的形式,其中早的任务总是在迟的任务之前。 为了搞清这一点,请注意如果某个早任务a(i)跟在某个迟任务a(j)之后,就可以交换a(i)和a(j)的位置,并不影响a(i)是早的a(j)是迟的状态。 类似的,任意一个调度可以安排成一个规范形式,其中早的任务先于迟的任务,且按期限单调递增顺序对早任务进行调度。 为了做到这一点,将调度安排成早任务优先形式。 然而,只要在该调度中有两个分别完成于时间k和k+1的早任务a(i)和a(j)使得d(j) 如此,寻找最优调度问题就成为找一个由最优调度中早的任务构成的集合A的问题.一旦A被确定后,就可按期限的单调递增顺序列出A中的所有元素,从而给出实际的调度,然后按任意顺序列出迟的任务(S-A),就可以产生出最优调度的一个规范次序.称一个任务的集合A是独立的,如果存在关于A中任务的一个调度,使得没有一个任务是迟的.显然,某一调度中早任务的集合就构成一个独立的任务集 3.实验数据 输入: 没有输入,有一个结构体task,系统会随机生成task的期限和惩罚 输出: 分别输出随机生成task的集合后的早任务集合,迟任务惩罚以及将每个Wi替换为max{W1,W2,W3,…,Wn}-Wi后的早任务集合,迟任务惩罚. 输入任务包含截止日期、惩罚如下表所示: Ai 1 2 3 4 5 6 7 Di 4 2 4 3 1 4 6 Wi 70 60 50 40 30 20 10 表3-1 将每个Wi替换为max{W1,W2,W3,…,Wn}-Wi,数据变成了如下表格所示的数据: Ai 1 2 3 4 5 6 7 Di 4 2 4 3 1 4 6 Wi 0 10 20 30 40 50 60 表3-2 4.实验截图 运行结果如下图所示。 对于表3-1输入的数据,总惩罚为50,受惩罚的任务为编号为5,6的任务。 对于表3-2的任务数据,总的惩罚为10,受惩罚的任务为编号为1,2的任务 5.结果分析 可以看出将每个wi替换为max{W1,W2,W3,…,Wn}-Wi后的早任务集合基本上包括了没有替换时的早任务集合,并且替换后的迟任务惩罚大于没有替换时的迟任务惩罚。 6源代码 C#语言实现的 Task.cs publicclassTask: IComparable { publicintint_num{get;set;} publicintint_deadline{get;set;} publicintint_punish{get;set;} publicTask() { } publicTask(intnum,intdeadline,intpunish) { int_num=num; int_deadline=deadline; int_punish=punish; } publicintCompareTo(objectobj) { if(objisTask) { TasktempStudent=objasTask; returnthis.int_deadline.CompareTo(tempStudent.int_deadline); } thrownewNotImplementedException("obj is not a Task! "); } } Program.cs中主要代码 publicstaticvoidMain(string[]args) { Taska1=newTask(1,4,70); Taska2=newTask(2,2,60); Taska3=newTask(3,4,50); Taska4=newTask(4,3,40); Taska5=newTask(5,1,30); Taska6=newTask(6,4,20); Taska7=newTask(7,6,10); Task[]tasks=newTask[7]{a1,a2,a3,a4,a5,a6,a7}; TaskSchedule(tasks); Console.WriteLine(""); Console.WriteLine(""); Console.WriteLine("替换后: "); Task[]tasksnew=newTask[7]{a1,a2,a3,a4,a5,a6,a7}; intmax=tasksnew[0].int_punish; for(inti=1;i { if(tasksnew[i].int_punish>max) { max=tasksnew[i].int_punish; } } for(inti=0;i { tasksnew[i].int_punish=max-tasksnew[i].int_punish; } IEnumerable query=fromitemsintasksneworderbyitems.int_punishdescendingselectitems; Task[]tasklist=newTask[7]{null,null,null,null,null,null,null}; intindex=0; foreach(variteminquery) { tasklist[index]=itemasTask; index++; } TaskSchedule(tasklist); Console.ReadKey(); } privatestaticvoidTaskSchedule(Task[]tasks) { List List for(inti=0;i<7;i++) { lists.Add(tasks[i]); listscopy.Add(tasks[i]); //加进去之后对di进行排序 listscopy.Sort(); //判断di与是第几个元素的大小 for(intj=0;j { if(lis
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 中科大 软件 学院 算法 实验 报告