中南大学算法实验报告.docx

上传人:b****6 文档编号:7333427 上传时间:2023-01-23 格式:DOCX 页数:19 大小:271.31KB
下载 相关 举报
中南大学算法实验报告.docx_第1页
第1页 / 共19页
中南大学算法实验报告.docx_第2页
第2页 / 共19页
中南大学算法实验报告.docx_第3页
第3页 / 共19页
中南大学算法实验报告.docx_第4页
第4页 / 共19页
中南大学算法实验报告.docx_第5页
第5页 / 共19页
点击查看更多>>
下载资源
资源描述

中南大学算法实验报告.docx

《中南大学算法实验报告.docx》由会员分享,可在线阅读,更多相关《中南大学算法实验报告.docx(19页珍藏版)》请在冰豆网上搜索。

中南大学算法实验报告.docx

中南大学算法实验报告

中南大学

算法分析与设计实验报告

 

班级:

物联网****班

学号:

******

姓名:

***

指导老师:

沙莎

2012年12月28日

目录

 

分治法实验

1.快速排序……………………………………………………2

2.归并排序………………………………………………………4

3.最大最小值……………………………………………………7

动态规划实验

多段图……………………………………………………………10

回溯法实验

N皇后……………………………………………………………15

 

分治法实验

分治法的基本思想是将一个规模为n的问题分解为k个规模较小的子问题,这些子问题互相独立且与原问题相同。

递归地求解这些子问题,然后将各子问题的解合并得到原问题的解。

1.快速排序

快速排序是基于分治策略的一个排序算法实现快速排序的分治过程如下:

分解:

数组A[p..r]被划分为两个(可能空)子数组A[p..q-1]和A[q+1..r],使得A[p..q-1]中的每个元素都小于等于A(q),而且,小于等于A[q+1..r]中的元素。

下标q也在这个划分过程中进行计算。

解决:

通过递归调用快速排序,对子数组A[p..q-1]和A[q+1..r]排序

合并:

因为两个子数组是就地排序的,将它们的合并不需要操作,整个数组

A[p..r]已排序。

实验代码如下:

#include

usingnamespacestd;

intnum;

voidswap(int&a,int&b)

{

inttemp=a;

a=b;

b=temp;

}//交换元素位置

voidPrintArray(int*arr)

{

for(inti=1;i<=num;++i)

cout<

cout<

}

intPartition1(int*arr,intp,intr)

{

intx=arr[r];

inti=p-1;

intj;

for(j=p;j<=r-1;j++)

{

if(arr[j]<=x)

{i=i+1;

swap(arr[i],arr[j]);

}

}

swap(arr[i+1],arr[r]);

returni+1;

}//对子数组A[p..r]进行就地重排

voidQuickSort(int*arr,intp,intr)

{

if(p

{

intq=Partition1(arr,p,r);

QuickSort(arr,p,q-1);

QuickSort(arr,q+1,r);

}

}//该过程实现快速排序

intmain()

{

intarr[100];

cout<<"请输入元素个数:

\n";

cin>>num;

cout<<"请输入元素大小:

\n";

for(inti=1;i<=num;++i)

cin>>arr[i];

QuickSort(arr,1,num);

cout<<"最后结果:

";

PrintArray(arr);

return0;

}

运行结果如下图所示:

实验收获与体会:

通过证明可以得到该算法在最坏情况下的时间复杂性为T(n)=O(n^2),平均情况下的时间复杂性是O(nlogn),通过该实验对分治法基本思想有了了解。

2.归并排序:

基本操作如下:

分解:

将n个元素分成各含n/2个元素的子序列

解决:

用合并排序法对两个子序列递归地排序

合并:

合并两个已排好序的子序列得到排序结果

在对子序列排序时,其长度为1时递归结束。

单个元素被视为是已排好序的。

实验代码如下:

#include

#include

template

voidMerge(Tc[],Td[],intl,intm,intr)

{//把c[l:

m]和c[m:

r]归并到d[l:

r]

inti,j,k;

i=l;//第一段游标

j=m+1;//第二段游标

k=l;//结束游标

while((i<=m)&&(j<=r))

if(c[i]<=c[j])

d[k++]=c[i++];

elsed[k++]=c[j++];

if(i>m)for(intq=j;q<=r;q++)

d[k++]=c[q];

elsefor(intq=i;q<=m;q++)

d[k++]=c[q];

}

template

voidMergePass(Tx[],Ty[],ints,intn){

//归并大小为s的相邻的段

inti=0;

while(i<=n-2*s){

//归并两个大小为s的相邻段

Merge(x,y,i,i+s-1,n-1);

i=i+2*s;

}

//剩下不足两个元素

if(i+s

elsefor(intj=i;j<=n-1;j++)

//把最后一段复制到y

y[j]=x[j];

}

template

voidMergeSort(Ta[],intn)

{T*b=newT[n];

ints=1;

while(s

MergePass(a,b,s,n);

s+=s;

MergePass(b,a,s,n);

s+=s;

}

}

intmain()

{

intn,i,j=0;

double*Input;

cout<<"请输入您要排序的元素个数"<

cin>>n;

Input=newdouble[100000];//定义排序数组

cout<<"请输入您要排序的元素:

"<

for(i=0;i

cin>>*(Input+i);

MergeSort(Input,n);//调用排序函数

cout<<"排序后的数组元素为:

"<

for(i=0;i

{

cout<

j++;

if(j%10==0)

cout<

}

delete[]Input;//释放内存;

}

 

运行结果如下图所示:

实验收获与体会:

通过归并排序的实验对分治法在排序中的应用有了更深刻的了解,与快速排序对比,归并排序相对较“稳定”些。

 

3.最大最小值问题:

每次将问题分成大致相等的两部分,分别在这两部分中找出最大值与最小值,再将这两个子问题的解组合成原问题的解,就可得到该问题的分治算法。

算法描述:

procedureMAXMIN(i,j,fmax,fmin)

globaln,A[1:

n]

case

{i=j:

fmax←fmin←A[i]/*只有一个元素*/

i=j-1:

ifA[i]

fmax←A[j];fmin←A[i]

elsefmax←A[i];fmin←A[j]

else:

mid←(i+j)/2/*分成两部分*/

MAXMIN(i,mid,max1,min1)

MAXMIN(mid+1,j,max2,min2)

fmax←max(max1,max2)

fmin←min(min1,min2)

}

如果MAX1和MIN1是I1中的最大和最小元素,MAX2和MIN2是I2中的最大和最小元素,MAX1和MAX2中的大者就是I中的最大元素MAX,MIN1和MIN2中的小者是I中的最小元素MIN。

如果I只包含一个元素,则不需要作任何分割直接就可得到其解。

实验代码如下:

#include"stdio.h"

#defineN100

voidmaxmin2(intA[],inti,intj,int*max,int*min)

{

intmid,max1,max2,min1,min2;

if(j==i)

{*max=*min=A[i]=A[j];

return;

}

if(j-1==i)

{

if(A[i]>A[j])

{

*max=A[i];

*min=A[j];

}

else

{

*max=A[j];

*min=A[i];

}

return;

}

mid=(i+j)/2;

maxmin2(A,mid+1,j,&max2,&min2);

maxmin2(A,i,mid,&max1,&min1);

if(max1>max2)

*max=max1;

else

*max=max2;

if(min1>min2)

*min=min2;

else

*min=min1;

}

main()

{

inti,n;

intA[N];

intmax,min;

printf("请输入要比较的数据的个数:

");

scanf("%d",&n);

for(i=0;i

{

printf("请输入第%d个数",i+1);

scanf("%d",&A[i]);

}

maxmin2(A,0,n-1,&max,&min);

printf("最大值为:

%d最小值为:

%d",max,min);

}

运行结果如下图所示:

实验收获与体会:

通过该实验对分治法掌握的更加透彻,明白了分治法发挥的作用。

动态规划实验

对于一个多阶段过程问题,是否可以分段实现最优决策,信赖于该问题是否有最优子结构性质,能否采用动态规划的方法,还要看该问题的子问题是否具有重叠性质。

最优子结构性质:

原问题的最优解包含了其子问题的最优解

子问题的重叠性质:

每次产生的子问题并不总是新问题,有些子问题被反复计算多次。

问题的最优子结构性质和子问题重叠性质是采用动态规划算法的两个基本要素

动态规划一般方法

1.找出最优解的性质,并刻画其结构特征

2.递归地定义最优值(写出动态规划方程)

3.以自底向上的方式计算出最优值

多段图

多段图算法:

ProcedureFGRAPH(E,k,n,P)

//输入是按段的顺序给结点编号的,有n个结点的k段图。

E是边集,c(i,j)是边的成本。

P(1:

k)是最小成本路径。

//

realCOST(n),integer(n-1),P(k),r,j,k,n

COST(n)<-0

forj<-n-1to1by-1do//计算COST(j)//

设r是一个这样的结点,(j,r)

E且使c(j,r)+COST(r)取最小值

COST(j)<-c(j,r)+COST(r);D(j)<-r;Repeat//向前对j-1进行决策//

P

(1)<-1;P(k)<-n;

forj<-2tok-1do//找路径上的第j个节点//

P(j)<-D(P(j-1));repeat;

endFGRAPH

实验代码如下:

#include

usingnamespacestd;

#defineMAX100

#definen12//图的总顶点数

#definek5//图的段数

intc[n][n];

voidinit(intcost[])//初始化图

{

inti,j;

for(i=0;i<13;i++)

{

for(j=0;j<13;j++)

{

c[i][j]=MAX;//初始化每条边长度为MAX

}

}

c[1][2]=9;c[1][3]=7;c[1][4]=3;c[1][5]=2;c[2][6]=4;c[2][7]=2;c[2][8]=1;

c[3][6]=2;c[3][7]=7;c[4][8]=11;c[5][7]=11;c[5][8]=8;c[6][9]=6;c[6][10]=5;

c[7][9]=4;c[7][10]=3;c[8][10]=5;c[8][11]=6;c[9][12]=4;c[10][12]=2;c[11][12]=5;

//给每条边赋值

}

voidfront(intcost[],intpath[],intd[])//向前递推算法求多段图的最短路径

{

intr,j,temp,min;

for(j=0;j<=n;j++)

cost[j]=0;

for(j=n-1;j>=1;j--)

{

temp=0;

min=c[j][temp]+cost[temp];//初始化当前路径长度的最小值

for(r=0;r<=n;r++)

{

if(c[j][r]!

=MAX)

{

if((c[j][r]+cost[r])

{

min=c[j][r]+cost[r];

temp=r;

}

}

}

cost[j]=c[j][temp]+cost[temp];

d[j]=temp;

}//向前对j-1进行决策

path[1]=1;//第一段所取节点

path[k]=n;//最后一段所取节点

for(j=2;j

path[j]=d[path[j-1]];//找到路径上第j个节点

}

voidback(intbcost[],intpath1[],intd[])//使用向后递推算法求多段图的最短路径

{

intr,j,temp,min;

for(j=0;j<=n;j++)

bcost[j]=0;

for(j=2;j<=n;j++)

{

temp=12;

min=c[temp][j]+bcost[temp];//初始化当前路径长度最小值

for(r=0;r<=n;r++)

{

if(c[r][j]!

=MAX)

{

if((c[r][j]+bcost[r])

{

min=c[r][j]+bcost[r];

temp=r;

}

}

}

bcost[j]=c[temp][j]+bcost[temp];

d[j]=temp;

}

path1[1]=1;

path1[k]=n;

for(inti=4;i>=2;i--)

{

path1[i]=d[path1[i+1]];

}//找出各段的节点

}

intmain()

{

intcur=-1;

intj;

intcost[13],d[12],bcost[13];

intpath[k];

intpath1[k];

cout<<"\t\t\t\t多段图问题"<

cout<<"\n\n";

init(cost);

front(cost,path,d);

cout<<"向前递推算法求得的最短路径:

\n\n";

for(inti=1;i<=5;i++)

{

if(i==5)

cout<

else

cout<";

}

cout<<"\n";

cout<

"<

cout<<"\n";

cout<<"向后递推算法求得的最短路径:

\n\n";

back(bcost,path1,d);

for(j=1;j<=5;j++)

{

if(j==5)

cout<

else

cout<";

}

cout<<"\n";

cout<

"<

cout<<"\n";

}

运行结果如下图所示:

实验收获与体会:

通过多段图实验对动态规划的思想有了更深理解,动态规划与分治法类似,基本思想也是将待求解问题分成若干个子问题,但是分解得到的子问题往往不是互相独立的。

 

 

回溯法实验

回溯法在问题的解空间树中,按深度优先策略,从根结点出发搜索解空间树。

算法搜索至解空间树的任意一点时,先判断该结点是否满足约束。

如果不满足,则跳过对该结点为根的子树的搜索,逐层向其祖先结点回溯;否则,进入该子树,继续按深度优先策略搜索。

N皇后:

基本思想:

(1)针对所给问题,定义问题的解空间,使N个皇后不在同行同列,对角线上;

(2)确定易于搜索的解空间结构;

(3)以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。

实验代码如下:

#include

#include"math.h"

classQUEEN

{

public:

friendintnQueen(int);

private:

boolPlace(intk);

voidBacktrack(intt);

intn,*x;

longsum;

};

 

intnQueen(intn)

{

QUEENx;

x.n=n;

x.sum=0;

int*p=newint[n+1];

for(inti=0;i<=n;i++)

p[i]=0;

x.x=p;

x.Backtrack

(1);

delete[]p;

returnx.sum;

}

boolQUEEN:

:

Place(intk)

{

for(intj=1;j

if((abs(k-j)==abs(x[j]-x[k]))||(x[j]==x[k]))

returnfalse;

returntrue;

}

voidQUEEN:

:

Backtrack(intt)

{

if(t>n){sum++;

cout<<"n皇后问题的第"<

"<

for(t=1;t<=n;t++)

cout<<"("<

cout<<"********"<

else

for(inti=1;i<=n;i++)

{

x[t]=i;

if(Place(t))

Backtrack(t+1);//递归求解

}

}

intmain()

{intn;

cout<<"***************N皇后问题***************"<

cout<

cout<<"请输入皇后的个数n:

"<

cin>>n;

cout<

cout<<"***************N皇后问题结束*************"<

}

运行结果如下图所示:

实验收获与体会:

通过该实验对回溯法的思想有了较深的了解,通过亲手实践,加深了记忆与理解,该实验的算法也可以用在类似有关回溯法问题上。

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

当前位置:首页 > 职业教育 > 职高对口

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

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