zoukankan      html  css  js  c++  java
  • 递归的正确切入方法

    一、递归的定义

    定义: 当函数直接或者间接调用自己时,则发生了递归。

    二、理解递归

    先举个递归在阶乘中的例子:阶乘的定义: “一个正整数的阶乘是所有小于或等于该数的正整数的积,并且0的阶乘为1。”

    以下是C++的实现:

    int factorial(int n)
    {
    	if(n <= 1)
    		return 0;
    	else
    		return n * factorial(n-1);
    	
    }
    

     分析:我们很容易判断当n = 某个较小数值时这个阶乘的递归计算是否是正确。比如当n = 4时, 那么factoria(4)等于4 * factoria(3), 而factoria(3)等于3 * factoria(2)factoria(2)等于2 * factoria(1),等于2 * 1,所以factoria(4)等于4 * 3 * 2 * 1。


    反思:这种分析已经有点门路了,可是怎么拓展到一般情况呢?

    Paul Graham提到一种方法, 给我很大启发, 该方法如下:

    1. 当n=0,1的时候,结果正确;
    2. 假设函数对于n是正确的, 函数对n+1结果也正确。
    3. 如果这两点是成立的,我们知道这个函数对于所有可能的n都是正确的。

    这种方法很像数学归纳法, 也是递归正确的思考方式, 事实上, 阶乘的递归表达方式就是1! = 1,n! = (n-1)! × n,当程序实现符合算法描述的时候, 程序自然对了, 假如还不对, 那是算法本身错了…… 相对来说,n,n+1的情况为通用情况, 虽然比较复杂, 但是还能理解, 最重要的, 也是最容易被新手忽略的问题在于第1点, 也就是基本用例(base case)要对. 比如, 上例中, 我们去掉if(n<=1)的判断后, 代码会进入死循环, 永远不会结束。

     

    三、寻找问题的递归算法

     

    在解题时,想运用递归却无从下手?

    你只需要做两件事情:

    1. 示范如何解决问题的一般情况, 通过将问题切分成有限小并更小的子问题;
    2. 示范如何通过有限的步骤,来解决最小的问题(基本用例);
    3. 因为递归每次都将问题变得更小,而一个有限的问题终究会被解决的,而最小的问题仅需几个有限的步骤就能解决。

    四、实战运用

     

    汉诺塔问题:有三根杆子A,B,C。A杆上有N个(N>1)穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至C杆:1.每次只能移动一个圆盘;2.大盘不能叠在小盘上面。

     

    如何使用递归?

    一般情况:
    当有N个圆盘在A上,我们已经找到办法将其移到C杆上了,我们怎么移动N+1个圆盘到C杆上呢? 很简单, 我们首先用将N个圆盘移动到C上的方法将N个圆盘都移动到B上, 然后再把第N+1个圆盘(最后一个)移动到C上, 再用同样的方法将在B杆上的N个圆盘移动到C上。问题解决。

    基本用例:
    当有1个圆盘在A上,我们直接把圆盘移动到C上即可。

     

    C++代码:

     1 // 汉诺塔
     2 # include  <stdio.h>
     3 void hanoi ( int n, char a,  char b,  char c )         //这里代表将a柱子上的盘子借助b柱子移动到c柱子
     4   {  if  (1 == n)                                          //如果是一个盘子直接将a柱子上的盘子移动到c
     5          {
     6             printf("%c-->%c
    ",a,c);
     7           }
     8        else
     9            {
    10              hanoi ( n-1,  a,  c,  b ) ;                  //将a柱子上n-1个盘子借助c柱子,移动到b柱子
    11              printf("%c-->%c
    ",a , c) ;               //再直接将a柱子上的最后一个盘子移动到c
    12              hanoi ( n-1,  b,  a,  c ) ;                  //然后将b柱子上的n-1个盘子借助a移动到c
    13           }
    14   }
    15 int main ()
    16   {  int  n ;
    17       printf( "Input the number of diskes:") ;
    18       scanf("%d",&n) ;
    19       hanoi ( n,  'A' ,  'B' , 'C' ) ;
    20       return 0;
    21   }

     

  • 相关阅读:
    C# 使用自带Microsoft.Office.Interop.Excel简单操作Excel文件
    Winform修改配置文件节点保存到配置文件
    C# MD5加密字符串
    dev gridcontrol简单的动态设置动态表头
    dev gridcontrol绘制页脚
    dev gridcontrol 导出到excel
    dev gridcontrol设置过滤器下拉列表
    为什么要使用Unix时间戳
    DataTable和DataReader的遍历
    C#生成不重复随机数的方法
  • 原文地址:https://www.cnblogs.com/xzxl/p/7223145.html
Copyright © 2011-2022 走看看