算法设计与分析报告报告材料实验二.docx

上传人:b****6 文档编号:6054133 上传时间:2023-01-03 格式:DOCX 页数:14 大小:25.36KB
下载 相关 举报
算法设计与分析报告报告材料实验二.docx_第1页
第1页 / 共14页
算法设计与分析报告报告材料实验二.docx_第2页
第2页 / 共14页
算法设计与分析报告报告材料实验二.docx_第3页
第3页 / 共14页
算法设计与分析报告报告材料实验二.docx_第4页
第4页 / 共14页
算法设计与分析报告报告材料实验二.docx_第5页
第5页 / 共14页
点击查看更多>>
下载资源
资源描述

算法设计与分析报告报告材料实验二.docx

《算法设计与分析报告报告材料实验二.docx》由会员分享,可在线阅读,更多相关《算法设计与分析报告报告材料实验二.docx(14页珍藏版)》请在冰豆网上搜索。

算法设计与分析报告报告材料实验二.docx

算法设计与分析报告报告材料实验二

实验二:

分治法实验

一、实验目的

(1)掌握设计有效算法的分治策略。

(2)通过快速排序学习分治策略设计技巧

二、实验要求

(1)熟练掌握分治法的基本思想及其应用实现。

(2)理解所给出的算法,并对其加以改进。

三、分治法的介绍

任何一个可以用计算机求解的问题所需的计算时间都与其规模有关。

问题的规模越小,越容易直接求解,解题所需的计算时间也越少。

而当n较大时,问题就不那么容易处理了。

要想直接解决一个规模较大的问题,有时是相当困难的。

分治法的设计思想是,将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。

如果原问题可分割成k个子问题,1

由分治法产生的子问题往往是原问题的较小模式,这就为使用递归技术提供了方便。

在这种情况下,反复应用分治手段,可以使子问题与原问题类型一致而其规模却不断缩小,最终使子问题缩小到很容易直接求出其解。

这自然导致递归过程的产生。

分治与递归像一对孪生兄弟,经常同时应用在算法设计之中,并由此产生许多高效算法。

分治法的适用条件:

(1)该问题的规模缩小到一定的程度就可以容易地解决;

(2)该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质。

(3)利用该问题分解出的子问题的解可以合并为该问题的解;

(4)该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。

上述的第一条特征是绝大多数问题都可以满足的,因为问题的计算复杂性一般是随着问题规模的增加而增加;第二条特征是应用分治法的前提,它也是大多数问题可以满足的,此特征反映了递归思想的应用;第三条特征是关键,能否利用分治法完全取决于问题是否具有第三条特征,如果具备了第一条和第二条特征,而不具备第三条特征,则可以考虑贪心法或动态规划法。

第四条特征涉及到分治法的效率,如果各子问题是不独立的,则分治法要做许多不必要的工作,重复地解公共的子问题,此时虽然可用分治法,但一般用动态规划法较好。

分治法的基本步骤:

分治法在每一层递归上都有三个步骤:

分解:

将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题;

解决:

若子问题规模较小而容易被解决则直接解,否则递归地解各个子问题;

合并:

将各个子问题的解合并为原问题的解。

它的一般的算法设计模式如下:

Divide-and-Conquer(P)

1. if|P|≤n0

2.   thenreturn(ADHOC(P))

3. 将P分解为较小的子问题P1,P2,...,Pk

4. fori←1tok

5.   doyi←Divide-and-Conquer(Pi)   △递归解决Pi

6. T←MERGE(y1,y2,...,yk)            △合并子问题

7. return(T)

其中|P|表示问题P的规模;n0为一阈值,表示当问题P的规模不超过n0时,问题已容易直接解出,不必再继续分解。

ADHOC(P)是该分治法中的基本子算法,用于直接解小规模的问题P。

因此,当P的规模不超过n0时,直接用算法ADHOC(P)求解。

算法MERGE(y1,y2,...,yk)是该分治法中的合并子算法,用于将P的子问题P1,P2,...,Pk的相应的解y1,y2,...,yk合并为P的解。

根据分治法的分割原则,原问题应该分为多少个子问题才较适宜?

各个子问题的规模应该怎样才为适当?

这些问题很难予以肯定的回答。

但人们从大量实践中发现,在用分治法设计算法时,最好使子问题的规模大致相同。

换句话说,将一个问题分成大小相等的k个子问题的处理方法是行之有效的。

许多问题可以取k=2。

这种使子问题规模大致相等的做法是出自一种平衡(balancing)子问题的思想,它几乎总是比子问题规模不等的做法要好。

分治法的合并步骤是算法的关键所在。

有些问题的合并方法比较明显,有些问题合并方法比较复杂,或者是有多种合并方案;或者是合并方案不明显。

究竟应该怎样合并,没有统一的模式,需要具体问题具体分析。

四、实验内容

1、编程实现归并排序算法和快速排序算法,程序中加入比较次数的计数功能,输出排序结果和比较次数。

输入10组相同的数据,验证排序结果和完成排序的比较次数。

用表格列出比较结果。

给出文字分析。

2、汉诺塔(hanoi)问题。

