算法设计与分析实验报告文档格式.docx
- 文档编号:21401930
- 上传时间:2023-01-30
- 格式:DOCX
- 页数:23
- 大小:580.71KB
算法设计与分析实验报告文档格式.docx
《算法设计与分析实验报告文档格式.docx》由会员分享,可在线阅读,更多相关《算法设计与分析实验报告文档格式.docx(23页珍藏版)》请在冰豆网上搜索。
实验二:
voidQuickSort(intr[],intfirst,intend){
if(first<
end){
pivot=Partition(r,first,end);
//问题分解,pivot是轴值在序列中的位置
QuickSort(r,first,pivot-1);
//递归地对左侧子序列进行快速排序
QuickSort(r,pivot+1,end);
//递归地对右侧子序列进行快速排序
}
}
Partition(intr[],intfirst,intend){
取一个first和end间的记录pivot为基准;
i=first;
j=end;
分别用来指示将要与基准记录进行比较的左侧记录位置和右侧记录位置;
while(i和j不指向一个地方){
右侧扫描过程:
while(array[pivot]<
array[j]&
&
i<
j)j--;
if(array[pivot]>
array[j])将pivot与j指向的记录交换;
左侧扫描过程:
while(array[pivot]>
array[i]&
j)i++;
if(array[pivot]<
array[i])将pivot与i指向的记录交换;
返回pivot的值;
第二部分:
实验调试过程
这里假设的数组是已经按升序排列好的,从而大大降低了难度。
该程序并不是很复杂,因此编程过程中并没有出现什么问题,主要的思想就是查找处于中间的元素,若它不是,则将它左右分为两部分,继续查找中间的一个数,循环下去,用递归就可以解决了。
输入的几组测试数据都有了意料中的正确结果。
由于这里该快速排序中不能使用递归,这个地方难住了很久。
最开始一直想着用while在主函数中反复调用,可是发现不能解决每次调用一次要解决的数组就要加倍的问题,最后才想到用两个函数来互相调用来避免递归的同时模仿它的功能,才解决了这个问题。
同样,这里的输出结果并不复杂,在算法问题解决了以后,不需要过多的调试,输入的几组测试数据都有了意料中的正确结果。
需要注意的是,这里的数据输入不能用空格间隔这样一次性输入许多数据,只能一个一个的输入,否则输出结果会出现错误,但不影响最后排序的结果。
第三部分:
实验结果分析(可加页)
实验一结果:
1.当找到所要寻找的数字时,输出找到所要寻找的数据:
这里的数据包括1到100的所有数字,55在这个序列中。
2.当没找到所要寻找的数字时,输出该数据并不存在于数据库中:
0并不存在于这个序列中。
一、时间复杂性分析:
1.最好情况下:
这里的最好情况,即为第一次查找就找到了要找的数据,故时间复杂性为O
(1)。
2.最坏情况下:
这里的最坏情况意味着要将所有数据都找一遍最后才能找到要查找的数据,随着数据库的增大,查找次数会随之增长,故其时间复杂度为O(n)。
3.平均情况下:
这种情况考虑了数据时等概率的分布于数据库中。
ASL=
折半查找的时间复杂性为O(
)。
二、空间复杂度分析:
这里查找的过程中并不需要额外的空间,只需要存放数据的空间,故空间复杂度为O(n),n为数组的大小。
三、算法功能:
其功能主要是用来查找数据,若对它进行一下拓展,可以由自主确定数据库,并可对他进行操作;
这里的数据也可以不只是包括整数。
实验二结果:
1.当数组的容量不大于0时,显示错误:
2.当输入数据错误时,显示错误:
3.当输入正确时的显示结果:
T(n)≤2T(n/2)+n≤2(2T(n/4)+n/2)+n=4T(n/4)+2n≤4(2T(n/8)+n/4)+2n=8T(n/8)+3n………≤nT
(1)+nlog2n=O(nlog2n)
因此,时间复杂度为O(nlog2n)。
待排序记录序列正序或逆序,每次划分只得到一个比上一次划分少一个记录的子序列(另一个子序列为空)。
此时,必须经过n-1次递归调用才能把所有记录定位,而且第i趟划分需要经过n-i次关键码的比较才能找到第i个记录的基准位置,因此,总的比较次数为:
因此,时间复杂度为O(n2)。
数量级也为O(nlog2n)
由于这里的排序过程中并不需要额外的空间,只需要存放数据的空间来在其中对数据进行交换,故空间复杂度为O(n),n为需要排序的数据的容量。
该算法主要用来对数据进行排序,这里只支持升序的整数排列,拓展一下应当可以支持任意排列条件和排列数据类型。
实验小结、建议及体会
在这次的实验中,主要学习了分治法,它将一个难以直接解决的大问题,划分成一些规模较小的子问题,以便各个击破,分而治之。
更一般地说,将要求解的原问题划分成k个较小规模的子问题,对这k个子问题分别求解。
如果子问题的规模仍然不够小,则再将每个子问题划分为k个规模更小的子问题,如此分解下去,直到问题规模足够小,很容易求出其解为止,再将子问题的解合并为一个更大规模的问题的解,自底向上逐步求出原问题的解。
由于第二个问题中禁止使用递归的使用,这里使用两个函数来互相调用来避免,在最后的查资料中发现这也是一种间接的递归调用。
正确的方法应该是使用堆栈来解决问题。
用栈保存每一个待排序子串的首尾元素下标,下一次while循环时取出这个范围,对这段子序列进行partition操作。
这里我并没有具体来实现这个方法。
这次实验中实现了分治法的一些具体例子,体会到我还缺的一些知识,比如堆栈上的知识,应当对这方面加以学习。
附录
#include<
iostream.h>
inta[100];
intnumber,Found;
//寻找要找的数字
voidsearch(inti,intj){
ints=(int)(i+j)/2;
if(number!
=a[s]&
Found==0){//当中间的数不是并且结果还未找到时
if(i<
=s-1&
number<
a[s])//将数组分为两半,尾变为中间数字的编号
search(i,s-1);
elseif(s+1<
=j&
number>
a[s])//将数组分为两半,头变为中间数字的编号
search(s+1,j);
else{
Found=1;
voidmain(){
Found=0;
//标记是否已找到数字
for(inti=0;
100;
i++){
a[i]=i+1;
}//这里的数组默认为1到100的数列,升序排列
cout<
<
"
Pleaseinputthenumber:
;
cin>
>
number;
if(number<
a[0]||number>
a[99]){//当这个数不在数组的范围内时
cout<
Thenumberdoesn'
texistinthearray!
\n"
search(0,99);
if(Found=0)
cout<
elsecout<
Thenumberexistsinthearray!
intarray[100];
voidSort(int,int,int);
intPartition(intfirst,intend){
inti,j,t;
i=first;
j=end;
//初始化
while(i<
j){
while(i<
j&
array[i]<
=array[j])
j--;
//右侧扫描
if(i<
j){//将较小记录交换到前面
t=array[i];
array[i]=array[j];
array[j]=t;
i++;
}
=array[j])//左侧扫描
j){//将较大记录交换到后面
}}
returni;
//i为轴值记录的最终位置
voidQuickSort(intfirst,intend){
intpivot;
end){
pivot=Partition(first,end);
//问题分解,pivot是轴值在序列中的位置}
Sort(first,end,pivot);
voidSort(intfirst,intend,intpivot){
if(first<
pivot-1)QuickSort(first,pivot-1);
if(pivot+1<
end)QuickSort(pivot+1,end);
inti,capacity;
请输入数组的容量:
capacity;
请输入需要排序的数组:
for(i=0;
i++)
array[i]=-1;
cin>
array[i];
//将要排序的数据输入
if(array[i]<
0){
i--;
该数据不合法,请重新输入"
if(capacity<
=0)
数据库为空!
else{QuickSort(0,capacity-1);
for(i=0;
array[i]<
"
算法设计与分析
动态规划算法应用及设计
田益秋子
一.实验内容描述(问题域描述)
1.实验描述:
将动态规划算法应用于货郎担问题和工程中的资金分配问题的求解,设计出高效的算法。
本实验是综合型、设计型实验,在实验中需要综合运用《离散数学》中的数理逻辑、图;
《数据结构》中的集合、队列、树;
《程序设计》中的数组、条件控制、循环控制、指针、结构体和《算法设计与分析》中的动态规划算法、多段图、以及计算时间的渐进表示和算法的时间复杂性分析等等方面的知识。
2.实验内容:
1)利用动态规划思想,求货郎担问题,并利用任何一种语言,在计算机上实现,同时进行时间复杂性分析。
2)已知资金总数为a(万元),工程数n,以及利润值g(i,j)(表示对工程i投资j万元所获得的利润,其中
,且j只取整数),试用动态规划方法求出如何分配资金才能使获得的利润最大(资金的分配以万元为单位)。
首先要对实验内容进行描述,用SPARK语言设计算法,然后C/C++或JAVA语编写程序对算法实现,同时用具用代表性的数据(给3组典型输入数据)进行测试,实验后,进行实验总结,描述设计过程步骤及各步骤含义。
1.for(i=1;
i<
n;
i++)//初始化第0列
d[i][0]=c[i][0];
2.for(j=1;
j<
2n-1-1;
j++)
for(i=1;
i++)//依次进行第i次迭代
if(子集V[j]中不包含i)//c[n][n]代表元素之间的代价
对V[j]中的每个元素k,计算d[i][j]=min(c[i][k]+d[k][j-1]);
3.对V[2n-1-1]中的每一个元素k,计算d[0][2n-1-1]=min(c[0][k]+d[k][2n-1-2]);
4.输出最短路径长度d[0][2n-1-1];
i或是j=0时:
table[i][j]=0;
i和j不等于0时:
table[i][j]=max{table[i-1][j],table[i-1][j-1]+g[i-1][1],table[i-1][j-2]+g[i-1][2],table[i-1][j-3]+g[i-1][3],.........,table[i-1][0]+g[i-1][j]}。
最后得出动态决策表
实验一第一次运行时出现以下问题,结果输出不正确。
在程序中添加计算并存储每个数字的二进制表示同时将其输出的代码来检测程序的错误:
printf("
%d的二进制表示为:
i);
for(k=0;
k<
6;
k++)printf("
%d"
array[i][k]);
printf("
);
运行结果为:
显示结果的错误从这个时候就存在了,二进制表示错误。
发现错误,在输出时,边界条件设置错误为看k<
6,这里应该为k<
n。
这时并没有根本解决问题,最后的结果依然同以上截图相同,只是二进制表示后的负数没有了。
这里的二进制表示依然是错误的。
发现错误,这里的initial(用来作为已经加上的值,以此为基础看以后的二进制位中是否还有1)的值并没有随计算过程而减少,添加上语句initial+=pow(2,j),二进制表示显示正确。
现在检查最后一段程序,该段只要功能为判断是否有该元素:
在程序后添加程序段,for(i=0;
i++){for(j=0;
j<
m;
j++)printf("
%d"
Distance[i][j]);
可以看出Distance数组中几乎所有的元素都溢出了。
检查出来是为未初始化造成的。
实验二中的过程比较简单,课件中已经给出了比较详细的算法,因此编写过程中并没有出现什么大的问题,只有一些小的书写方面和终止条件考虑不当的错误。
在最后的结果中,发现每当工程数大于资金数时,就会出现以下结果:
收入的总资金一直为负,而工程i的投入资金都显示正确,检查总资金total的求值过程,在最后可以看出,由于表中并没有投入资金为0时,并没有收入,这里出现错误,在求total的过程中应当排除中这种情况,添加语句以下语句,结果正确,错误被更正。
if(result[i]>
0)total+=profit[i][result[i]-1];
在这里,还有一个常见的错误,就是忘记输入时在变量前面加上符号&
,使程序出现中断。
1.下组数据是书上的一组例题,运行结果显示正确,给出了最短路径和路径长度。
2.在上个输入的基础上,将结点之间的代价反过来,即i->
j的代价与j->
i的代价互换后,依然以1结点作为开始,路程反过来,由下图可示,输出结果正确。
3.该组数据也是书上的,但是开始的结点处不同。
给出了最短路径和路径长度。
由于这里涉及到填表,这里的复杂性只与数组的大小有关,因此没有情况好坏的差别,故这里考虑平均情况下,算法的时间复杂性为O(2n)。
和蛮力法相比,动态规划法求解TSP问题,把原来的时间复杂性是O(n!
)的排列问题,转化为组合问题,从而降低了算法的时间复杂性,但它仍需要指数时间。
这里的填表的过程需要的空间与数据的个数有关即为n,这里的Distance数组的纵坐标为0~2n-1,故空间的复杂度为O(2n)。
该算法的功能只要是解决JSP问题,寻找要从某地出发,途径所有的结点最后回到出发地所需的最小代价和路程,这个算法的计算过程就是通过将所有下个可能的结点的代价算出来求出最小值来填表。
1.工程数比资金少的情况下,运行结果为:
2.工程与资金相同的情况下,运行结果下:
3.工程比资金多的情况下,运行结果如下:
可以看出以上结果均正确。
动态规划递推关系式:
V(i,0)=V(0,j)=0
平均情况下:
在该段程序中,for循环嵌套最多的是对决策表进行赋值的时候,里面包含三个for循环,运行次数为N*A*A!
,因此时间复杂度为O(n!
该程序不需要临时存储空间,这里他的数据全部存在定义的几个数组中,可以看出空间复杂度为0(N*A)。
该算法主要表达的是填动态规划表的方法,通过不断填表来满足后续数据的求解。
实验一中,我感觉我用的方法太复杂了,在其中使用了许多的for、while循环和ifelse条件判断,而且在编写的过程中花费了很多的时间,感觉有些并不理解自己写的东西,再者就是有时写着写着就不知道写到哪儿了。
这反映了我的一个问题,对程序没有事先考虑好以及没有理解好,这样写起来就很不顺利。
对递归的掌握也不是很好,但是在编写这个程序的过程中,对动态规划法确实有了一些深的理解,还是要多动手,使程序的可读性提高。
至于实验二,就是一个变相0/1的背包问题。
最开始对题目的理解出现了偏差,使问题复杂化了,解决这个地方也花了不少时间,还是应该多请教他人,不能固执地钻牛角尖。
stdio.h>
math.h>
intm,n,time=0,Distance[6][64],start,routine[7],distance[6][6],number[64],array[64][6];
intfindCompare(inti,intj,intk){//找到当要分解一个Distance[][]时,求的对应一个distance[][]的Distance[][]的纵坐标
intx=0,y,initial=0;
while(number[x]!
=number[j]-1)x++;
while(initial==0){
y=0;
for(intl=0;
l<
l++){
if(array[x][l]==array[j][l]||l==k)
y++;
if(y==n)initial=1;
elsex++;
return(x);
voidgetRoutine(inti,intj,intinitial){//确定得到最小路径值的路径
intk,x;
switch(initial){
case0:
k=1;
while(distance[0][k]+Distance[k][m-k-1]!
=Distance[i][j]&
k<
n)k++;
if(k+1!
=start)
routine[1]=k+1;
elseroutine[1]=1;
i=k;
j=m-k-1;
case1:
time++;
for(k=0;
n-1;
k++){
if(array[j][k]==1){
x=findCompare(i,j,k);
if(Distance[i][j]==distance[i][k+1]+Distance[k+1][x]){
if(k+1!
routine[time+1]=k+2;
//time=1,k=1
elseroutine[time+1]=1;
}
if(time+1<
n){
routine[n-1]=1;
getRoutine(k+1,x,1);
if(time==n-1){
j=0;
for(i=1;
=n;
j+=i;
for(i=0;
j=j-routine[i];
routine[n-1]=j;
intinitial,x,i,j,t,k;
请输入结点个数:
scanf("
&
n);
m=pow(2,n)/2;
请依次输入结点之间的代价(以矩阵的形式输入,本结点之间的代价写0):
printf("
routine[i]=0;
for(j=0;
j++)
scanf("
distance[i][j]);
请输入想作为开始的结点编号(从1开始):
start);
routine[n]=start;
routine[0]=start;
i++){//将作为开始的结点移到第一个位置
t=distance[0][i];
distance[0][i]=distance[start-1][i];
distance[start-1][i]=t;
for(j=0;
j++){
t=distance[j][0];
dista
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 算法 设计 分析 实验 报告