算法设计与分析实验指导书.docx
《算法设计与分析实验指导书.docx》由会员分享,可在线阅读,更多相关《算法设计与分析实验指导书.docx(38页珍藏版)》请在冰豆网上搜索。
![算法设计与分析实验指导书.docx](https://file1.bdocx.com/fileroot1/2022-12/11/72f2166d-f2d4-4f7d-ae93-082aa5fdf256/72f2166d-f2d4-4f7d-ae93-082aa5fdf2561.gif)
算法设计与分析实验指导书
实验一、求最大公约数
一、实验内容:
(1)至少设计出3种版本的求最大公约数的算法;
(2)对所设计的算法采用大O符号进行时间复杂性分析;
(3)上机实现算法。
二、实验要求:
(1)掌握并应用算法的数学分析和后验分析方法;
(2)理解这样一个观点:
不同的算法能够解决相同的问题,这些算法的解题思路不同,复杂程度不同,解题效率也不同。
三、主要仪器设备
装有TC或VisualC++的PC机
四、实验步骤
算法分析
(1)连续整数检测
1.t=min{m,n}
2.m除以t,如果余数为0,则执行步骤3,否则,执行第4步;
3.n除以t,如果余数为0,返回t的值作为结果,否则执行第4步;
4.T=t-1,转第2步。
(2)欧几里得算法
1.r=m%n;
2.循环直到r=0;
2.1m=n;
2.2n=r;
2.3r=m%n;
3.输出n.
(3)分解质因数算法
1.将m分解质因数;
2.将n分解质因数;
3.提取m和n中的公共质因数;
4.将m和n中的公共质因数相乘,乘积作为结果输出
五、注意事项
(1)、将本实验上机调试、运行,注意调试过程中出现的问题;
(2)、结合运行结果,进行复杂性分析。
实验二、最近对问题
一、实验内容
按照按照蛮力法有关思想,写出相应的程序求解平面上的最近点对,并在计算机上调试成功,并分析其性能特征。
二、实验要求
结合学过的有关算法设计的基本知识,掌握蛮力算法;
理解蛮力算法的概念特征;
掌握其时间性能与空间性能及可能的改进方案。
三、主要仪器设备
装有TC或VisualC++的PC机
四、实验步骤
(1)算法分析
用分治算法求S中最接近点对的基本思想是:
选取一垂直线L∶x=m作为分割直线,将S的点分割为点数大致相同的2个子集S1和S2,使得:
S1={p∈S|p(x)≤m},S2={p∈S|p(x)>m}
其中:
m是S中各点x坐标的中位数,因此S1和S2中点数大致相同,且S=S1∪S2。
递归地在S1和S2上解最接近点对的问题,分别得到S1和S2中的最小距离d1和d2,并设d=min{d1,d2}。
用P1和P2分别表示在直线L左边和右边与其距离在d范围的点构成的两个垂直长条平面区域。
P1:
{p∈P1|(|m-x(p)|≤d)},P2:
{p∈P2|(|x(p)-m|≤d)}
S中的最接近点对的距离或者是d,或者是某个{p,q}点对的距离,其中p∈P1,q∈P2。
如果{p,q}是S中的最接近点对,则必有distance(p,q) 将上述描述简化如下:
(1)递归用L将节点集分成两个相等的部分;
(2)设d是d1和d2的最小值;
(3)删除离L超过d的节点;
(4)按照y维扫描剩下的节点,计算5个邻居的距离;
(5)如果距离小于d,更新d
下面我们分析分治算法的时间复杂度,由于步骤2-5是每个递归过程中都要去做的,我们先分析2-5。
步骤2时间复杂度为O
(1);步骤3时间复杂度为O(n);步骤4时间复杂度为O
(1);步骤5时间复杂度为O
(1),所以步骤2-5的时间复杂度为O(n)。
步骤1递归地将平面S中的点分成两个相等的部分时间复杂度为O(logn),所以总的时间复杂度为O(n)*O(logn)=O(nlogn)。
(2)参考代码
#include
#include
#include
#include
#include
usingnamespacestd;
constintN=100005;
constdoubleMAX=10e100;
constdoubleeps=0.00001;
typedefstructTYPE
{
doublex,y;
intindex;
}Point;
Pointa[N],b[N],c[N];
doubleclosest(Point*,Point*,Point*,int,int);
doubledis(Point,Point);
intcmp_x(constvoid*,constvoid*);
intcmp_y(constvoid*,constvoid*);
intmerge(Point*,Point*,int,int,int);
inlinedoublemin(double,double);
intmain()
{
intn,i;
doubled;
scanf("%d",&n);
while(n)
{
for(i=0;iscanf("%lf%lf",&(a[i].x),&(a[i].y));
qsort(a,n,sizeof(a[0]),cmp_x);
for(i=0;ia[i].index=i;
memcpy(b,a,n*sizeof(a[0]));
qsort(b,n,sizeof(b[0]),cmp_y);
d=closest(a,b,c,0,n-1);
printf("%.2lf\n",d);
scanf("%d",&n);
}
return0;
}
doubleclosest(Pointa[],Pointb[],Pointc[],intp,intq)
{
if(q-p==1)
returndis(a[p],a[q]);
if(q-p==2)
{
doublex1=dis(a[p],a[q]);
doublex2=dis(a[p+1],a[q]);
doublex3=dis(a[p],a[p+1]);
if(x1returnx1;
elseif(x2returnx2;
else
returnx3;
}
intm=(p+q)/2;
inti,j,k;
doubled1,d2;
for(i=p,j=p,k=m+1;i<=q;i++)
if(b[i].index<=m)
c[j++]=b[i];
//数组c左半部保存划分后左部的点,且对y是有序的.
else
c[k++]=b[i];
d1=closest(a,c,b,p,m);
d2=closest(a,c,b,m+1,q);
doubledm=min(d1,d2);
merge(b,c,p,m,q);//数组c左右部分分别是对y坐标有序的,将其合并到b.
for(i=p,k=p;i<=q;i++)
if(fabs(b[i].x-b[m].x)c[k++]=b[i];
//找出离划分基准左右不超过dm的部分,且仍然对y坐标有序.
for(i=p;ifor(j=i+1;j{
doubletemp=dis(c[i],c[j]);
if(tempdm=temp;
}returndm;
}
doubledis(Pointp,Pointq)
{
doublex1=p.x-q.x,y1=p.y-q.y;
returnsqrt(x1*x1+y1*y1);
}
intmerge(Pointp[],Pointq[],ints,intm,intt)
{
inti,j,k;
for(i=s,j=m+1,k=s;i<=m&&j<=t;)
{
if(q[i].y>q[j].y)
p[k++]=q[j],j++;
else
p[k++]=q[i],i++;
}
while(i<=m)
p[k++]=q[i++];
while(j<=t)
p[k++]=q[j++];
memcpy(q+s,p+s,(t-s+1)*sizeof(p[0]));
return0;
}
intcmp_x(constvoid*p,constvoid*q)
{
doubletemp=((Point*)p)->x-((Point*)q)->x;
if(temp>0)
return1;
elseif(fabs(temp)return0;
else
return-1;
}
intcmp_y(constvoid*p,constvoid*q)
{
doubletemp=((Point*)p)->y-((Point*)q)->y;
if(temp>0)
return1;
elseif(fabs(temp)return0;
else
return-1;
}
inlinedoublemin(doublep,doubleq)
{
return(p>q)?
(q):
(p);
}
五、注意事项
(1)、将本实验上机调试、运行,注意调试过程中出现的问题;
(2)、结合运行结果,进行复杂性分析。
实验三、快速排序算法
一、实验内容
利用快速排序算法编制程序对给定的一组数排序,并分析其性能。
二、实验要求
掌握分治法解决问题的策略;
学会使用分治法设计程序并能分析它。
三、主要仪器设备
装有TC或VisualC++的PC机
四、实验步骤
(1)算法分析
快速排序的基本思想是基于分治策略的。
对于输入的子序列L[p..r],如果规模足够小则直接进行排序,否则分三步处理:
分解(Divide):
将输入的序列L[p..r]划分成两个非空子序列L[p..q]和L[q+1..r],使L[p..q]中任一元素的值不大于L[q+1..r]中任一元素的值。
递归求解(Conquer):
通过递归调用快速排序算法分别对L[p..q]和L[q+1..r]进行排序。
合并(Merge):
由于对分解出的两个子序列的排序是就地进行的,所以在L[p..q]和L[q+1..r]都排好序后不需要执行任何计算L[p..r]就已排好序。
(2)参考代码
QSort(Sqlist&L,intlow,inthigh){
c=high-low;/*循环次数*/
if(c<10)直接调用插入排序法;/*小数时直接调用插入排序法*/
if(L.r[low].key>L.r[high].key)L.r[low]<->L.r[high];/*确保区间内第一个元素的值不大于区间内最后一个元素的值*/
ilow=low;/*小于区间内第一个元素的值数组边界下标*/
ihigh=high;/*大于区间内最后一个元素的值数组边界下标*/
for(i=low+1;iif(L.r[i].keyL.r[++ilow];/*小于区间内第一个元素的值放置ilow区间内*/
else
if(L.r[i].key>L.r[high].key){
L.r[i]<->L.r[--ihigh];/*大于区间内最后一个元素的值放置ihigh区间内*/
i--;/*下一个比较位置不变*/
c--;/*循环次数减一*/
}
}
L.r[ilow]<->L.r[low];/*将小于区间内第一个元素的边界下标元素与第一个元素互换*/
L.r[ihigh]<->L.r[high];/*将大于区间内最后一个元素的边界下标元素与最后一个元素互换*/
QSort(L,low,ilow-1);
QSort(L,ilow+1,ihigh-1);
QSort(L,ihigh+1,high);
}
voidQuickSort(Sqlist&L)
{
QSort(L,1,L.length);
}
五、注意事项
(1)、将本实验上机调试、运行,注意调试过程中出现的问题;
(2)、结合运行结果,进行复杂性分析。
实验四、最大子段和(分治法)
一、实验内容
编制程序求解如下问题:
给定由n个整数(可能有负整数)组成的序列(a1,a2,…,an),最大子段和问题要求该序列形如
的最大值(1<=i<=j<=n),当序列中所有整数均为负整数时,其最大子段和为0。
二、实验要求
进一步掌握递归算法的设计思想以及递归程序的调式技术;
理解这样一个观点,分治与递归经常同时应用在算法设计之中。
三、主要仪器设备
装有TC或VisualC++的PC机
四、实验步骤
(1)算法分析
首先判断输入的数组是不是一个元素。
如果是,则再看该元素是不是大于0.如果大于0,则问题的解为该元素的值,否则为0;如果输入的数组不是一个数,则求出其数组中间的元素下标。
递推对前半部分数组(low,center)和后半部分(center+1,high)求最大字段和.之后,设置一个左标记和一个右标记。
从数组中间向前边执行for语句。
在这个过程中,把当前元素加到左标记里面去。
同时判断左标记是不是大于左部分可能的字段和,如果大于,把左部分可能的字段和值设置为左标记的值。
对数组的右半部分做同样操作。
把右半部分的当前元素加到右标记里面去。
同时判断右标记是不是大于右部分可能的字段和,如果大于,把右部分可能的字段和值设置为右标记的值。
之后设置可能的问题解为左部分可能解和右部分可能解之和。
之后判断该可能解是不是大于该数组左边和右边的递推解。
如果前者没有后面2者的一个大。
则设置问题的最终解为最大者。
(2)参考代码
#include
#defineN10
intsubMaxSum(inta[],intlow,inthigh)/*quickSort*/
{
intsum=0;
inti;
if(low==high){
sum=a[low];
if(sum<0)
sum=0;
}
else{
intcenter=(low+high)/2;
ints1=0;
intleftsum=0;
intrightsum=0;
ints2=0;
leftsum=subMaxSum(a,low,center);
rightsum=subMaxSum(a,center+1,high);
for(i=center;i>=low;i--){
leftsum+=a[i];
if(leftsum>s1)s1=leftsum;
}
for(i=center+1;i<=high;i++){
rightsum+=a[i];
if(rightsum>s2)s2=leftsum;
}
sum=s1+s2;
if(sumif(sum}
returnsum;
}
intMaxSum(inta[],intn)
{
returnsubMaxSum(a,0,n-1);
}
voidmain(void){
inti,sum;
inttest[N];
for(i=0;iprintf("pleaseinputthe%dnumber:
",i+1);
scanf("%d",&test[i]);
printf("\n");}
printf("yourinputis:
");
for(i=0;iprintf("%d",test[i]);
printf("\n");
sum=MaxSum(test,N);
printf("themaxsumis:
%d\n",sum);
}
五、注意事项
(1)、将本实验上机调试、运行,注意调试过程中出现的问题;
(2)、结合运行结果,进行复杂性分析。
实验五、最长公共子序列问题
一、实验内容
利用动态规划算法编制程序求解下面的问题:
若给定序列X={x1,x2,…,xm},则另一序列Z={z1,z2,…,zk},是X的子序列是指存在一个严格递增下标序列{i1,i2,…,ik}使得对于所有j=1,2,…,k有:
zj=xij。
例如,序列Z={B,C,D,B}是序列X={A,B,C,B,D,A,B}的子序列,相应的递增下标序列为{2,3,5,7}。
给定2个序列X和Y,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列。
给定2个序列X={x1,x2,…,xm}和Y={y1,y2,…,yn},找出X和Y的最长公共子序列。
二、实验要求
熟悉最长公共子序列问题的算法;
初步掌握动态规划算法;
三、主要仪器设备
装有TC或VisualC++的PC机
四、实验步骤
(1)算法分析
最长公共子序列问题具有最优子结构性质。
设X={x1,...,xm},Y={y1,...,yn},及它们的最长子序列Z={z1,...,zk},则:
1、若xm=yn,则zk=xm=yn,且Z[k-1]是X[m-1]和Y[n-1]的最长公共子序列
2、若xm!
=yn,且zk!
=xm,则Z是X[m-1]和Y的最长公共子序列
3、若xm!
=yn,且zk!
=yn,则Z是Y[n-1]和X的最长公共子序列
由性质导出子问题的递归结构
当i=0,j=0时,c[i][j]=0
当i,j>0;xi=yi时,c[i][j]=c[i-1][j-1]+1
当i,j>0;xi!
=yi时,c[i][j]=max{c[i][j-1],c[i-1][j]}
(2)参考代码
#include"iostream.h"
#include"iomanip.h"
#definemax100
voidLCSLength(intm,intn,char*x,char*y,char*b)
{
inti,j,k;
intc[max][max];
for(i=1;i<=m;i++)
{
c[i][0]=0;
}
for(i=1;i<=n;i++)
{
c[0][i]=0;
}
for(i=1;i<=m;i++)
{
for(j=1;j<=n;j++)
{
if(x[i-1]==y[j-1])
{
c[i][j]=c[i-1][j-1]+1;
k=i*(n+1)+j;
b[k]='\\';
}
elseif(c[i-1][j]>=c[i][j-1])
{
c[i][j]=c[i-1][j];
k=i*(n+1)+j;
b[k]='|';
}
else
{
c[i][j]=c[i][j-1];
k=i*(n+1)+j;
b[k]='-';
}
}
}
}
voidLCS(inti,intj,char*x,char*b,intwidth)
{
if(i==0||j==0)
return;
intk=i*(width+1)+j;
if(b[k]=='\\')
{
LCS(i-1,j-1,x,b,width);
cout<}
elseif(b[k]=='|')
{
LCS(i-1,j,x,b,width);
}
else
{
LCS(i,j-1,x,b,width);
}
}
voidmain()
{charx[max]={'a','b','c','b','d','a','b'};
chary[max]={'b','d','c','a','b','a'};
intm=7;
intn=6;
charb[max]={0};
LCSLength(m,n,x,y,b);
LCS(m,n,x,b,n);
cout<五、注意事项
(1)、将本实验上机调试、运行,注意调试过程中出现的问题;
(2)、结合运行结果,进行复杂性分析。
实验六、最大子段和(动态规划)
一、实验内容
运用动态规划法编制一个程序求解实验3的最大字段和问题,并对这两种算法比较分析。
二、实验要求
深刻掌握动态规划法的设计思想并能熟悉运用;
理解这样一个观点,同样的问题可以用不同的方法解决,一个好的算法是返回努力和重新修正的结果。
三、主要仪器设备
装有TC或VisualC++的PC机
四、实验步骤
(1)算法分析
若记b[j]=max(a[i]+a[i+1]+..+a[j]),其中1<=i<=j,并且1<=j<=n。
则所求的最大子段和为maxb[j],1<=j<=n。
由b[j]的定义可易知,当b[j-1]>0时b[j]=b[j-1]+a[j],否则b[j]=a[j]。
故b[j]的动态规划递归式为:
b[j]=max(b[j-1]+a[j],a[j]),1<=j<=n。
据此,可设计出求最大子段和问题的动态规划算法。
(2)参考代码
intmaxSum(int[]a)
{intsum=0;
intb=0;
for(inti=0;i{if(b>0)b+=a[i];
elseb=a[i];
if(b>sum)sum=b;}
returnsum;}
五、注意事项
(1)、将本实验上机调试、运行,注意调试过程中出现的问题;
(2)、结合运行结果,进行复杂性分析。
实验七、哈夫曼编码
一、实验内容
运用贪心法编制程序求解如下问题:
设需要编码的字符集为{d1,d2,…dn},它们出现的频率为{w1,w2,…wn},应用哈夫曼树构造最短的不等长编码方案。
二、实验要求
了解前缀