算法设计与分析所有程序.docx
- 文档编号:23978090
- 上传时间:2023-05-23
- 格式:DOCX
- 页数:88
- 大小:43.90KB
算法设计与分析所有程序.docx
《算法设计与分析所有程序.docx》由会员分享,可在线阅读,更多相关《算法设计与分析所有程序.docx(88页珍藏版)》请在冰豆网上搜索。
算法设计与分析所有程序
第二章递归与分治
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 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 如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。 copyright@ 2008-2022 冰点文档网站版权所有 经营许可证编号:鄂ICP备2022015515号-1=tc+s)//在
冰豆网所有资源均是用户自行上传分享,仅供网友学习交流,未经上传用户书面授权,请勿作他用。