08计科2班王进 12号.docx
- 文档编号:4666946
- 上传时间:2022-12-07
- 格式:DOCX
- 页数:24
- 大小:88.11KB
08计科2班王进 12号.docx
《08计科2班王进 12号.docx》由会员分享,可在线阅读,更多相关《08计科2班王进 12号.docx(24页珍藏版)》请在冰豆网上搜索。
08计科2班王进12号
(上机实验报告)
姓名:
王进
班级:
08计科
(2)班
学号:
080104021112
指导老师:
秦明
完成时间:
2011年5月12日星期四
一.题目:
归并排序
二.算法介绍
归并排序采用的是分治法。
分治策略是将两个已排好序的集合归并成一个新的已排好序的集合。
归并排序分两步走:
1、划分元素。
2、归并。
这里是2路归并排序,即:
假设初始序列含有n个记录,这些记录可划分成n个有序的子序列,每个子序列的长度为1,然后两两归并,得到n/2个长度为2或1的有序子序列;再两两归并……如此重复,直至得到一个长度为n的有序序列为止。
即为2路归并排序。
三.程序流程图
开始
开始
intlow,mid,high
输入数据]
退出
Low 归并排序 meresort(intlow,inthing) N mid=(low+high)/2 mergsort(low,high) mergesort(mid+1,high) 打印排序结果 K=1,J[1]=1 Y 结束 meresort(intlow,inthing) K=1,J[1]=1 打印排序结果 K=1,J[1]=1 四.源程序及实验结果 #include #defineN10 voidmerge(inta[],intb[],intlow,intmid,inthigh) { inth,i,j,k; h=low,i=low,j=mid+1; while(h<=mid&&j<=high) { if(a[h]<=a[j]) { b[i]=a[h]; h++; } else { b[i]=a[j]; j++; } i++; } if(h>mid) { for(k=j;k<=high;k++) { b[i]=a[k]; i++; } } else { for(k=h;k<=mid;k++) { b[i]=a[k]; i++; } } for(k=low;k<=high;k++) { a[k]=b[k]; } for(inti=0;i<10;i++) { printf("%d",a[i]); } printf("\n\n"); } voidmergesort(inta[],intb[],intlow,inthigh) { intmid; if(low { mid=(low+high)/2; mergesort(a,b,low,mid); mergesort(a,b,mid+1,high); merge(a,b,low,mid,high); } } voidmain() { inta[N];//{310,285,179,652,351,423,861,254,450,520}; intb[N]; inti; printf("输入数组中待排序的数: \n"); for(i=0;i scanf("%d",&a[i]); printf("\n"); mergesort(a,b,0,9); } 结果截图 五.结果分析 实验采用二路归并的策越,先左子树后右子树,先将元素划分知道成最小的单元然后合并。 第一次归并[310,285]归并成了[285,310],第二次归并,[285,310,179]归并成了[179,285,310],直到形成最终的结果,左边归并好了归并右边这样就有了两个各含5个元素的已分好类的子集合,最后的归并得到分好类的结果 时间复杂度: n个元素进行归并排序,共需logn,每次所需比较关键字的次数不超过n,共比较O(nlogn)次。 每趟移动n个记录,共移动O(nlogn)个记录。 归并排序需要一个大小为n的辅助空间b[1..n]。 归并排序是稳定的。 一.题目: 快速排序 二、算法介绍 快速排序的分治策略每次确定每个元素在排好序后的数组的位置。 通过分支策略找到划分元素在排好序后的数组中应该出现的位置。 让后以这个找到的元素为划分点,分成左右两支,这样依次下去形成最终的结果。 三、程序流程图 开始 退出 N p > Y intv,i,temp v=a[m],i=m i=i+1 Y a[i] N p=p-1 Y a[p]>v N i Y temp=a[i] a[i]=a[p], a[p]=temp 结束 四、源程序及实验结果 #include #defineN9 voidparttion(inta[],intm,int*p) { intpoint,low,t; point=a[m]; low=m; while (1) { while(a[++low] while(a[--*p]>point); if(low>*p)break; else { t=a[low]; a[low]=a[*p]; a[*p]=t; } } a[m]=a[*p]; a[*p]=point; for(inti=0;i<9;i++) { printf("%d",a[i]); } printf("\n\n"); } voidquicksort(inta[],intp,intq) { intj; j=q+1; if(p { parttion(a,p,&j); quicksort(a,p,j-1); quicksort(a,j+1,q); } } voidmain() { inti; inta[N]; printf("输入数组中待排序的数: \n"); for(i=0;i scanf("%d",&a[i]); printf("\n"); quicksort(a,0,8); } 五、结果分析 划分元素由parttion(1,10)来找到,a[1]=65是划分元素,经过第一次划分最终确定他是此数组中的第5个元素,parttiond的功能是将这个划分元素放到了它在排序好后的数组中所在的正确位置,65前面的元素都比它小,65后面的元素都比它大。 然后将这个集合分成两个部分,也按照这样的策越,,当数组元素是序(顺序或逆序)的时候,是快速排序的最坏情况,时间复杂度为O( ),而平均情况时间是O(nlogn)。 快速排序是不稳定的。 一、题目: 背包问题 二、算法介绍 背包问题用到了贪心算法,贪心策略是按每一次装入的物品应使它占用的每一单位容量获得当前最大的单位效益。 这就需使物品的装入次序按Pi/Wi比值的非增次序来考虑。 在这种策略下的量度是已装入物品的累积效益值与所用容易之比。 其量度标准是每次装入要使累计效益值与所用容量的比值有最多的增加或最少的减少。 三、程序流程图 开始 输入p[N],w[N]并打印 初始化解向量x[i]=0(≦i≤n) 剩余容量cu=m 对物品单位容量的效益值排序 i=0 N 结束 i Y N Y i++ W[i]>cu + X[i]=1 cu=cu-w[i] x[i]=cu/m 四、源程序及实验结果 #include #defineN7//背包的个数 voidpackage(floatp[],floatw[],floatm,floatx[],intn) { inti,j; floatt,cu; for(i=0;i { for(j=i;j { if(p[i]*w[j] { t=p[i]; p[i]=p[j]; p[j]=t; t=w[i]; w[i]=w[j]; w[j]=t; } } } cu=m; for(i=0;i { if(w[i]>cu)break; x[i]=1; cu=cu-w[i]; } if(i } voidmain() { inti; floatm=15; floatx[7]={0}; floatp[7]; floatw[7]; printf("输入物品的效率值: \n"); for(i=0;i { scanf("%f",&p[i]);//各个背包单位容量的效益值 } printf("输入物品的重量: \n"); for(i=0;i { scanf("%f",&w[i]);//各个背包单位容量的效益值 } package(p,w,m,x,N); printf("输出解向量为: \n"); for(i=0;i { printf("x%d=%.5f",i,x[i]); } printf("\n"); } 五、结果分析 对输入的物品按单位容量的效益值按非增次序排好序,如图所示,然后按照排好序后的物品来考虑,首先选择重量w为1,p为6,接着选择重量w为2,p为10,依次选择,最终当选择到w=3时,只剩下了2个容量,即选择该物品的2/3。 通过与按容量非减和效益大小非增的两个为量度来比较,得到按照单位容量效益值非增的量度得到的是一个最优解。 一、题目: 带有期限的作业排序 二、算法介绍 目标函数为 为量度。 使用这一量度,下一个要计入的作业将是在满足所产生的J是一个可行解的限制条件下让 得到最大增加的作业。 这就要求按Pi的非增次序来考虑这些作业。 三、程序流程图 开始 输入p[n],d[n] n] d[0]=J[0]=0 k=1,j[1]=1 i=2 退出结束 N i<=n Y r=k d[j[r]]>d[i]&&d[J[r]]! =r N Y d[j[r]]<=d[i]&&d[J[r]]>r r=r-1 Y x=k i++ N x>=r+1 Y x-- J[x+1]=J[x] J[r+1]=i k++ 四、源程序及实验结果 #include voidjs(intd[],intj[],intn) { inti,j1,k,r; d[0]=j[0]=0; k=1; j[1]=1; for(i=2;i<=n;i++) { r=k; while(d[j[r]]>d[i]&&d[j[r]]! =r) { r=r-1; } if(d[j[r]]<=d[i]&&d[i]>r) { for(j1=k;j1>=r+1;j1--) { j[j1+1]=j[j1]; } j[r+1]=i; k++; } } } voidmain() { inti; intd[6]={0,2,2,1,3,3}; intj[6]={0}; js(d,j,5); for(i=1;i<=5&&j[i]! =0;i++) printf("j=j%d",j[i]); } 五、结果分析 输入了五个作业,将它们按照截止效益值非增次序排序,如图,先选择效益p为20,截止日期D[1]为2的作业,放到第一个任务处,然后选择p为15,D[2]为2的作业,先将D[2]与D[1]比较,发现相等,然后就将第一个作业移到第二个任务处,将第二个作业放到第一个作业处,第三个作业因为D[3]为1所以不能放到任务序列中,第四个作业,与第2个作业即D[2]比较后发现D[4]>D[2],即将该作业放到第三个任务处,对于第5个作业,它的D为3,而前面已经被别的作业占用了,所以它放不了任务序列中。 即作业的处理顺序为第1,2,4个作业依次处理。 一、题目: 单源点路径问题 二、算法介绍 对于单源点最短路径问题,首先是逐条构造这些最短路径,可以使用迄今已生成的所有路径长度之和作为一种量度,为了使这一量度达到最小,其单独的每一条路径都必须具有最小长度。 使用这一量度标准时,假定已经构造了i条最短路径,则下面要构造的路径应该是下一条最短的最小长度路径。 生成从V0到所有其它结点的最短路径的贪心方法就是按照路径长度的非降次序生成这些路径。 首先,生成一条到最近结点的最短路径;然后生成一条到第二近结点的最短路径。 三、程序流程图 开始 单源点最短路径 生成同图等价的邻接二维矩阵 输入源点 i=0 N i Y s[i]=0,dist[i]=COST[v][i] i=i+1 S[v]=1,dist[v]=0 i=0 N 打印结果 i Y i++ min=INFINITE u=v : j=0 N j j++ Y S[u]=1 S[j]==0&&DIST[j] N j=0 Y N j min=DIST[j] u=j Y j++ S[j]==0&&DIST[j] N Y DIST[j]=min+COST[u][j] 四、源程序及实验结果 #include intsearch(intt[],intn,intm,intd[]) { intk=t[n]; if(k==0) { printf("%d",d[m]); return(0); } else{ printf("v%d",search(t,k,m,d)+1); return(t[n]); } } voidshortpaths(intv,intcost[][7],intdist[],intn,bools[]) { intu,num,i,w; intfront[7]={0,0,0,0,0,0,0}; for(i=0;i { s[i]=0; dist[i]=cost[v][i]; } s[v]=1; dist[v]=0; for(num=1;num { intmin=10000; for(w=1;w { if(s[w]==0) { if(dist[w] { min=dist[w]; u=w; } } } s[u]=1; for(w=1;w { if(s[w]==0) { if(dist[w]>dist[u]+cost[u][w]) { dist[w]=dist[u]+cost[u][w]; front[w]=u; } } } } printf("路径值源结点到各结点的最短路径\n"); for(i=0;i<7;i++) { printf("v%d",search(front,i,i,dist)+1); printf("v%d\n",i+1); } } voidmain() { inti,j; intcost[7][7]= { {0,20,50,30,200,200,200}, {200,0,25,200,200,70,200}, {200,200,0,40,25,50,200}, {200,200,200,0,55,200,200}, {200,200,200,200,0,10,70}, {200,200,200,200,200,0,50}, {200,200,200,200,200,200,0} }; intfront[7]={0,0,0,0,0,0,0}; intdist[7]; bools[7]; printf("有向图的成本邻接矩阵\n"); for(i=0;i<7;i++) { for(j=0;j<7;j++) { printf("%d",cost[i][j]); } printf("\n"); } shortpaths(0,cost,dist,7,s); } 五、结果分析 由结果可知当从源点0出发去往其它结点均为最短路径,路径的长度即为此路径所经过的边的长度之和。 首先最初产生从0点到它自身的路径,这条路径没有边,其长度为0,.在贪心算法的每一步中,产生下一个最短路径。 考虑加入一条最短的边,再从所有这些边中先选择最短的。 可以验证按长度顺序产生最短路径时,下一条最短路径总是由一条已产生的最短路径加上一条边形成。 实际上,下一条最短路径总是由已产生的最短路径再扩充一条最短的边得到的,且这条路径所到达的顶点其最短路径还未产生。 例如第二条路径是第一条路径扩充一条边形成的;第三条路径则是第二条路径扩充一条边;第四条路径是第一条路径扩充一条边;第五条路径是第三条路径扩充一条边。 如此即得到最终结果。 该算法的时间复杂度为哦(n*n). 一、题目: 每对结点之间的最短路径 二、算法介绍 本次用到了动态规划,动态规划的要点是从决策序列中选取最优决策序列。 利用最优性原理,无论过程的初始状态是什么,其余的决策都必须相对于初始决策所产生的状态构成一个最优决策序列。 对于结点之间的最短路径问题,首先需要决策哪一个结点是该路径上具有最大编号的中间结点k,然后再去求取有i到k和由k到j这两对结点间的最短路径。 当然,这两条路径都不可能有比k-1还大的中间结点。 三、程序流程图 开始 给定等价邻接矩阵 将矩阵复制到二维数组中 k=1 k=k+1 i=1 i=i+1 j=1 j=j+1 A(i,j)=MIN(A(i,j),A(i,k)+A(k,j) N Y j Y i N Y k N 结束 四、源程序及实验结果 #include #defineMAX1000 #defineN3 voidmain() { intcost[3][3]={{0,4,11},{6,0,2},{3,MAX,0}}; intA[3][3]; inti,j,k; printf("成本矩阵如下: \n"); for(i=0;i<3;i++) { for(j=0;j<3;j++) { A[i][j]=cost[i][j]; } } for(k=0;k { for(i=0;i { for(j=0;j { if(A[i][j]>A[i][k]+A[k][j]) A[i][j]=A[i][k]+A[k][j]; } } for(i=0;i { for(j=0;j { printf("%d",A[i][j]); } printf("\n"); } printf("\n"); } } 五、结果分析 每对结点之间的最短路径问题是求满足下述条件的矩阵A,要求A中的任何元素A(i,j)是代表结点i到结点j的最短路径的长度。 考察G中一条由i到j的最路径,i≠j。 这条路径由i出发,通过一些中间结点,在j处结束。 如果k是这条最短路径上的一个中间结点,那么由i到k和由k到j的这两条子路径应分别是由i到k和由k到j的最短路径。 否则,这条由i到j的路径就不是具有最小长度的路径。 于是,最优性原理成立。 如果k是编号最高的中间结点,那么由i到k的这条最短路径上就不会有比编号k-1更大的结点通过。 同样,在k到j的那条最短路径上也不会有比编号k-1更大的结点通过。 因此,可以把求取一条由i到j的最短路径看成是如下的过程: 首先需要决策哪一个结点是该路径上具有最大编号的中间结点k,然后就再去求取由i到k和由k到j这两对结点之间的最短路径。 当然,这两条路径上都不可能有比k-1还大的中间结点。 总结心得体会: 本次算法分析过程是层层推进的过程,首先是分治策越,然后是贪心算法,在就是动态规划。 分治策越完成两个实验,一个是归并排序,然后是快速排序,归并是先划分然后反向归并。 它是个稳定的排序算法。 快速排序是先找到划分元素的位置把它放在正确的位置上,然后按这个元素划分成两部分,它是不稳定的算法,但都是一种递归算法策越。 贪心算法是完成的背包问题和带有限期限值的作业排序算法,贪心算法主要是贪心策越的选取,只有正确的选择最优策越才能求出最优解。 动态规划是个多阶段的决策过程,通过决策可以使得解的范围缩小。 算法上机实验,主要是用实践来证明理论的正确性。 算法设计的学习是很难的,上机也不是那么的容易。 好的算法,能够很好地解决一类问题。 同样的问题有不同的算法来解决。 像排序算法,有选择,冒泡,归并,快速等等。 好的方法不仅在时间复杂度上和空间复杂度上都能保持在较小的值,节省了资源。 一个算法题目的求解首先要分析,然后选择合理的算法,然后上机验证正确与否,也是个相当严谨的过程。 我开始只是抱着一种验证性的思想来完成实验,但是经过老师的点评,发现要学好算法,即必须严谨,数据要键盘输入,要符合大众的,不能抱着马马虎虎的思想来完成。 每一次的归并,每一次划分元素的查找都必须输出,这样才能使得结果有说服力,让人理解。 算法的时间复杂度要经过详尽的分析,只有深入的了解才能够明白她们的优劣所在。 总之,算法的学习确实对个人的编程能力有很多的帮助,它让人又一定方法去针对相应的问题。 要想学好算法必须思考,要上机,并且还要严谨。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 08计科2班王进 12号 08 班王进 12