递归与分治
一、分治
分治( Divide-and-Conquer )及分而治之,就是把一个较为复杂的问题分成多个规模较小但结构和原问题相同的或相似的子问题,然后在分别解决这些子问题,最后再将这些子问题合并即可得到原问题的解。在计算机中分治是一种很重要的算法思路,如:快速排序、归并排序……都是建立在分治的思路上。
根据上面定义分治可以分为三个步骤:
- 分解:将原问题分解为若干个和原题结构相同或相似的子问题。
- 解决:递归所有问题,如果问题小到可以直接解决则直接解决它,若不能直接解决则继续分解。
- 合并:将所有子问题的解进行合并以求出原问题的解。
注:分治分解出的的问题应该是相互独立的、没有交叉的,如果分解的问题有相交的地方,那么改题则不能使用分治解决。一般来说分治作为一种算法思想既可以使用递归的手段来实现,也可以通过非递归的方式来实现,不过一般来说使用递归实现分治较为简单(从广义上将,分治分解的问题个数>0
即可,但是严格来讲一般把子问题个数为1
的的情况成为减治)
二、递归
递归(递去归来):就是在函数(或方法)运行的过程中自己调用自己的现象。 在《算法笔记》上提到的递归的定义:“要理解递归,你首先要理解递归,直达你能理解递归”,这应该算是对递归有趣且十分直观的解释。递归就在于反复调用自己函数(或方法),但每次把问题规模缩小直到得到边界数据的结果,然后在返回的路上一步步求出最后的解。由此看来递归非常适分治的思想。
递归两概念&三要素
两概念:①:递归边界②递归式(递归调用)
三要素
- 明确你这个函数(或方法)想要⼲什么,
- 寻找递归结束条件,否则肯进入递归死循环。
- 提取重复的逻辑,缩小问题规模。
递归缺点
递归相对的不同的循环运行效率略低,在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等。
例1:n的阶乘
分析:n! = n * (n-1),(n-1)! = (n-1) * (n-2)! ,(n-2)! = (n-2) * (n-3)!,(n-3)! = (n-3) * (n-4)!,2! = 2 * 1,1! = 0! = 1
由分析得出递归边界应该是当n==1或n==0
当到达边界时返回值应为1
同时递归式应为F(n)=n*F(n-1)
,编写C代码如下: