【问题标题】:First n elements of a list (Tail-Recursive)列表的前 n 个元素(尾递归)
【发布时间】:2015-03-21 22:26:23
【问题描述】:

在弄清楚这个算法的递归版本之后,我正在尝试创建一个迭代(尾递归)版本。

我已经很接近了,但是返回的列表最终被颠倒了。

这是我目前所拥有的:

(define (first-n-iter lst n)
  (define (iter lst lst-proc x)
    (cond
      ((= x 0) lst-proc)
      (else (iter (cdr lst) (cons (car lst) lst-proc) (- x 1)))))
  (if (= n 0)
      '()
      (iter lst '() n)))

即调用(first-n-iter '(a b c) 3) 将返回(c b a)

有人可以提出解决办法吗?再一次,我想保留尾递归。

注意:我不希望你建议只在返回的列表上调用 (reverse lst)..

【问题讨论】:

  • 但是,在结果上调用 reverse 实现这一点的标准方法。
  • 真的吗?我没有意识到这一点。我希望我可以通过使用 cons carcdr 来实现它,但如果真的是这样,那么我将不得不忍受它。
  • 确实如此。由于reverse 以这种方式使用,许多实现提供了非常快速的reverse 的内置版本。

标签: scheme racket


【解决方案1】:

您可以使用 head sentinel 技巧来实现尾递归模 cons

(define (first-n-iter lst n)
  (define result (cons 'head '()))
  (define (iter tail L-ns x)
    (cond
      ((= x 0) (cdr result))
      ((null? L-ns) 
       (error "FIRST-N-ITER input list " lst " less than N" n))
      (else 
       (begin (set-cdr! tail (list (car L-ns)))
              (iter (cdr tail) (cdr L-ns) (- x 1))))))
      (iter result lst n))


(first-n-iter '(a b c d e f g h i j k l m n o p q r s t u v w x y z) 8))

;Value 7: (a b c d e f g h)

还添加了一个 cond 子句来捕获您尝试获取的元素多于列表中实际存在的元素的情况。

【讨论】:

  • 这在常规 Scheme 中有效,但在 Racket 中无效,其中 set-cdr! 不存在,因为列表是不可变的。
【解决方案2】:

您可以翻转 cons 语句的参数,list 最后一个(以前是第一个)arg,并将 cons 更改为 append

(define (first-n-iter lst n)
  (define (iter lst acc x)
    (cond
      [(zero? x) acc]
      [else (iter (cdr lst) (append acc (list (car lst))) (sub1 x))]))
  (iter lst empty n))

这将按您的意愿工作。如果您将此作为学习练习,那么我认为这就是您所需要的。但是如果你真的在尝试制作这个功能,你应该知道它已经完成了--(take lst 3)

此外,您根本不需要您的 if 语句 - 您对 (= x 0) 的检查将立即返回 '(),并且您按原样传递 (iter lst '() n)。所以(if (= n 0) ... ) 正在做(cond [(= x 0)...)' 已经为你做的工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-26
    • 1970-01-01
    • 1970-01-01
    • 2015-02-10
    • 1970-01-01
    • 2014-12-20
    • 2021-06-26
    • 2020-03-09
    相关资源
    最近更新 更多