一)递归介绍
定义:
1、在函数体中直接或间接的调用自身的一种方法。
2、必须要有边界值,也就是停止的条件。
头递归:函数调用时不是传递本次计算的结果,而是把当前的调用状态传递,相当于要一直记录上一次函数的调用状态。这种方式会耗内存资源,当计算的值较大,递归层次较深时,容易报内存错误。
尾递归:函数调用时传递本次计算的结果,不需要记录函数的调用状态,由于一直是在尾部计算,大大减少了资源占用。
备注:递归也不是能无限计算下去的,只要是计算,就会有计算瓶颈限制。如果要一直计算,递归和死循环就差不多了。
二)递归案例
(一)计算球的反弹高度和总路径?
描述:一个球从100米高度自由落下,每次落地后反跳回原高度的一半;再落下,求它在第10次落地时,共经过多少米?第10次反弹多高?
普通方式:h代表初始高度,n代表反弹次数
public static double fn(double h, int n) {if (h<=0 || n<=0) {return 0;}double sum = 0;while (n>0) {sum += h;h = h/2;n--;}return sum;
}
尾递归方式(该案例不适合用头递归):
h代表初始高度,n代表反弹次数(如需计算第10次总高度,n=11,因为每次是先减1,再求和),sum表示总共的高度。
// h代表初始高度,n代表反弹次数(如需计算第10次总高度,n=11,因为每次是先减1,再求和),sum表示总共的高度
public static double fn(double h, int n, double sum) {if (h<=0 || n<=0) {return 0;}if (n <= 1) {return sum;}return fn(h/2, n-1, sum + h);
}
计算并分解的步骤如下:
高度 次数 总共米数
fn(100, 10, 0)
fn(50.0, 9, 100.0)
fn(25.0, 8, 150.0)
fn(12.5, 7, 175.0)
fn(6.25, 6, 187.5)
fn(3.125, 5, 193.75)
fn(1.5625, 4, 196.875)
fn(0.78125, 3, 198.4375)
fn(0.390625, 2, 199.21875)
fn(0.1953125, 1, 199.609375)
总共经过199.609375米,第10次反弹高度为0.1953125
(二)阶乘计算
描述:计算从1到n每个数相乘的结果。公式:1*2*3*4*......*n的结果。
普通方式:
public static int fn(int n) {int sum = 1;for(int i=1; i<n; i++) {sum = sum * (i+1);}return sum;
}
头递归方式:
public static int fn(int n) {return n==0 ? 1 : n * fn(n-1);
}
假设n=5,计算并分解的步骤如下:
fn(5)
{5 * fn(5-1)}
{5 * {4 * fn(4-1)}}
{5 * {4 * {3 * fn(3-1)}}}
{5 * {4 * {3 * {2 * fn(2-1)}}}}
{5 * {4 * {3 * {2 * {1 * fn(1-1)}}}}}
{5 * {4 * {3 * {2 * {1 * 1}}}}}
{5 * {4 * {3 * {2 * 1}}}}
{5 * {4 * {3 * 2}}}
{5 * {4 * 6}}
{5 * 24}
{120}
结果返回120
尾递归方式:
public static int fn(int n, int sum) {return n == 0 ? sum : fn(n-1, n*sum);
}
假设n=5,sum初始为1(如果是阶加,初始为0)
计算并分解的步骤如下:
fn(5, 1)
fn(4, 5)
fn(3, 20)
fn(2, 60)
fn(1, 120)
结果返回sum=120
(三)斐波那契数列
描述:斐波那契数列,数列为1,1,2,3,5,8,13,21......n,每一个数是前面两个数之和,计算第n个数是多少。
普通方式:
public static int fn(int n) {int a = 1;int b = 1;int num = 0;for (int i=2; i<n; i++) {num = a+b;a = b;b = num;}return num;
}
头递归方式:
public static int fn(int n) {return n<=2 ? 1 : fn(n-1) + fn(n-2);
}
假设n=6,计算并分解的步骤如下:
fn(6)
{fn(5) + fn(4)}
{fn(4) + fn(3) + {fn(3) + fn(2)}
{fn(3) + fn(2) + fn(2) + fn(1) + fn(2) + fn(1) + 1}
{fn(2) + fn(1) + 1 + 1 + 1 +1 + 1 + 1}
{1+ 1 + 1 + 1 + 1 +1 + 1 + 1}
第6个数结果为:8
尾递归方式:
// 写法一:假设n等8, n = fn1(8, 1, 1);
public static int fn1(int n, int num1, int num2) {return n == 1 ? num1 : fn1(n - 1, num2, num1 + num2);
}// 写法二:假设n等8, n = fn2(1, 1, 8);
public static int fn2(int first, int second, int n) {return n < 3 ? second : fn2(second, first + second, n - 1);
}
假设n=6,计算并分解的步骤如下:
fn2(1, 1, 6)
fn2(1, 2, 5)
fn2(2, 3, 4)
fn2(3, 5, 3)
fn2(5, 8, 2)
第6个数结果为:8
识别二维码关注个人微信公众号
本章完结,待续,欢迎转载!
本文说明:该文章属于原创,如需转载,请标明文章转载来源!