【问题标题】:More to Recursion than Just a Function Calling Itself递归不仅仅是一个函数调用本身
【发布时间】:2012-05-19 17:56:15
【问题描述】:

我见过的关于递归函数的每一本教科书都使用阶乘 举个例子,这很有帮助,但并不完全有启发性。

出于编程目的,递归函数能否以函数为基础 案例,它是否可以在其主体中包含其他函数调用,或者它是否可以执行 不同层次的递归有什么不同?

如果它做了这些事情中的任何一个,它仍然是一个“递归函数”吗? 还是现在是别的什么?

【问题讨论】:

  • 递归函数只不过是一个调用自身的函数。就是这样。 “以函数为基本案例”是什么意思?
  • 我猜,例如,你会有一个函数,它接受一些输入并以某种方式将它们转换为输出。然后你会有第二个函数调用第一个函数并修改它的输出,然后在它自己的输出上调用它自己,可能使用 case switch 语句或不同输入的不同行为,诸如此类?在这片领土上真的很新鲜,只是想感受一下。
  • 有趣的问题!关于第 2 部分,“它是否可以包含其他函数调用”,答案肯定是肯定的:例如,您甚至可以调用另一个递归函数来调用您的第一个函数,即 mutual recursion

标签: math recursion computer-science


【解决方案1】:

递归函数的定义只是“一个调用自身的函数”。所以如果你有一个调用自己的函数,它就是一个递归函数。

其他任何事情都取决于您使用的语言的功能。

【讨论】:

    【解决方案2】:

    这是一个相当简单的递归函数示例,它简单地将集合(表示为堆栈的数组)中的所有值输出到浏览器控制台,因为它使用 .pop() 方法将它们从堆栈中弹出.

    totalSize 值不会在整个调用堆栈中发生变化,因此可以通过将当前堆栈大小除以原始大小来测量中点。

    要回答它在递归的不同层次上是否可以表现不同的问题,答案是肯定的:

    // a simple array of 10 items
    var coll = [1,2,3,4,5,6,7,8,9,10];
    
    // recursive function that calls itself. It behaves slightly different at
     // the halfway point
    function test(totalSize, col) {
        if(col == undefined || col.length == 0) {
            return 0;
    
         } else {
            if(col.length / totalSize < .5) {
                console.log("Past 1/2 way point!");
            }
            console.log("total = " + totalSize);
            console.log("col.pop() = " + col.pop());
            return test(totalSize, col);
        }
    }
    
    // make a call to the function with the total size and the collection
    test(coll.length, coll);
    

    另外,您还问过是否可以调用其他函数,这也是可以的。在下面的示例中,一个函数用于返回基本情况的结果, 并用一个函数来抽象中途点行为:

    // a simple array of 10 items
    var coll = [1,2,3,4,5,6,7,8,9,10];
    
    // recursive function that calls itself. It behaves slightly different at
     // the halfway point
    function test(totalSize, col) {
        if(col == undefined || col.length == 0) {
            return handleBaseCase(totalSize, col);
    
         } else {
            // handle if it's at 1/2 way point
            handleHalfwayPoint(totalSize, col);  
    
            console.log("tital = " + totalSize);
            console.log("col.pop() = " + col.pop());
            return test(totalSize, col);
        }
    }
    
    function handleHalfwayPoint(totalSize, collection) {
        if(collection.length / totalSize < .5) {
            console.log("Past 1/2 way point!");
        }
    }
    
    // instead of returning 0, return "Done" and also print to the log
    function handleBaseCase(totalSize, collection) {
        console.info("Done!");
        return "Done!";
    }
    
    // make a call to the function with the total size and the collection
    test(coll.length, coll);
    

    虽然这些特定示例并不能解决任何实际问题,但它展示了在另一个函数中调用一个函数的概念如何扩展以处理其他用例。教科书中的示例旨在教您递归的基础知识,并帮助您掌握必要的工具,以应对未来更复杂的现实问题。

    由于这种函数式语言是 JavaScript,因此运行它们的障碍很低。您可以通过在 Chrome 开发者控制台中运行代码来尝试这些示例,或者您可以在一个小的测试 HTML 文件中运行它们。祝你好运!

    【讨论】:

    • 我不认为您可以推荐任何资源来进一步了解递归编程?我读过迭代和递归函数应该可以相互转换,试图更好地理解这意味着什么。就像,任何书籍或在线资料都会有很大帮助。如果没有,无论如何,非常感谢,如果可以的话,我会投票给你两次。
    • 如果你仔细想想,递归只是另一种循环策略,就像 for 或 while 循环。例如,您可以将 while 循环的主体视为重复调用的函数,只要该 while 循环中的条件继续为真。至于递归的资源,我的建议是谷歌它。谷歌你选择和递归的语言,谷歌将递归函数翻译成 for/while 循环。恕我直言,你会得到更好的结果。祝你好运! :)
    【解决方案3】:

    递归函数是在其主体中调用自身一次或多次的函数。函数也可以相互递归,其中一个函数根据第二个函数定义,反之亦然。

    我已经在不需要递归的情况下进行了 20 多年的编程。让我真正理解递归调用的必要性和美妙之处在于 Scheme 语言,以及诸如“The little Schemer”之类的书籍。

    并非所有编程语言都支持同一级别的递归。计划是做得很好的人之一。 Python 少得多。因此,如果您想深入了解递归,请检查您的编程语言的能力。

    【讨论】:

    • “我已经在不需要递归的情况下编程了 20 多年。” 所以你从来没有写过递归下降解析器,也没有使用过树形数据结构,或使用快速排序/二分搜索/合并排序,或欧几里得算法?
    • 我在 wikipedia 上查找了“递归下降解析器”,我认为这就是我提出问题的原因。我正在阅读“Little Schemer”,但我很难找到关于递归的好资源,比如它使用的实际示例。你能推荐任何资源(在线、书籍等)吗?
    • @Matt Ball:确实如此。我曾经为一家银行编写程序。例如,您不需要这些东西来编写安全后台系统。我什至会说它在大多数地方实际上是不受欢迎的,因为必须维护你的代码的人将无法理解它。
    【解决方案4】:

    正如其他答案所说,递归函数是一个调用自身的函数。正如here所解释的有两种类型:

    1. 直接递归:函数调用自身。
    2. 间接递归:当一个函数不是由它自己调用而是由它调用的另一个函数调用时(直接或间接)。

    我在您的问题中看到了数学标签。递归与数学归纳有关。如果你证明它可以解决基本情况,然后你证明如果无限序列语句中的任何一个语句为真,那么下一个语句也是如此,你证明它在任何情况下都能解决问题。

    【讨论】:

      猜你喜欢
      • 2013-09-09
      • 2019-12-31
      • 2014-07-21
      • 2016-05-06
      • 2015-08-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-17
      相关资源
      最近更新 更多