(算法复习-) 递归 & 分治 详解

 递归和分治从解决问题的角度上讲是息息相关的、甚至从根本上就无法分开,递归本身就实际包含着分治的思想、而分治又必须要用到递归的手段,所以这里把递归和分治放到一起来讲。 文章不可避免的会有些长,而我的笔记又尽可能的会把语言放简洁,这样便容易导致好多看这篇文章的人看不懂,如果出现了这样的情况,请尽可能在评论栏留言,我会一一回复并争取对文章进行向好的修改

---------------------------------

   [ 0已更新 递归练习1(汉诺塔): 汉诺塔 - 从数学意义上的详解            很用心,推荐看一下

-------------------

递归,最简单的理解就是 “自己调用自己”

一个非常典型的就是例子就是“老和尚讲故事”:

 

//老和尚讲故事函数
 Void Story()
 {
   printf("从前有个山,山上有个庙,庙里有个老和尚,他在讲故事:  \r\n");
   Story();
 }

    上面那个函数看起来很好玩,也并不难理解;然而在实际应用中,单纯进行没有终止条件不断自调用的递归大多数是没有意义的,而真正使用中的递归应该满足其它一些基本条件;

一般解决问题需要的: 
       
  1.递归终止条件
             2.终止处理办法
                 3.递归处理方法

阶乘就是一个实用化当中最经典的例子:

//阶乘
 int factorial(int n)
 { 
   if(n==0) return 1;  //递归边界(终止条件)
   return n*factorial(n-1);
 }

 

图中我们可以看到,递归的最终结果来自于嵌套在最内部的一个简单if语句,也就是递归出口这一行一般都以一个最简单处理语句返回最初也是最关键的值,而后,通过这个值向前调用、一步一步集合成更高阶的子值、并最终实现原问题的解答;

也就是说,递归在实际使用中至少包括一个递进(去)的过程和一个归来(回)的过程。(即“ 递进需归来 ”)

下面斐波那契数列我已经画好了但传不上来...大家可以自己画一下

//Fibonacci数列
 int Fibonacci(int n)
 {
   if(n<=1) return 1;
   return Fibonacci(n-1)+Fibonacci(n-2);
 }

 

 

后面我还会更新好多递归分治的习题;

而且,这种东西只是开头很苦但是并不难 只要你能做到不断的练习,最终一定是能够理解递归思想的

 

这里先贴下递归三个要点:

1. 递归也是一种特殊的迭代,但是在迭代之前并不知道还要迭代多少次
    2. 递归函数一定有参数,而且参数会在迭代的过程中步步紧逼某个值
    3. 递归函数中一定有处理终点,而这个点就是递归出口

 

 

※附 递归与循环之区别


   循环:
  你打开一扇门,看到屋子里还有一扇门(这门和前面的门一样大小),你走过去,发现你有钥匙可以打开它,你推开它,发现里面还有一扇门,你继续打开这扇门,...一直这么走下去,满足特定条件则停止。这时,你知道哪扇门里有你想要的东西、但入口处的人始终等不到你回去。


   递归:
  你打开面前这扇门,看到屋子里还有一扇门(可能这门变小了些),你走过去,发现手中的钥匙还可以打开它,你推开门,发现里面还有一扇门,你继续打开,...若干次之后,你打开面前的一扇门、发现只有一间屋子、没有门了。 你开始原路往回走,每回到一间屋子,你数一次,回到入口的时候,你甚至可以回答出你到底用这钥匙开了几扇门

 

---------------------------------------------------------------------------

 

 

分治法的根本在于以大化小以小的子问题的解来解决大的问题

当时这篇翻译来的博客中曾提到过这种算法思想:归并排序(Merge Sort)


      分治策略算法细分为三个阶段: Divide(分)、Conquer(治)、Combine(合)。  Divide阶段是把原问题分割成小问题, Conquer阶段是递归处理流程, Combine阶段是运用一个个小问题的答案合成出原问题的答案。

 

比较直接的又可以分为两个步骤:
    1.Divide step: Divide the large, original problem into smaller sub-problems and recursively solve the smaller sub-problems,
将较大的原始问题划分为较小的子问题,并递归地解决较小的子问题,)

    2.Conquer step: Combine the results of the smaller sub-problems to produce the result of the larger, original problem.
结合较小子问题的结果,以产生较大的原始问题的结果。)

 


分治算法的框架:
                 divide - and - conquer (P)  :

(1)  if( |P| <= n0 ) adhoc(p);      //递归出口、用特定程序解决基础问题 
(2)  divide P into smaller subinstances P1,P2,...Pk ;      //分解出子问题
(3)  for (i = 1, i<= k, i++)
    yi = divide-and-conquer(Pi);      //递归求解各子问题
(4)  return merge(y1,...,yk);      //将各个子问题的解合并为原问题的解

 

一些关于分治法的要点:
设计划分策略、把原问题P分解成k个规模较小的子问题,这个步骤是分治算法的基础和关键,人们往往遵循两个原则:
    · 平衡子问题原则,分割出的k个子问题其规模最好大致相当
    · 独立子问题原则,分割出的k个子问题之间重叠越少越好、最好k个子问题相互独立,不存在重叠子问题 。

 

    merge步骤合并子程序,即把k个子问题的解合并得到原问题的解。但合并子程序因求解问题而异,即使是同一个问题、如果第二步的划分策略不同,其合并子程序也往往不一样。
 

附 分治举例

最简单的——如果你想把你家里刚买的床搬进去、你需要把床分成一个一个的小块,床腿啊床垫啊背靠啊收纳仓啊什么的,然后再在屋子里把它组装起来。 

 

递归练习1(汉诺塔详解):https://blog.csdn.net/weixin_41298915/article/details/89318084

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值