算法设计与分析所有程序.docx

上传人:b****8 文档编号:23978090 上传时间:2023-05-23 格式:DOCX 页数:88 大小:43.90KB
下载 相关 举报
算法设计与分析所有程序.docx_第1页
第1页 / 共88页
算法设计与分析所有程序.docx_第2页
第2页 / 共88页
算法设计与分析所有程序.docx_第3页
第3页 / 共88页
算法设计与分析所有程序.docx_第4页
第4页 / 共88页
算法设计与分析所有程序.docx_第5页
第5页 / 共88页
点击查看更多>>
下载资源
资源描述

算法设计与分析所有程序.docx

《算法设计与分析所有程序.docx》由会员分享,可在线阅读,更多相关《算法设计与分析所有程序.docx(88页珍藏版)》请在冰豆网上搜索。

算法设计与分析所有程序.docx

算法设计与分析所有程序

 

第二章递归与分治

1、用递归思想求N!

王晓东版——《计算机算法设计与分析(第四版)》P11页,例2-1

#include

voidmain()

{

longn;

intJieChen(intn);

printf("请输入一个数\n");

scanf("%ld",&n);

longresult=JieChen(n);

printf("%ld",result);

}

intJieChen(intn)

{

if(n==1)

return1;

else

returnn*JieChen(n-1);

}

2、用递归思想求Fibonacci数列

王晓东版——《计算机算法设计与分析(第四版)》P12页,例2-2

intFibonacci(intn)

{

if(n<=1)

return1;

else

returnFibonacci(n-1)+Fibonacci(n-2);

}

voidmain()

{

longn;

printf("请输入一个数\n");

scanf("%ld",&n);

longresult=Fibonacci(n);

printf("%ld\n",result);

}

3、用递归思想求排列问题

王晓东版——《计算机算法设计与分析(第四版)》P13页,例2-4

N个元素的全排列的个数为:

N!

本算法非常重要,因为它是很多算法的基础,比如回溯法那章里的算法很多都是以本算法为基础的。

#include

//交换两个元素的值

voidSwap(int&x,int&y)

{

intt=x;

x=y;

y=t;

}

//产生list[k:

m]的所有排列

//m是最后一个元素在数组中的下标

voidPerm(intlist[],intk,intm)

{

if(k==m)//如果只有一个元素

{

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

printf("%d",list[i]);

printf("\n");

}else

{

for(inti=k;i<=m;i++)

{

Swap(list[i],list[k]);

Perm(list,k+1,m);

Swap(list[i],list[k]);//将元素还原

}

}

}

voidmain()

{

inta[5]={1,2,3,4,5};

//求数组前面三个元素的全排列

Perm(a,0,3);

}

4、用递归思想求整数划分问题

王晓东版——《计算机算法设计与分析(第四版)》P14页,例2-5

整数划分问题是算法中的一个经典命题之一,有关这个问题的讲述在讲解到递归时基本都将涉及。

所谓整数划分,是指把一个正整数n写成如下形式:

n=m1+m2+……+mi;(其中mi为正整数,并且1<=mi<=n),则{m1,m2,...,mi}为n的一个划分。

如果{m1,m2,...,mi}中的最大值不超过m,即max(m1,m2,...,mi)<=m,则称它属于n的一个m划分。

这里我们记n的m划分的个数为f(n,m);

例如,但n=4时,他有5个划分,{4},{3,1},{2,2},{2,1,1},{1,1,1,1};

注意4=1+3和4=3+1被认为是同一个划分。

该问题是求出n的所有划分个数,即f(n,n)。

下面我们考虑求f(n,m)的方法;

根据n和m的关系,考虑以下几种情况:

(1)当n=1时,不论m的值为多少(m>0),只有一种划分即{1};

(2)当m=1时,不论n的值为多少,只有一种划分即n个1,{1,1,1,...,1};

(3)当n=m时,根据划分中是否包含n,可以分为两种情况:

(a).划分中包含n的情况,只有一个即{n};

(b).划分中不包含n的情况,这时划分中最大的数字也一定比n小,即n的所有(n-1)划分。

因此f(n,n)=1+f(n,n-1);

(4)当n

(5)但n>m时,根据划分中是否包含最大值m,可以分为两种情况:

(a).划分中包含m的情况,即{m,{x1,x2,...,xi}},其中{x1,x2,...,xi}的和为n-m,可能再次出现m,因此是(n-m)的m划分,因此这种划分个数为f(n-m,m);

(b).划分中不包含m的情况,则划分中所有值都比m小,即n的(m-1)划分个数为f(n,m-1);

因此f(n,m)=f(n-m,m)+f(n,m-1);

综合以上情况,我们可以看出,上面的结论具有递归定义特征,其中

(1)和

(2)属于回归条件,(3)和(4)属于特殊情况,将会转换为情况(5)。

而情况(5)为通用情况,属于递推的方法,其本质主要是通过减小m以达到回归条件,从而解决问题。

