递归算法的简单理解
递归算法
程序调用自身的编程技巧称为递归( recursion)。递归做为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。
递归算法两大要素
1.确定递归公式
2.确定边界(终了)条件
帮助理解小案例(java实现)
求数组中的最大数
RecursionMaxArrayTest.java
/**
* java递归方法求数组最大元素
* 思路:拿比较后的前两个元素去和第三个元素比较......以此类推求出最大值
* @author Scen
* @date 2018/11/5 11:04
*/
public class RecursionMaxArrayTest {
public static void main(String[] args) {
int[] array = {6, 1, 5, 4, 8, 3, 9, 12, 51, 11, 15, 14, 13, 25, 69, 47, 56, 74, 26, 78};
System.out.print(maxNum(array,array.length-1));
}
private static int max(int a, int b) {
return a > b ? a : b;
}
private static int maxNum(int[] arr, int endIndex) {
// 边界
if (endIndex == 0) {
return arr[0];
}
// 递归公式
return max(arr[endIndex], maxNum(arr, endIndex - 1));
}
}
对1+2+3+…+n进行求和
Recursion12nTest.java
/**
* java递归实现1+2+3+...+n
* 思路:拿第一个元素和第二个元素的和去加第三个元素...以此类推
* @author Scen
* @date 2018/11/5 11:29
*/
public class Recursion12nTest {
public static void main(String[] args) {
System.out.println(sum12n(100));
}
private static int sum(int a, int b) {
return a + b;
}
private static int sum12n(int n) {
// 边界
if (n == 0) {
return 0;
}
// 递归公式
return sum(n, sum12n(n-1));
}
}
求n个整数的积
RecursionProductTest.java
/**
* java递归实现求n个整数的积
* 思路:拿第一个元素和第二个元素的乘积去乘以第三个元素...以此类推
* @author Scen
* @date 2018/11/5 11:46
*/
public class RecursionProductTest {
public static void main(String[] args) {
int[] n = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
System.out.println(productN(n, n.length - 1));
}
private static int product(int a, int b) {
return a * b;
}
private static int productN(int[] arr, int endIndex) {
if (endIndex < 0) {
return 1;
}
return product(arr[endIndex], productN(arr, endIndex - 1));
}
}
求n个整数的平均值
RecursionAveragetTest.java
/**
* java递归求n个整数的平均值
* 思路:求和后除以个数
* @author Scen
* @date 2018/11/5 12:00
*/
public class RecursionAveragetTest {
public static void main(String[] args) {
int[] array = {1,2,3,4,9};
System.out.println(averageN(array, 0, 0));
}
private static float averageN(int[] a, float sum, int index) {
// 边界
if (index ==a.length) {
return sum/index;
}
// 递归公式
return averageN(a, sum += a[index], index + 1);
}
}
求n个自然数的最大公约数与最小公倍数
RecursionGcdAndLcmTest.java
/**
* java求n个自然数的最大公约数与最小公倍数
* 思路:拿第一个元素和第二个元素的最大公约数(最小公倍数)去和第三个元素进行求取运算
* ...以此类推
* @author Scen
* @date 2018/11/5 15:53
*/
public class RecursionGcdAndLcmTest {
public static void main(String[] args) {
int[] arr = {3,5,7};
System.out.println(gcdN(arr,arr.length));
System.out.println(lcmN(arr,arr.length));
}
private static int gcd(int m, int n) {
if (m < n) {
int temp = m;
m = n;
n = temp;
}
// 边界
if (n == 0) {
return m;
}
// 递归公式
return gcd(n, m % n);
}
private static int lcm(int m, int n) {
return m * n / gcd(m, n);
}
private static int gcdN(int[] a, int endIndex) {
// 边界
if (endIndex == 0) {
return a[0];
}
// 递归公式
return gcd(a[endIndex-1], gcdN(a, endIndex-1));
}
private static int lcmN(int[] a, int endIndex) {
// 边界
if (endIndex == 0) {
return a[0];
}
// 递归公式
return lcm(a[endIndex - 1], lcmN(a, endIndex - 1));
}
}
有一对雌雄兔,每两个月就繁殖雌雄各一对兔子.问n个月后共有多少对兔子(斐波拉契数列)
RecursionFibonacciTest.java
/**
* 有一对雌雄兔,每两个月就繁殖雌雄各一对兔子.问n个月后共有多少对兔子(斐波拉契数列)
* 思路:把问题抽象成一个函数f(n)=f(n-1)+f(n-2)(n>=3)
* @author Scen
* @date 2018/11/5 17:25
*/
public class RecursionFibonacciTest {
public static void main(String[] args) {
System.out.println(fibonacci(12));
}
public static int fibonacci(int n) {
// 边界
if (n < 3) {
return 1;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
}
已知:数列1,1,2,4,7,13,24,44,…求数列的第 n项.
RecursionSequenceTest.java
/**
* java已知:数列1,1,2,4,7,13,24,44,...求数列的第 n项.
* 思路:把问题抽象成一个函数f(n)=f(n-1)+f(n-2)+f(n-3)(n>=4)
* @author Scen
* @date 2018/11/5 18:48
*/
public class RecursionSequenceTest {
public static void main(String[] args) {
System.out.println(sequence(8));
}
private static int sequence(int n) {
if (n < 4) {
switch (n) {
case 3:
return 2;
default:
return 1;
}
}
return sequence(n - 1) + sequence(n - 2) + sequence(n - 3);
}
}