算法学习 - 递归 & 分治

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

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

递归最简单的说法就是“自己调用自己”

最典型的就是例子就是“老和尚讲故事”:

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

    然而在实际应用中,单纯进行没有终止条件不断自调用的递归大多数是没有意义的,而真正有用处的递归应该满足一些基本条件

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

例:

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

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

下面斐波那契数列可以自己画一下

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

重点:

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

※附 递归与循环之区别


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


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

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

我在这篇博客中曾提到过这种算法思想:https://blog.csdn.net/weixin_41298915/article/details/88933449


      分治策略算法细分为三个阶段: 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个子问题的解合并得到原问题的解。但合并子程序因求解问题而异,即使是同一个问题、如果第二步的划分策略不同,其合并子程序也往往不一样。
 

附 分治举例

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

猜你喜欢

转载自blog.csdn.net/weixin_41298915/article/details/89315587