3、棋盘覆盖问题。

4、循环赛日程安排问题。

五、算法设计

1、归并排序算法

procedureMERGESORT(low,high)

//A(low;high)是一个全程数组,它含

有high-low+1≥0个待排序的元素//

integerlow,high;

iflow

thenmid←,//求这个集合的分割点//

callMERGESORT(low,mid)//将一个子集合排序//

callMERGESORT(mid+1,high)//将另一个子集合排序

callMERGE(low,mid,high)//归并两个已排序的子集合//

endif

endMERGESORT

归并两个已排序的集合

procedureMERGE(low,mid,high)

//A(low:

high)是一个全程数组//

//辅助数组B(low;high)//

integerh,i,j,k;

h←low;i←low;j←mid+1;

whileh≤midandj≤highdo//当两个集合都没取尽时//

ifA(h)≤A(j)thenB(i)←A(h);h←h+1

elseB(i)←A(j);j←j+1

endif

i←i+1

repeat

ifh>midthen

fork←jtohighdo//处理剩余的元素//

B(i)←A(k);i←i+1

repeat

elsefork←htomiddo

B(i)←A(k);i←i+1

repeat

endif

将已归并的集合复制到A

endMERGE

2、快速排序算法

我们已经知道,在决策树计算模型下,任何一个基于比较来确定两个元素相对位置的排序算法需要Ω(nlogn)计算时间。

如果我们能设计一个需要O(n1ogn)时间的排序算法,则在渐近的意义上,这个排序算法就是最优的。

许多排序算法都是追求这个目标。

下面介绍快速排序算法,它在平均情况下需要O(nlogn)时间。

这个算法是由C.A.R.Hoare发明的。

算法的基本思想:

快速排序的基本思想是基于分治策略的。

对于输入的子序列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]就已排好序。

这个解决流程是符合分治法的基本步骤的。

因此,快速排序法是分治法的经典应用实例之一。

QuickSort(p,q)

//将数组A[1:

n]中的元素

A[p],A[p+1],,A[q]按不降次序排列,

并假定A[n+1]是一个确定的、且大于

A[1:

n]中所有的数。

//

intp,q;globaln,A[1:

n];

ifp

j=Partition(p,q+1);//划分后j成为划分元素的位置

QuickSort(p,j-1);

QuickSort(j+1,q);

endif

endQuickSort

procedurePARTITION(m,p)

//退出过程时,p带着划分元素所在的下标位置。

//

integerm,p,i;globalA(m:

p-1)

v←A(m);i←m//A(m)是划分元素//

loop

loopi←i+1untilA(i)≥vrepeat//i由左向右移//

loopp←p-1untilA(p)≤vrepeat//p由右向左移//

ifi

thencallINTERCHANGE(A(i),A(p))//A(i)和A(p)换位//

elseexit

endif

repeat

A(m)←A(p);A(p)←v//划分元素在位置p//

EndPARTITION

3、汉诺塔(hanoi)问题。

设有A、B、C共3根塔座,在塔座A上堆叠n个金盘,每个盘大小不同,只允许小盘在大盘之上,最底层的盘最大,如下图所示。

现在要求将A上的盘全都移到C上,在移的过程中要遵循以下原则:

每次只能移动一个盘;圆盘可以插在A、B和C任一个塔座上;在任何时刻,大盘不能放在小盘的上面。

 

hanoi问题递归求解思想:

我们把一个规模为n的hanoi问题:

1到n号盘按照移动规则从A上借助B移到C上表示为H(A,B,C,n);原问题划分成如下三个子问题:

(1)将1到n-1号盘按照移动规则从A上借助C移到B上H(A,C,B,n-1);

(2)将n号盘从A上直接移到C上;

(3)将1到n-1号盘按照移动规则从B上借助A移到C上H(B,A,C,n-1);

经过三个子问题求解,原问题的也即求解完成。

4、盘覆盖问题。

在一个2k×2k个方格组成的棋盘中,恰有一个方格与其它方格不同,称该方格为一特殊方格,且称该棋盘为一特殊棋盘。

在棋盘覆盖问题中,要用图示的4种不同形态的L型骨牌覆盖给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖。

六、参考程序代码

1、归并排序

#include

#include

#include

#include

#defineM11

typedefintKeyType;

typedefintElemType;

structrec{

KeyTypekey;

ElemTypedata;

};

typedefrecsqlist[M];

classguibing{

public:

guibing(sqlistb)

{

for(inti=0;i

r[i]=b[i];

}

voidoutput(sqlistr,intn)

{

for(inti=0;i

cout<

cout<

}

voidxuanze(sqlistb,intm,intn)

{

inti,j,k;

for(i=m;i

{

k=i;

for(j=i;j

if(b[k].key>b[j].key)k=j;

if(k!

=i)

{

rectemp=b[k];

b[k]=b[i];

b[i]=temp;

}

}

}

voidmerge(intl,intm,inth,sqlistr2)

{

xuanze(r,l,m);

xuanze(r,m,h);

output(r,M);

inti,j,k;

k=i=l;

for(j=m;i

{

if(r[i].key<=r[j].key)

{

r2[k]=r[i];

i++;

}

else

{

r2[k]=r[j];

j++;

}

output(r2,M);

}

while(j

{

r2[k]=r[j];

j++;

k++;

}

while(i<=m)

{

r2[k]=r[i];

i++;

k++;

}

output(r2,M);

}

private:

sqlistr;

};

voidmain()

{

cout<<"guibingfa1运行结果:

\n";

sqlista,b;

inti,j=0,k=M/2,n=M;

srand(time(0));

for(i=0;i

{

a[i].key=rand()%80;b[i].key=0;

}

guibinggx(a);

cout<<"排序前数组:

\n";

gx.output(a,M);

cout<<"数组排序过程演示:

\n";

gx.merge(j,k,n,b);

cout<<"排序后数组:

\n";

gx.output(b,M);

cin.get();

}

2、快速排序

#include

#include

#include

#include

#defineMAXI10

typedefintKeyType;

typedefintElemType;

structrec{

KeyTypekey;

ElemTypedata;

};

typedefrecsqlist[MAXI];

classkuaisu

{

public:

kuaisu(sqlista,intm):

n(m)

{

for(inti=0;i

}

voidquicksort(ints,intt)

{

inti;

if(s

i=part(s,t);

quicksort(s,i-1);

quicksort(i+1,t);

}

elsereturn;

}

intpart(ints,intt)

{

inti,j;

recp;

i=s;j=t;p=b[s];

while(i

{

while(i=p.key)j--;

b[i]=b[j];

while(i

b[j]=b[i];

}

b[i]=p;

output();

returni;

}

voidoutput()

{

for(inti=0;i

cout<

cout<

}

private:

sqlistb;

intn;

};

voidmain()

{

cout<<"kuaisu1.cpp运行结果:

\n";

sqlista1;

inti,n=MAXI,low=0,high=9;

srand(time(0));

for(i=0;i

a1[i].key=rand()%80;

kuaisupx(a1,n);

cout<<"数组排序过程演示:

\n";

px.quicksort(low,high);

cout<<"排序后数组:

\n";

px.output();

cin.get();

}

3、hanoi问题递归求解代码:

voidH(charA,charB,charC,intn)

{

if(n>0)

{

H(A,C,B,n-1);

printf(“%dfrom%cto%c”,n,A,C);

H(B,A,C,n-1);

}

}

4、棋盘覆盖问题。

voidchessBoard(inttr,inttc,intdr,intdc,intsize)

  {

     if(size==1)return;

     intt=tile++, //L型骨牌号

       s=size/2; //分割棋盘

     //覆盖左上角子棋盘

     if(dr

        //特殊方格在此棋盘中

        chessBoard(tr,tc,dr,dc,s);

     else{//此棋盘中无特殊方格

        //用t号L型骨牌覆盖右下角

        board[tr+s-1][tc+s-1]=t;

        //覆盖其余方格

        chessBoard(tr,tc,tr+s-1,tc+s-1,s);}

     //覆盖右上角子棋盘

     if(dr=tc+s)

        //特殊方格在此棋盘中

        chessBoard(tr,tc+s,dr,dc,s);

     else{//此棋盘中无特殊方格

        //用t号L型骨牌覆盖左下角

board[tr+s-1][tc+s]=t;

        //覆盖其余方格

        chessBoard(tr,tc+s,tr+s-1,tc+s,s);}

       //覆盖左下角子棋盘

     if(dr>=tr+s&&dc

        //特殊方格在此棋盘中

        chessBoard(tr+s,tc,dr,dc,s);

     else{//用t号L型骨牌覆盖右上角

        board[tr+s][tc+s-1]=t;

        //覆盖其余方格

        chessBoard(tr+s,tc,tr+s,tc+s-1,s);}

     //覆盖右下角子棋盘

     if(dr>=tr+s&&dc>=tc+s)

        //特殊方格在此棋盘中

        chessBoard(tr+s,tc+s,dr,dc,s);

     else{//用t号L型骨牌覆盖左上角

        board[tr+s][tc+s]=t;

        //覆盖其余方格

        chessBoard(tr+s,tc+s,tr+s,tc+s,s);}

  }

5、循环赛日程安排问题

#include"stdio.h"

voidTable(intk,inta[][9])

{

intn=1;

for(inti=1;i<=k;i++)n*=2;

for(i=1;i<=n;i++)a[1][i]=i;

intm=1;

for(ints=1;s<=k;s++)

{

n/=2;

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

for(i=m+1;i<=2*m;i++)

for(intj=m+1;j<=2*m;j++)

{

a[i][j+(t-1)*m*2]=a[i-m][j+(t-1)*m*2-m];

a[i][j+(t-1)*m*2-m]=a[i-m][j+(t-1)*m*2];}

m*=2;

}

}

main()

{

intk=3;

inta[9][9]={0};

Table(k,a);

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

{for(intj=1;j<=8;j++)

printf("%3d",a[i][j]);

printf("\n");

}

}

思考问题:

1、递归的关键问题在哪里?

2、递归与非递归之间程序的转换?

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

当前位置:首页 > 自然科学

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

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