【问题标题】:Can this permutations-listing Racket function be made tail-recursive?这个排列列表 Racket 函数可以尾递归吗?
【发布时间】:2021-10-20 14:28:20
【问题描述】:

我编写了一个函数,它接收一个列表并返回一个包含所有排列的列表。它的工作原理是:

  • 单元素列表的排列是其自身的列表。
  • n 元素列表的排列是每个元素后跟删除元素后的列表排列。
(define (remove-nth lst n) ; remove the nth element from a list lst
  (append (take lst n)
          (drop lst (+ 1 n))))

(define (perm lst) ; a list of all permutations of lst
  (if (null? (cdr lst))
      (list lst)
      (apply append (map (lambda (i)
                           (map (lambda (sublst) (cons (list-ref lst i)
                                                       sublst))
                                (perm (remove-nth lst i))))
                         (range (length lst))))))

例子:

> (perm '(1 2 3))
'((1 2 3) (1 3 2) (2 1 3) (2 3 1) (3 1 2) (3 2 1))

可以做尾递归吗?

附:我知道 Racket 中有一个permutations 函数。虽然它是尾递归的,但它使用不同的算法。我很好奇我写的那个是否也可以是尾递归的。

【问题讨论】:

  • 是的,每个程序都可以写成迭代过程,要么直接写,要么使用自动转换。参见例如 CPS 重写。当前延续是显式的,您可以直接选择接下来要计算的内容,并且可以选择使其成为尾递归。

标签: recursion scheme lisp racket tail-recursion


【解决方案1】:

任何递归过程都可以成为尾递归,方法是显式地将任何数据移动到堆中,否则这些数据会通过递归调用隐式存储在堆栈中。转换为连续传递风格是一种常见的机械方式。

但是,如果没有特定的原因,这并不是一个特别富有成效的探索途径。毕竟,它分配相同的数据。而在permutations 的情况下,任何产生普通列表结果的算法都必须占用大量空间,因为要产生大量结果。所以,考虑一下你为什么要问这个问题:你希望通过使这个尾递归实现什么目标?有了这个答案,你就可以考虑目标是否可以实现。

【讨论】:

    猜你喜欢
    • 2012-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-10
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    相关资源
    最近更新 更多