递归概念:把问题转化为规模缩小了的同类问题的子问题,然后递归调用函数(或过程)来表示问题的解。
特点:
1.调用自身
2.务必有一个明确的递归结束条件(递归出口)
3.递归算法解题通常显得很简洁,但递归算法解题的运行效率较低。
4.在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等。
递归必须满足的条件:
1)调用自身
2)递归出口否则进入死循环
分治介绍:
分治的概念:
是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同,求出子问题的解,就可得到原问题的解。
利用分治解题步骤:
(1)分解,将要解决的问题划分成若干规模较小的同类问题;
(2)求解,当子问题划分得足够小时,用较简单的方法解决;
(3)合并,按原问题的要求,将子问题的解逐层合并构成原问题的解。
使用分治法的要求:
当我们求解某些问题时,由于这些问题要处理的数据相当多,或求解过程相当复杂,使得直接求解法在时间上相当长,或者根本无法直接求出。对于这类问题,我们往往先把它分解成几个子问题,找到求出这几个子问题的解法后,再找到合适的方法,把它们组合成求整个问题的解法。如果这些子问题还较大,难以解决,可以再把它们分成几个更小的子问题,以此类推,直至可以直接求出解为止。
一般会把递归和分治结合使用。
接触到的算法用到的:树的三种递归遍历方式、快速排序、折半查找、图的遍历、归并排序、N的阶乘、欧几里德算法(求最大公约数)、斐波那契数列、汉诺塔问题
介绍几种典型的:
(1)阶乘
n! = n * (n-1) * (n-2) * ...* 1(n>0)
这便是个典型的递归的算法.设 f(n) 为求n的阶乘的函数,那么可以一个可以等价为 n * f(n-1)
而递归结束的条件为: n == 1时,求1!直接返回数值1
int recursive(int i)
{
int sum = 0;
if (1 == i)
return 1;
else
sum = i * recursive(i);
return sum;
}2):欧几里德算法(求最大公约数)
给出两个数m、n,求出两个数的最大公约数public static int gcd(int m, int n){
/*递归结束*/
if (n == 0){
return m;
}
/*递归调用*/
return gcd(n, m%n);
}
3)斐波那契数列
斐波纳契数列,又称黄金分割数列,指的是这样一个数列:1、1、2、3、5、8、13、21、……
这个数列从第三项开始,每一项都等于前两项之和。
有趣的兔子问题:

一般而言,兔子在出生两个月后,就有繁殖能力,一对兔子每个月能生出一对小兔子来。如果所有兔子都不死,那么一年以后可以繁殖多少对兔子?
分析如下:
第一个月小兔子没有繁殖能力,所以还是一对;
两个月后,生下一对小兔子,总数共有两对;
三个月以后,老兔子又生下一对,因为小兔子还没有繁殖能力,总数共是三对;
……
long Fib(int n)
{
if (n == 0)
return 0;
if (n == 1)
return 1;
if (n > 1)
return Fib(n-1) + Fib(n-2);
}4)汉诺塔问题(经典)
有三个塔(分别为A号,B号和C号)。开始时.有n个圆形盘以从下到上、从大到小的次序叠置在A塔上。现要将A塔上的所有圆形盘,借助B搭,全部移动到C搭上。且仍按照原来的次序叠置。
移动的规则如下:
这些圆形盘只能在3个塔问进行移动.一次只能移动一个盘子,且任何时候都不允许将较大的盘子压在比它小的盘子的上面。
如果有2个盘子,可以先将盘子1上的盘子2移动到B;将盘子1移动到c;将盘子2移动到c。这说明了:可以借助B将2个盘子从A移动到C,当然,也可以借助C将2个盘子从A移动到B。
如果有3个盘子,那么根据2个盘子的结论,可以借助c将盘子1上的两个盘子从A移动到B;将盘子1从A移动到C,A变成空座;借助A座,将B上的两个盘子移动到C。这说明:可以借助一个空座,将3个盘子从一个座移动到另一个。
- 如果有4个盘子,那么首先借助空座C,将盘子1上的三个盘子从A移动到B;将盘子1移动到C,A变成空座;借助空座A,将B座上的三个盘子移动到C。
定义一个递归方法Hannoita(int N,char A,char B,char C)[这里的N代表移动的盘数,A表示盘子来源的塔,B表示移动时借助的塔,C表示盘子要移动到的目标塔]
设初始盘子个数为N
▲若A塔上仅仅只有一个盘子(N=1),则直接从A移动到C问题完全解决。
▲若A塔上有一个以上的盘子(N>1),则进行如下操作:
1.先把(n-1)个盘子从A塔经过移动,叠放到B塔上。在不违反规则情况下,所有(N一1)个盘子不能作为一个整体一起移动,而是要符合要求地从一个塔移到另一个塔上。
2.用Hannoita(N-1,A, C,B)调用递归方法,注意:这里是借助于C塔,将(N一1)个盘子从A塔移动到B塔,A是源塔,B是目标塔。
3.将剩下的第N个盘子(也就是最底下的一个)直接从A塔叠放到空着的C塔上。
4.用第一步的方法,再次将B塔上的所有盘子叠放到C塔上。同样,这一步实际上也是由一系列更小的符合规则的移动盘子的操作组成的,用Hannoita(N一1,B,A,C)调用递归方法【注意:这里是借助于A塔,将(N—1)个盘子从B塔移动到C塔,B是源塔,C是目标塔】
public static void Hannoita(int n, char A, char B, char C){
/*递归结束*/
if (n == 1){
System.out.println("n=" + n + " " + A + "-->" + C);
}else{
/*递归调用*/
Hannoita(n-1,A,C,B);
System.out.println("n=" + n + " " + A + "-->" + C);
Hannoita(n-1, B, A, C);
}
}
public static void main(String[] args) {
HannoitaProblem.Hannoita(3, 'A', 'B', 'C');
}
本文深入解析了递归和分治算法的概念、特点及其在解决实际问题中的应用,通过阶乘计算、欧几里德算法求最大公约数、斐波那契数列、汉诺塔问题等典型例子,展示了递归与分治法的实用性和高效性。同时,文章还介绍了如何结合使用递归和分治法解决复杂问题,并提供了相应的代码实现。
282

被折叠的 条评论
为什么被折叠?