其递推表达式如下:

f(n,m)=1;(n=1orm=1)

f(n,m)=f(n,n);(n

f(n,m)=1+f(n,m-1);(n=m)

f(n,m)=f(n-m,m)+f(n,m-1);(n>m)

因此我们可以给出求出f(n,m)的递归函数代码如下。

//求整数n的全部划分数,其中max代表最大加数

longGetPartitionCount(intn,intmax)

{

if(n==1||max==1)

return1;

elseif(n

returnGetPartitionCount(n,n);

elseif(n==max)

return1+GetPartitionCount(n,max-1);

else

returnGetPartitionCount(n,max-1)+GetPartitionCount(n-max,max);

}

voidmain()

{

printf("请输入要划分的整数\n");

intn;

scanf("%d",&n);

intnum=GetPartitionCount(n,n);

printf("总划数为:

%d\n",num);

}

怎样求出具体的划分结果呢?

这个问题比较难解决,等进一步分析。

5、用递归思想求汉诺塔问题

//n代表盘子个数

//a,b,c代表柱子名称

//程序功能:

将n个从小到大又叠放的盘子,从A柱子移动到B柱子,

//中间可以借助C柱子

voidHanoi(intn,charA,charB,charC)

{

if(n>0)

{

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

printf("%d,%c-->%c\n",n,A,B);//模拟移动过程

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

}

}

voidmain()

{

Hanoi(3,'a','b','c');

}

6、用递归思想实现插入排序

#include

#include

#include

voidinsertSort(int*aa,intn)

{

if(n>0)

{

n=n-1;

insertSort(aa,n);

inta=aa[n];

intk=n-1;

while((k>=0)&&a

{

aa[k+1]=aa[k];

k--;

}

aa[k+1]=a;

}

}

voidmain()

{

inta[10];

srand((unsignedint)time(NULL));

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

{

a[i]=rand()%100;

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

}

printf("\n");

insertSort(a,10);

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

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

printf("\n");

}

7、用分治思想实现二分查找

方法一:

用到了递归

//在a数组里查找是否存在x这个元素,如果存在,则返回元素所在下标,如果不存在

//left:

查找的起始下标right:

查找的终止下标

intBinarySearch(inta[],intx,intleft,intright)

{

intmiddle=(left+right)/2;

if(left>right)

return-1;

if(x==a[middle])

returnmiddle;

else

{

if(x>a[middle])

returnBinarySearch(a,x,middle+1,right);

else

returnBinarySearch(a,x,left,middle-1);

}

}

voidmain()

{

inta[9]={-2,2,7,9,19,21,34,65,98};

intindex=BinarySearch(a,100,8);

printf("%d\n",index);

}

方法二:

用循环代替递归

//在a数组里查找是否存在x这个元素,如果存在,则返回元素所在下标,如果不存在

//则返回-1

//n为最后一个元素的下标

intBinarySearch(inta[],intx,intn)

{

intleft=0;//开始需要查找元素的下标

intright=n-1;//最后需要查找元素的下标

while(left<=right)

{

intmiddle=(left+right)/2;

if(x==a[middle])

returnmiddle;

else

{

if(x>a[middle])

left=middle+1;

else

right=middle-1;

}

}

return-1;

}

8、用分治法求两个大整数的乘法

最简单的方法,这里没有体现分治法的思想

#include

intmain()

{

chara[100],b[100],s[202];

inti,j,g,t=0,k=0,temp;

printf("请输入两个大整数,空格分隔\n");

scanf("%s%s",&a,&b);

intm=strlen(a);

intn=strlen(b);

while(k

{

s[k]=0;

temp=0;

for(i=0;i

{

for(j=0;j

{

if((i+j)==k)//第k位上所有数字之和

temp+=(a[m-1-i]-48)*(b[n-1-j]-48);

}

}

g=(temp+t)%10;

t=(temp+t)/10;//t用来保存进位

s[k]=g;

k++;

}

//求最高1位或者2位,并输出

temp=0;

for(i=0;i

{

for(j=0;j

if((i+j)==k)

temp+=(a[m-1-i]-48)*(b[n-1-j]-48);

}

temp+=t;//加上原来的进位

printf("%d",temp);

//将其它位逆向输出

for(i=m+n-2-1;i>=0;i--)

printf("%d",s[i]);

printf("\n");

return0;

}

9、用分治思想求一个数组的最大值与最小值

#include

#include

#include

#defineLEN8

voidmaxmin(inta[],int*max,int*min,intlow,inthigh)

{

intmid,max1,min1,max2,min2;

if((high-low)<=1)

{

if(a[high]>=a[low])

{

*max=a[high];

*min=a[low];

}else

{

*max=a[low];

*min=a[high];

}

}else

{

mid=(high+low)/2;

maxmin(a,&max1,&min1,low,mid);

maxmin(a,&max2,&min2,mid+1,high);

*max=max1>max2?

max1:

max2;

*min=min1

min1:

min2;

}

}

voidmain()

{

inta[LEN];

intmax=-1,min=1000;

srand((unsigned)time(NULL));

printf("数组里的元素为:

\n");

for(inti=0;i

{

a[i]=rand()%100;

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

}

maxmin(a,&max,&min,0,LEN-1);

printf("\n最大值为:

%d\n最小值为:

%d\n",max,min);

}

#include

#include

#include

#defineLEN8

voidmain()

{

inta[LEN];

srand((unsigned)time(NULL));

printf("数组里的元素为:

\n");

for(inti=0;i

{

a[i]=rand()%100;

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

}

}

*/

10、用分法思想实现合并排序

#include

intb[9];

voidmerge(intc[],intd[],intl,intm,intr)

{

inti=l,j=m+1,k=l;

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

{

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

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

else

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

}

//将剩余部分处理好

while(j<=r)

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

while(i<=m)

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

}

voidmergesort(inta[],intleft,intright)

{

if(left

{

inti=(left+right)/2;

mergesort(a,left,i);//将左边部分排好序

mergesort(a,i+1,right);//将右边部分排好序

merge(a,b,left,i,right);//将左右两边合并

for(intj=left;j<=right;j++)

a[j]=b[j];

}

}

voidmain()

{

inta[9]={4,3,6,8,9,1,25,2,34};

printf("原始数据为:

\n");

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

printf("%d\t",a[i]);

mergesort(a,0,8);

printf("\n合并后的数据为:

\n");

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

printf("%d\t",a[i]);

printf("\n");

}

11、用分治思想实现快速排序

#include

voidquicksort(inta[],intp,intr)

{

intpartition(inta[],intp,intr);

if(p

{

intq=partition(a,p,r);

quicksort(a,p,q-1);

quicksort(a,q+1,r);

}

}

//以a[p]为基准,将数组a[p]-a[r]段元素分为两部,其实一部分

//比a[p]小,另一部分比a[p]大,

//返回值为a[p]最终所在位置

intpartition(inta[],intp,intr)

{

voidswap(int*x,int*y);

inti=p,j=r+1;

intx=a[p];

while(true)

{

while(a[++i]

while(a[--j]>x&&j>p);

if(i>=j)

break;

swap(&a[i],&a[j]);

}

a[p]=a[j];

a[j]=x;

returnj;

}

voidswap(int*x,int*y)

{

intt;

t=*x;

*x=*y;

*y=t;

}

voidmain()

{

inta[9]={9,8,7,6,5,4,3,2,1};

printf("\n排序前的结果\n");

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

printf("%d\t",a[i]);

quicksort(a,0,8);

printf("\n排序后的结果\n");

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

printf("%d\t",a[i]);

printf("\n");

}

如果每次划分不以a[p]为基准,而是随机从a[p]-a[r]里取一个数为基准,则可以设计如下随机化快速排序算法。

//随机选择策略的划分算法,需要调用partition函数

intRandomizedPartition(inta[],intp,intr)

{

srand((unsignedint)time(NULL));

inti=p+rand()%(r-p+1);

swap(&a[i],&a[p]);

returnpartition(a,p,r);

}

12、用分治法实现线性时间选择问题

本算法要用到上面快速排序的随机划分算法

intRandomizedSelect(inta[],intp,intr,intk)

{

if(p==r)//如果只剩下一个数,则这个肯定就是第k小的数

returna[p];

else

{

inti=RandomizedPartition(a,p,r);//经过快速排序进行划分

intj=i-p+1;//计算通过划分后,从a[p]到a[i]有多少数

if(k<=j)//第k小的数在a[i]的前半段

returnRandomizedSelect(a,p,i,k);

else//第k小的数在a[i]的后半段,并且从a[p]到a[i]这些数都小于第k小的数

returnRandomizedSelect(a,i+1,r,k-j);

}

}

13、用分法思想实现残缺棋盘问题

王晓东版——《计算机算法设计与分析(第四版)》P20页,例2.6

注意:

同一种形状的骨牌,在填充时数字不一样,关键看三个相同数字摆放位置所构成的形状。

#include

inttile=1;//L型骨牌的编号(递增)

intboard[100][100];//棋盘

/*****************************************************

*tr--当前棋盘左上角的行号

*tc--当前棋盘左上角的列号

*dr--当前特殊方格所在的行号

*dc--当前特殊方格所在的列号

*size:

当前棋盘的:

2^k

*****************************************************/

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

{

if(size==1)//棋盘方格大小为1,说明递归到最里层

return;

intt=tile++;//每次递增1

ints=size/2;//棋盘中间的行、列号(相等的)

//检查特殊方块是否在左上角子棋盘中

if(dr

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

else//不在,将该子棋盘右下角的方块视为特殊方块

{

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//不在,将该子棋盘左下角的方块视为特殊方块

{

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//不在,将该子棋盘右上角的方块视为特殊方块

{

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

{

board[tr+s][tc+s

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

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

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

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