为什么这种印刷反向?

时间:2013-02-28 01:12:53

标签: scheme racket

(define (square-list items)
  (define (iter things answer)
    (if (null? things)
        answer
        (iter (cdr things)
              (cons (square (car things))
                    answer))))
  (iter items nil))

当我进入

(square-list (list 1 2 3 4))

它返回(16 9 4 1) - 为什么这会倒退?

4 个答案:

答案 0 :(得分:4)

您正在使用尾递归构建输出列表,为此,您将通过附加到列表的 head 来累积answer。当然,这将产生相反的列表。你有两个解决这个问题的方法,一个是放弃尾递归:

(define (square-list items)
  (if (null? items)
      nil
      (cons (square (car items))
            (square-list (cdr items)))))

其他,在处理之前撤消列表:

(define (square-list items)
  (define (iter things answer)
    (if (null? things)
        answer
        (iter (cdr things)
              (cons (square (car things))
                    answer))))
  (iter (reverse items) nil))

还有另一种选择:在最后添加元素,而不是将它们包括在内:

(define (square-list items)
  (define (iter things answer)
    (if (null? things)
        answer
        (iter (cdr things)
              (append answer
                      (list (square (car things)))))))
  (iter items nil))

每个选项都有自己的权衡,但是:

  • 第一个选项不是尾递归(尽管它是tail-recursive modulo cons
  • 第二个选项需要一个额外的遍历和一个额外的列表(当列表颠倒时会发生这种情况)
  • 第三个选项是二次方,因为每个追加操作遍历列表以在末尾添加元素

考虑到所有事情,最好的尾递归选项将是第二个。

答案 1 :(得分:1)

问题在于您的cons声明。如果您从以下地址切换订单:

(cons (square (car things)) answer)

致:

<击> (cons answer (square (car things)))

您的列表将按照您想要的顺序出现。

我总觉得这样写起来容易得多:

(define (square-list2 items)
  (square-list-helper items '())
)

(define (square-list-helper items squares)
  (cond
    [(empty? items) squares]
    [else (append 
             squares 
             (square-list-helper (cdr items) (list (square (car items)))))]
    )
 )

答案 2 :(得分:1)

看看两个元素的简单情况:

(square-list '(2 3))

这导致:

(iter '(3)
      (cons (square 2) nil))

==

(iter '(3) '(4))

然后递归调用:

(iter '()
      (cons (square 3) '(4))

==

(iter '() '(9 4))

然后,这会调用iter的基本情况,只返回answer

所以它正在向前遍历列表,但是在处理每个元素时,正方形被放在answer列表的 front 上,因此结果是向后构建的。

简单的解决方法是将(cons (square (car things)) answer)更改为:

(append answer (list (square (car things))))

这会将新结果放在最后而不是开头。但是,这通常被认为是一种不好的方法,因为它必须每次重建结果列表,复制O(n)元素。

答案 3 :(得分:0)

您的输入顺序错误:首先是递归处理的列表的其余部分,然后是处理当前元素的结果。这将在处理它的同时反转您的列表。试试这个:

(define (square-list items)
  (define (iter things answer)
    (if (null? things)
      answer
      (iter (cdr things)
            (append answer (list (square (car things)))))))
(iter items (list)))