• 算法之递归


           什么是递归?递归是一种算法思想。从字面上看,递归包含两层含义,传递和回归。现实中有很多问题,只是传递而不用回归。比如说,军训时,每天的一项训练:”报数”。报数从头到尾,依次传递,到最后一个人停止,这时候军官就知道了总体人数是多少,有没有少人。假如,队伍中有人想知道自己是几号,怎么办呢?问下旁边的人,如果旁边的人说自己是“N”号,那么自己是“N+1”号。如果旁边的人不知道自己的号,那么他会继续问他旁边的人,以此类推,知道某个人知道自己是多少号,然后把这个号往回传回传其实就是报数。用一段程序表示:

            public static int GetPeopleCount(int n)
            {
    if (n<1) return 0;
    if (n == 1) return 1; return GetPeopleCount(n - 1) + 1; }

           有人问了,你这还用得着递归吗?直接循环搞定。我说此时用循环意义变了,那军官从第一个人数到最后一个人,不就是很累吗?递归(报数)效率多高啊。军官自己数的话,相当于每次指针移动。在现实当中不可取,原因不光是累,还有一个致命的原因,就是大家都是迷彩服,数数肯定花眼了,难免出错。

           好了,递归可以用来数数,我们的循环当然可以数数,而且循环效率肯定高。放到计算机中,这只是不同的算法而已。

    要算一个数的阶乘,怎么算呢?

            public static int GetNumber(int n)
            {
                if (n < 1) return 0;
                if (n == 1)
                    return 1;
    
                return GetNumber(n - 1) * n;
            }

    和上面的数数多么相似啊,只是递归的时候函数变了而已。为了程序的正确性,小测一下,求5的阶乘:

    有人说,循环也可以啊,效率也高,那我们改为循环:

           public static int GetNumber(int n)
            {
                int result = 1;
    
                for (int i = 1; i <= n; i++)
                {
                    result = result * i;
                }
                return result;
            }

    的确根据阶乘的定义,可以改为循环。

          有一个很经典的问题,那就是 斐(fei)波那契数列(兔子总数) 1,1,2,3,5,8,13..这个数列的特点就是从第三个数开始,每一项都是前两项之和。那这个数列跟兔子又有什么联系呢,原来还有这么个问题:

     有一对兔子,从出生后第三个月起每个月都生一对兔子,小兔子长到第三个月后又生一对兔子,假如兔子都不死,每个月兔子对数为多少? 
    第一个月:1对; 
    第二个月:1对; 
    第三个月:2对; 
    第四个月:3对: 
    第五个月:5对: 
    第六个月:8对;

    请问第五个月,为什么是5对?那是因为自己生了一对,在第三个月生下的一对兔子,在第五个月开始生了一对兔子,所以加起来就增加了2对兔子,因此是5,请问第20月的时候,一共有多少兔子?要让人算,恐怕得费点事情了,好在我们发现这个兔子数的规律就是斐(fei)波那契数列。

    程序编写为:

           public static int GetNumber(int n)
            {
                if (n < 1) return 0;
    
                if (n == 1 || n == 2) return 1;
    
                return GetNumber(n - 2) + GetNumber(n - 1);
            }

    第20个月兔子总数:

    这么多啊,果然非人力所为,那怎么知道这个方法正确呢?测试下,第6个月:

    这段程序依然可以改为循环,就不用写了,为什么我一直把递归和循环比较呢?那是因为我曾经面试的时候,有个面试官问我循环和递归有什么不同,递归在什么时候用,我当时一脸懵逼,心里嘀咕,该用递归时自然用递归。他给的结论是:能用递归的,就能用循环。

    果真是这样的吗?

    1、给定一个文件夹,找出下面所有的文件

    2、遍历二叉树

    你给我来个循环试试。这个我就确实用循环写不出来,为什么呢?因为之前的例子,都是数学问题,有明显的规律可寻,但是遍历文件和二叉树没有这样的规律,而且我无法确定循环多少次,什么时候才能循环结束。也许有某些高人能写出来。

    附:递归遍历文件

     1          /// <summary>  
     2         /// 获取目录path下所有子文件名  
     3         /// </summary>  
     4         public static List<string> getAllFiles(String path)
     5         {
     6             List<string> fileNames = new List<string>();
     7             if (System.IO.Directory.Exists(path))
     8             {
     9                 //所有子文件名  
    10                 string[] files = System.IO.Directory.GetFiles(path);
    11                 foreach (string file in files)
    12                 {
    13                     fileNames.Add(file);
    14                 }
    15                 //所有子目录名  
    16                 string[] Dirs = System.IO.Directory.GetDirectories(path);
    17                 foreach (string dir in Dirs)
    18                 {
    19                     var tmp = getAllFiles(dir);  //子目录下所有子文件名  
    20                     if (tmp.Count>0)
    21                     {
    22                         fileNames.AddRange(tmp);
    23                     }
    24                 }
    25             }
    26             return fileNames;
    27         }
  • 相关阅读:
    html表单的创建
    mysql数据库连接标准操作
    关于Apache+MySQL+PHP下载及配置注意事项
    两个范例
    Stack类
    Collections类集
    key可以重复的map集合:IdentityHashMap
    foreach对集合的输出作用
    ListIterator接口
    【官方方法】xcode7免证书真机调试
  • 原文地址:https://www.cnblogs.com/wangqiang3311/p/7992122.html
Copyright © 2020-2023  润新知