--- title: "递归" date: 2022-05-10T09:10:48+08:00 --- * 递归技术 * 直接或间接地调用自身的算法称为递归算法 * 用函数自身给出定义的函数称为递归函数 * 每个递归函数都必须有非递归定义的初始值,否则递归函数无法计算 --------------------- * 阶乘函数 * 可递归地定义为$n!= \begin{cases}1,& \text{n=0} \\\\ n(n-1)!,&\text{n>0} \end{cases}$ ```java public static int Factorial(int n){ if(n==0) return 1; return n*Factorial(n-1); } ----------------------- * Fibonacci数列 * 可递归地定义为$F(n)=\begin{cases}1, &\text{n=0},1 \\\\ F(n-1)+F(n-2) &\text{n>1} \end{cases}$ ```java public static int fibonacci(int n){ if(n<=1) return 1; return fibonacci(n-1)+fibonacci(n-2); } ---------------------------- * 排列问题 * 当$n=1时,perm(R)=(r)$,其中r是集合R中唯一的元素; * $当n>1时,perm(R)=(r)$ $perm(R)由(r_1)perm(R_1),(r_2)perm(R_2),\cdots,(r_n)perm(R_n)构成$ * 算法perm(list,k,m)递归地产生所有前缀是list[0:k-1],且后缀是list[k:m]的全排列的所有排列。调用perm(list,0,n-1)即产生list[0:n-1]的全排列 * 一般情况下,$k1$时,需要利用塔座c作为辅助塔座, * 将$n-1$个较小的圆盘依照移动规则从塔座a移至塔座c, * 将剩下的最大圆盘从塔座a移至塔座b, * 将$n-1$个较小的圆盘依照移动规则从塔座c移至塔座b ```java public static void hanoi(int n,char a,char b,char c){ if(n>0){ hanoi(n-1, a, c, b); move(n,a,b); hanoi(n-1,c,b,a); } } public static void move(int n,char a,char b){ System.out.println("第"+n+"个盘子从"+a+"--->"+b); } ``` * 递归调用总结和系统原理 * 实现递归调用的关键:为算法建立递归调用工作栈 * 运行被调用算法前的行为 * 为所有实参指针,返回地址等信息传递给被调用算法 * 为被调用算法的局部变量分配存储区 * 将控制转移到被调用算法的入口 * 从被调用算法返回调用算法时 * 保存被调用算法的计算结果 * 释放分配给被调用算法的数据区 * 依照被调用算法保存的返回地址将控制转移到调用算法 * 嵌套调用时的系统原则:后调用先返回,即算法间的信息传递和控制转移通过栈来实现 * 递归算法的调用层次 * 调用一个递归算法的主算法为第0层算法 * 从主算法调用递归算法为进入第1层调用 * 从第i层递归调用本算法为进入第i+1层调用。 * 退出第i层递归调用,则返回至i-1层调用。 * 递归调用的栈使用情况示意 | 主算法栈块 | | :---------------------------: | | M | | 主算法调用递归算法A的栈块 | | 算法A的第一层递归调用工作记录 | | 算法A的第二层递归调用工作记录 | | TOP | | M |