算法设计与分析所有程序.docx
《算法设计与分析所有程序.docx》由会员分享,可在线阅读,更多相关《算法设计与分析所有程序.docx(86页珍藏版)》请在冰豆网上搜索。
算法设计与分析所有程序
第二章递归与分治
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);(nf(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(nreturnGetPartitionCount(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;jif((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=min1min1:
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&&dcchessBoard(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]=t
展开阅读全文
相关搜索