【问题标题】:2 tail recursive functions for length [racket]长度的 2 个尾递归函数 [球拍]
【发布时间】:2012-09-30 11:09:03
【问题描述】:

我正在尝试编写两个单独的尾递归函数来计算列表的长度,但我遇到了以下限制:

  1. 编写一个版本,lengtht,它是尾递归并根据需要使用外部(非嵌套)辅助函数

  2. 编写第二个版本,lengtht2,它不使用额外的顶级函数。该函数应该仍然是尾递归的,并且可以使用您想要的任何本地绑定

我是球拍新手,这就是我所理解的尾递归的一般形式:

(define (func x)
    (cond (end-test-1 end-value-1)
          (end-test-2 end-value-2)
          (else (func reduced-x))))

我只是对如何做到这一点有点困惑

【问题讨论】:

标签: scheme racket


【解决方案1】:

本质上,尾递归函数会不断调用自身,直到达到其结束条件。然而,与“常规”递归不同,它会将中间答案传递给自身,直到到达终点。

一个例子是这样的:

(define (find-length i lst)
  (if
    (null? lst) i
    (find-length (+ i 1) (cdr lst))))

该函数有两个值:i,它跟踪到目前为止列表的长度,以及lst,我们正在计算其元素的列表。 i,出于所有意图和目的,是我们对列表中元素的运行计数。因此,如果我们调用此方法,我们会希望将i 初始化为 0 来调用它。

首先我们检查列表是否为空。 (null?) 如果列表为空,我们可以假设我们已经计算了所有元素,所以我们简单地返回i,这是我们的运行计数。这是我们的最终条件。

否则,我们再次调用find-length。然而,这一次,我们将 i 增加了 1,并从列表 (cdr lst) 中删除了第一个元素。

例如,假设我们这样调用函数:

(find-length 0 (list 2 3 4 3 5 3))

当我们评估时,程序会递归调用:

(find-length 1 '(3 4 3 5 3))
(find-length 2 '(4 3 5 3))
(find-length 3 '(3 5 3))
(find-length 4 '(5 3))
(find-length 5 '(3))
(find-length 6 '()) ; end condition, return 6

This question 通常是尾递归的一个很好的参考。

【讨论】:

    【解决方案2】:

    这看起来像家庭作业,所以我会给你一些提示,为你指明正确的方向,你可以填空。第一个问题试试这个:

    (define (loop lst acc)              ; receives a list and an accumulator
      (cond ((null? lst) <???>)         ; if the list is empty return the accumulator
            (else (loop <???> <???>)))) ; advance the recursion, +1 to accumulator
    
    (define (length1 lst)
      (loop <???> <???>))               ; how should we initialize the iteration?
    

    第二个问题试试这个:

    (define (length2 lst)
      (letrec ((loop <???>)) ; lambda with the same procedure as the previous `loop`
        (loop <???> <???>))) ; start the recursion exactly the same as in `length1`
    

    无论如何,想一想:空(null)列表的长度是多少?答案将向您展示如何初始化迭代。对于这两种解决方案,我们使用一个名为 acc 的额外参数来跟踪到目前为止的答案,并将它与列表一起传递给循环尾递归过程。

    【讨论】:

    • 这些过程是等价的,但最好将辅助函数隐藏在使用它们的过程中,因此首选第二种解决方案。第二种解决方案的另一种选择是使用“命名的 let”
    • 嗯,我没有说清楚。您在第二个函数中看到的 loop 只是您必须定义的 lambdaname,并且 lambda 有两个参数,就像第一个函数中的 loop功能 - 事实上,它们是相同的功能。充实更多细节,length2 中的第一个 ??> 应如下所示:(lambda (lst acc) ...)。我们使用了letrec,因为lambda 需要引用自身,名称为loop,它正在被定义
    • 是的,填写缺少的... 部分。与第一个 loop 几乎相同。
    • 也许你没有正确地推进递归?建议你看看《The Little Schemer》或者《How to Design Programs》,这两本书都会教你如何解决这类问题
    猜你喜欢
    • 2012-10-07
    • 2015-04-17
    • 2022-10-06
    • 1970-01-01
    • 2021-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多