列表的前n个元素(Tail-Recursive)

时间:2015-03-21 22:26:23

标签: scheme racket

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

我非常接近,但返回的列表最终会被撤消。

这是我到目前为止所做的:

(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)

2 个答案:

答案 0 :(得分:1)

你可以做头部哨兵技巧来实现尾递归模数缺点

(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子句来捕获您尝试获取的元素多于列表中实际存在的元素。

答案 1 :(得分:0)

您可以翻转cons语句的参数,list最后一个(先前的第一个)参数,并将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)...)'已为您做的工作。