zoukankan      html  css  js  c++  java
  • 利用数学归纳法指导编写递归程序

    本人的第一篇博客,纯原创,部分内容参考下面两位博主的文章,鸣谢!

    https://www.cnblogs.com/GODYCA/archive/2013/01/15/2861545.html

    https://www.cnblogs.com/LiCheng-/p/8206444.html (这篇文章写的不是很好,因为博文提到“每次问题规模缩小程度必须为1”,而事实上我在查阅资料时,这是需要根据实际情况确定的,比如”二分查找法”就是最好的例子,每次问题规模缩小程度就是一半)

      关于递归,今天逛园子的时候偶然发现的,一篇关于利用数学归纳法指导编写递归程序的博文,启发了我。但博主的文章写的不是那么好理解,于是我又琢磨了一下午,参考了别的资料,写了三个例子帮助自己理解。

    关于数学归纳法,先看看是怎么回事:

    一般地,证明一个与自然数n有关的命题P(n),有如下步骤:

    (1)证明当n取第一个值n0时命题成立。n0对于一般数列取值为0或1,但也有特殊情况;

    (2)假设当n=k(k≥n0,k为自然数)时命题成立,证明当n=k+1时命题也成立。

    综合(1)(2),对一切自然数n(≥n0),命题P(n)都成立。

     

    举个例子:

    已知N!=N*(N-1)*(N-2)*(N-3)*…*2*1,求证R(N)与R(N-1)之间的关系!

    第一步当N=1时可知 N!=1

    第二步设当R(N)=N!,R(N-1)=(N-1)!

    第三步,求R(N)与R(N-1)之间的关系:

    因为R(N-1)=(N-1)!= (N-1)*…*2*1=> R(N)=N*R(N-1)

    即:R(N)=N*R(N-1) 

    写成一个函数求N!的值:

     factorial (int N)
        {

           if(N==1) return 1;        /*    特殊部分    */

           return N * factorial (N - 1)        /*    递归部分    */

        }

    上面这个例子,利用数学归纳法得到R(N)=N*R(N-1) 的关系式恰好是递归写法的核心(通用)部分,而递归返回(特殊)部分为 if(N==1) return 1 语句。

    那么编写递归程序就有指导思想:首先分析得到问题解决的通用处理步骤(规律),再处理递归返回(特殊)部分

     

    下面看看三个例子帮助消化:

    第一个例子(自己碰到的面试题,当时写不好,现在一下子就写出了):

    现有如下关系:1、1、2、3、5、8、13…请用递归求出第150位数字的值?

    分析:对于8=5+3,对于5=3+2,对于2=1+1,即第n位=第n-1位+第n-2位,其中n>2

             而对于第1位、第2位时,他们的值都是一样,即为1.

    那我们可以很容易就可以写出来:

           int IndexNum (int n)

            {

                if(n==1||n==2)

                {

                    return 1;

                }

                return IndexNum(n - 1) + IndexNum(n - 2);

            }

     

    第二个例子,汉诺塔的实现,这个也很有意思(虽然书上很多):

     

      汉诺塔:三个立柱(命名为from、temp、to,from为圆盘初始所在立柱、to是目标立柱),N个直径不相等的圆盘,将圆盘从from上一个一个移动在to上,要求,每次只能移动一个圆盘,而且只能在三个立柱之间移动。目标柱to不能出现大盘压小盘的情况。

     

     首先用数学归纳法分析:


    当只有一个圆盘的时候,我们可以确定:

    直接将圆盘从from移动到to上:           move (n, from, to); 

     

    现在假设有N个圆盘在from上,则需要进行如下操作:

    首先需要将from上N-1个盘移动到temp上:   Hanoi (n-1, from, temp);

    然后将from上的第N个盘移到to:           move (n, from, to);    

    最后再将temp上N-1个盘移到to上:         Hanoi (n-1, temp, to); 

     

    设Hanoi (int n, int from, int temp, int to)函数就是我们要求的汉诺塔实现函数,意义是将按直径递增摞在一起的n个圆盘从from按要求移动到to上,temp为辅助柱。

     

    写出代码即:

    void Hanoi (int n, int from, int temp, int to)

    {

      if (n == 1)

      {

        move (n, from, to);

      }

      else

      {

        Hanoi (n-1, from, to, temp);

        move (n, from, to);

        Hanoi (n-1, temp, from, to);

      }

    }

    上面的代码,也同样包含通用规律,特殊部分即是递归的返回部分。

     

    再看第三个例子,关于建立单向链表关系:

    假设有节点,定义如下:

    class node

    {

         public int Num { get; set; }                 //序号

         public node next { get; set; }             //指向的下一个节点

     

         public node(int num)

         {

                Num = num;

         }

    }

    现在有数组nodes如下:

    node[] nodes = new node[5];

    nodes[0] = new node(2);

    nodes[1] = new node(4);

    nodes[2] = new node(1);

    nodes[3] = new node(3);

    nodes[4] = new node(9);

    需将他们建立单向链关系:

     

    首先分析:对于数组第n个节点,有nodes[n].next = nodes[n+1]的通用关系;

                    对于最后一个节点,有nodes[4].next = null

    那我们可以这么写:

    void CreatLink(node[]data, int n)

    {

         if (n >= data.Length-1)

         {

             data[n] = null;

             return;

         }else

         {

             data[n].next = data[n + 1];

             CreatLink(data, n + 1);

         }

    }

    初步总结:对于编写递归程序,首先是得到其通用的处理步骤(规律),然后再分析其特殊部分,而特殊部分往往是递归函数返回(闭环)的关键。

  • 相关阅读:
    2019天梯赛训练1
    Python课程设计 搭建博客
    最容易理解的贪吃蛇小游戏
    数据结构-队列
    数据结构-堆栈(2)
    数据结构-堆栈(1)
    数据结构-线性表(3)
    数据结构-线性表(1)
    linux知识积累
    Maven学习笔记
  • 原文地址:https://www.cnblogs.com/iDream2018/p/8215116.html
Copyright © 2011-2022 走看看