分治的实现::递归程序设计

【分治算法】
是一种思想,你拿到的问题往往不会是很简单的事情,而再复杂再难的问题都可以分解成一些有限的简单问题的和,这就是分治法的原理。

举个最简单的例子,计算阶乘之和n!+(n-1)!+...+1!:

n可以取大取小,问题的范围可以大可以小,如果小就比较容易,比如1!=1这是己知,如何将大问题化成小问题,找它们之间的联系:

如果n=k已经解决,那么n=k+1能否解决,如何解决?

很显然:n=k+1的情况就是将n=k的结果加上(k+1)!的值。

【递归程序设计】
是一种算法常用设计方法,在高级语言中,函数之间可以进行嵌套调用,用栈的机制实现,这样的做法可以使我们在算法设计的时候能够达到套调算法设计。

int facsum(int n)
{
  if(n==1)return 1;
  return fac(n)+facsum(n-1);
}
/*fac()为求阶乘函数,facsum()为阶乘求和函数*/

“if(n==1)return 1;”为小问题、简单问题解的直接描述,在递归中称为递归边界,没有设定边界的递归是只能‘递’不能‘归’的,即死循环。

“return fac(n)+facsum(n-1);”中将n的范围缩小:n-1,以此将大问题化为类似的小问题,类似很重要,如果不类似就不能调同一个函数,这很显然。——这样一个过程就是分治算法的实现。

[阶乘求和可以用更高效率的算法求解,以上只是做为一个简单例子]

再举一例,将数组的元素逆置:

void inverse(int a[],int n)
{
  if(__①__)return;
  swap(a[0],a[n-1]);/*swap(a,b)为交换a,b的值*/
  inverse(__②__);
}

①处为小问题解描述,也是递归边界,怎样的小问题是很显然的呢?当数组的元素个数小于2时是不需要逆置的,所以填:n<2
②交换之后进行递归,分解成小问题,两端的已经交换,所以往中间靠,所以填:a+1,n-2

这样的问题有很多很多,如拆半法查找,用二分法求方程的根等等。都离不开两点:1、小问题的描述,即递归边界,2、将大问题化成小问题。
拆半法查找的小问题是:low==high;二分法求根的小问题是fabs(x1-x2)<eps。

PS:再加点吧,我竟没有想到汉诺塔这么经典的递归设计问题,有很多初学朋友不太明白程序的意图,你可以借助我上面讲的加深理解,书中的经典程序大致如下:
void move(int n,int from,int med,int to)
{
     if (n==1)
        printf("%d-->%d/n",from,to);
     else
     {
         move(n-1,from,to,med);
         printf("%d-->%d/n",from,to);
         move(n-1,med,from,to);
     }
}
这是一个核心函数,
if(n==1)即小问题描述,也就是递归边界

move(n-1,from,to,med);
printf("%d-->%d/n",from,to);
move(n-1,med,from,to);

是把问题的规模化小,也就是分而治之的思想,不管过程有多复杂,只要能把问题的规模化小,就可以运用分治+递归设计程序。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值