递归小记

Posted carblack

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了递归小记相关的知识,希望对你有一定的参考价值。

在非负集定义一个函数f,满足f(0) = 0 且 f(x) = 2f(x-1) + x^2,可以看出f(1) = 1,f(2) = 6,f(3) = 21,当一个函数用自己来定义时就称为递归函数,java中允许函数递归

1 public int f(int x){
2         if(x == 0){
3             return 0;
4         }else{
5             int b = 2*f(x-1)+ x*x; //递归调用
6             return b;
7         }
8     }

递归是一种循环推理,例如我们想得到f(4)的值,那么第6行要计算2*f(3)+4*4,得到f(3)需要计算2*f(2)+3*3,得到f(2)需要计算2*f(1)+2*2,计算f(1)需要计算2*f(0)+1*1,f(0) = 0是已知基准情况,从而得出结果f(1) = 1,f(2) = 6,f(3) = 21,f(4) = 58,这样的情况就是循环推理。

递归的基本法则:基准情形,不用递归就可以求解

        不断推进,递归调用总能向着一个基准情形前进

        设计法则,假设所有递归调用都能运行

        合成效益法则,求解一个问题的同一实例时,切勿在不同的递归调用中做重复的工作

 

2、实践

(1)求和:1+2+3+.....+n

/**
* 求和,程序实现是从基准情形f(0) =0逆序相加,0+1+2+3+.....+(n-1)+n
* @param n
* @return
*/
public int f1(int n){
int b = 0;
if(n == 0 ){
return 0;
}else {
b = n + f1(n-1);
return b;
}
}

(2)阶乘:n! = n * (n-1) * (n-2) * ...* 1(n>0)

/**
     * 阶乘,程序实现是从基准情形f(1) =1逆序相乘,1*2*3*4*.....*(n-1)*n
     * @param n
     * @return
     */
    public int f2 (int n){
        int b = 0;
        if( n == 1){
            return 1;
        }else {
            b = n * f2(n-1);
        }
        return b;
    } 

(3)河内塔问题:

技术图片

 

 

 借助2号杆把1号杆上的珠子转移到3号杆上且顺序不变,一次只能移动一个珠子且大珠子不能在小珠子上面,最少需要移动多少次?

/**
     * 河内塔问题,最少移动2^n-1次,f3(1) = 1,f(2) = 3,f(3) = 7,f(4) = 15
     * 假如只有1个穿孔圆盘,就需要移动1次。 A→C 1 次
     * 假如只有2个穿孔圆盘,就需要移动3次。A→B, A→C,B→C 3次
     * 假如只有3个穿孔圆盘,这时我们可以将上面的2个圆盘看做是一个整体,也就是将3分解成1+2.来考虑。
   * 如我们将最大的第三个圆盘,取消,只剩2个圆盘,这时借助C柱,移动3次可以让2个圆盘到从A到B柱。再考虑最大的圆盘,移动最大的第三个圆盘到C柱。这时借助A柱,移动3次可以让2个圆盘从B到C柱。就需要移动7次。 * @param n * @param a 1号柱 * @param b 2号柱 * @param c 3号柱 */ public void f3(int n, String a, String b, String c) { if(1 == n) { System.out.println(a + "->" + c); } else{ f3(n-1, a, c, b); System.out.println(a + "->" + c); f3 (n-1, b, a, c); } } public int f3_1(int n){ int b = 0; if(n == 1){ return 1; }else{ b = 2*f3_1(n-1)+1; return b; } }

(4)斐波那契数列:1、1、2、3、5、8、13、21、……

/**
*斐波那契数列,n=1和n=2两种基准情形,n=3开始,后一个数等于前两个数相加的和,f4(3) = f(2) + f(1)
* @param n
* @return
*/
public int f4(int n){
int b = 0;
if (n ==1 ){
return 1;
}else if(n == 2){
return 1;
}else {
b = f4(n-1)+f4(n-2);
return b;
}
}

(5)全排列:从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。

        如1,2,3三个元素的全排列为:1,2,3、1,3,2、2,1,3、2,3,1、3,1,2、 3,2,1 

    /**
     * 全排列,对数组中的数进行循环换位,输出
     * @param arr 输入数组
     * @param start 起始位置
     * @param end 结束位置,arr.length-1
     * @return
     */
    public void f5(int[] arr, int start, int end){
        // 递归终止条件
        if (start == end) {
            //循环遍历
            for (int i : arr) {
                System.out.print(i);
            }
            System.out.println();
            return;
        }
        for (int i = start; i <= end; i++) {
            swap(arr, i, start);
            f5(arr, start + 1, end);
            swap(arr, i, start);
        }
    }
    private  void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

    /**
     *全排列的数量,就是数组长度的阶乘,n=1 num=1,n=2 num=1*2=2,n=3 num =1*2*3=6;n=4 num=1*2*3*4=21.......
     * @param arr
     * @return
     */
    public int f5_1(int[] arr){
        int num = 0;
        num = f5_1_1(arr.length);
        return num;
    }
    public int f5_1_1(int n){
        if(n == 1){
            return 1;
        }else{
            return n * f5_1_1(n-1);
        }
    }

  

以上是关于递归小记的主要内容,如果未能解决你的问题,请参考以下文章

算法课程小记—递归(整数划分问题)

PHP-数组小记

2018.07.29(搜索)学习DFS算法小记

JavaScript - 代码片段,Snippets,Gist

CSP核心代码片段记录

executePendingTransactions 的递归入口