zoukankan      html  css  js  c++  java
  • 递归

    递归

      从程序设计的角度看,递归是一种程序设计方法。函数直接或间接地调用自身,称为递归调用。递归调用是用相同的策略去解决规模更小的问题,直至问题规模达到某个边界条件时,不再进行递归调用,而是直接处理。

      函数递归调用的嵌套层数称为递归层次。其中,其他函数对递归函数的调用为第0层,递归函数第一次调用自身为第1层......以此类推。递归函数的执行过程为:

      1. 执行第n-1(n>0)层的代码到调用递归函数时,进入第n层,执行第n层递归函数的代码。

      2. 第n(n>0)层递归函数的执行结果返回到第n-1层,之后执行第n-1层调用递归函数之后的代码。

      编写递归函数时需要注意:

      1. 递归函数传入引用类型的数据时会改变数据本身。

      2. 递归必须设置退出条件,而且每次递归时都是向退出条件逼近,否则就变成了无限递归,最终会出现StackOverflowError。

    阶乘

      阶乘的定义是:n! = 1 * 2 * 3 * ... * n。特别的有,0! = 1。

      根据阶乘的定义,可以得到n! = n * (n - 1)!。也就是说,n的阶乘可以通过先求n - 1的阶乘再乘以n得到。所以可以通过递归实现求一个数的阶乘,而递归的退出条件即为n == 0时返回1。

    1 public static int factorial(int n) {
    2     if (n == 0) return 1;
    3     return n * factorial(n - 1);
    4 }
    factorial

    最大公因数

      求a和b(a ≥ b)的最大公因数的过程为:

      a = b * q1 + r1

      b = r1 * q2 + r2

      r1 = r2 * q3 + r3

      ...

      rn-2 = rn-1 * qn-1 + rn

      rn-1 = rn * qn

      可以发现,上一个式子的除数和余数分别是当前式子的被除数和除数。直到出现一个式子的余数为0时,该式子的除数即为最大公因数。这种求最大公因数的方式称为辗转相除法。

      特别的,任何一个数和0的最大公因数都是这个数本身。

      可以通过递归实现辗转相除法求最大公因数,而递归的退出条件即为除数为0,此时被除数为最大公因数。

    1 public static int gcd(int a, int b) {
    2     if (a < b) return gcd(b, a);
    3     if (b == 0) return a;
    4     return gcd(b, a % b);
    5 }
    gcd

    斐波那契数列

      1, 1, 2, 3, 5, 8, 13, ...这个数列被称为斐波那契数列。斐波那契数列的特点是:从第3项开始,当前项为前两项之和。所以斐波那契数列的递推公式为:F(n) = F(n - 1) + F(n - 2)。

      求斐波那契数列第n项的数值,可以转变为求其第n-1项和第n-2项的数值之和。可以通过递归来实现该功能,而退出条件即为n == 1和n == 2时返回都为1。

    1 public static int fibonacci(int n) {
    2     if (n == 1 || n == 2) return 1;
    3     return fibonacci(n - 1) + fibonacci(n - 2);
    4 }
    fibonacci

    汉诺塔问题

      汉诺塔游戏(http://www.4399.com/flash/109504.htm#sim2|109504):有三根柱子,其中第一根柱子上有n个圆环,越往下的圆环越大。

      游戏任务:将第一根柱子上的所有圆环移动到第三根柱子上。

      游戏规则:每次移动都是移动最上面的圆环,且必须保证每次都是小环在上大环在下。

      例如,移动3个圆环,效果如图所示:

      

      移动n(n > 0)个圆环的一般步骤如下:

      a. 将n - 1个圆环从第一根柱子移到第二根柱子。

      b. 将第n个圆环从第一根柱子移动到第三根柱子。

      c. 将n - 1个圆环从第二根柱子移动到第三根柱子。

      所以,可以通过递归实现汉诺塔。而递归退出的条件则为n == 1时结束。

     1 public static void hanoi(int n, char a, char b, char c) {
     2     if (n == 1) {
     3         // 1个圆环,直接从第一根柱子移动到第三根柱子
     4         System.out.println("第" + n + "个圆环从第" + a + "根柱子移动到第" + c + "根柱子。");
     5     } else {
     6         // 将n - 1个圆环从第一根柱子移动到第二根柱子上
     7         hanoi(n - 1, a, c, b);
     8         // 将第n个圆环从第一根柱子移动到第三根柱子上
     9         System.out.println("第" + n + "个圆环从第" + a + "根柱子移动到第" + c + "根柱子。");
    10         // 将n - 1个圆环从第二根柱子移动到第三根柱子上
    11         hanoi(n - 1, b, a, c);
    12     }
    13 }
    hanoi

      测试3个圆环的输出结果:

      

    八皇后问题

      八皇后游戏(http://www.7k7k.com/swf/49842.htm):有一个8*8的棋盘和8个皇后棋子

      游戏任务:在棋盘上摆放8个皇后。

      游戏规则:摆放的8个皇后不能相互攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上。

      摆放第n个皇后的一般步骤如下:

      a. 摆放在第n行的位置上。

      b. 判断是否可以摆放在这个位置上,即摆放后是否依然满足皇后不会相互攻击。

      c. 如果第n行上没有一个位置使得n个皇后不会相互攻击,证明第n - 1个皇后摆放的位置不正确,需要改变位置。

      八皇后问题可以通过递归实现,递归的退出条件为成功摆放最后一个皇后。

    1 public static boolean check(int[] bound, int x) {
    2     for (int i = 0; i < x; i++) {
    3         // bound[i] == bound[x]表示两个皇后在同一列,x - i == |bound[x] - bound(i)|表示两个皇后在同一斜线
    4         if (bound[i] == bound[x] || x - i == Math.abs(bound[x] - bound[i])) return false;
    5     }
    6     return true;
    7 }
    check
     1 public static int put(int[] bound, int n) {
     2     int count = 0;
     3     for (int i = 0; i < 8; i++) {
     4         bound[n] = i;
     5         if (check(bound, n)) {
     6             // n == 7表示已经成功摆上最后一个皇后,该条件作为递归的退出条件
     7             if (n == 7) {
     8                 count++;
     9                 for (int index : bound) 
    10                     System.out.print((index + 1) + " ");
    11                 System.out.println();
    12             } else {
    13                 count += put(bound, n + 1);
    14             }
    15         }
    16     }
    17     return count;
    18 }
    put

      其中,check()方法用于判断摆放皇后的位置是否正确;put()方法用于计算8皇后摆放方案。

      通过测试,得到结果如下:

      

      可以看到,八皇后一共有92种摆法。以“5 1 4 6 8 2 7 3”为例,“5”表示第一个皇后摆放在第1行的第5个位置,“6”表示第四个皇后摆放在第4行的第6个位置......

      

  • 相关阅读:
    摘记
    【题解】网格 & Single Cut of Failure(trick:答案上界)
    题解 CF1404C 【Fixed Point Removal】
    Linux IO模型知识梳理
    Java IO模型知识梳理
    如何回答什么是线程安全?
    MySQL主从复制与备份
    MySQL的高性能索引策略
    CAS(乐观锁)的原理解析
    Java虚拟机的类加载机制
  • 原文地址:https://www.cnblogs.com/lqkStudy/p/11547943.html
Copyright © 2011-2022 走看看