recursion - 复制长度函数的有效方法

标签 recursion scheme lisp racket

我正在复制 Racket 的长度函数,仅使用 car 和 cdr 来比较两个列表的长度并返回两个列表中较短的一个。

长度函数简单来说就是:

(define length
 (lambda (list)
    (if (null? list)
        0
        (+ 1 (length (cdr list))))))

以及用于比较两个列表时

(define short
  (lambda (list1 list2)
    (if (<= (length list1) (length list2))
        list1
        list2)))

> (short '(a b c) '(1 2 3 4 5 6 7))

将返回“(a b c)”。

但是,此方法无效,尤其是当一个列表比另一个列表长得多时,因为它会在返回较短的列表之前迭代两个列表。

下面我有一个更有效的方法。然而我想知道是否有一种更有效/替代的方法来获得更短的长度而不检查两个列表的末尾。也许通过与 car/cdr 同时递归地遍历列表,直到较短的列表首先到达其末尾。

(define shorter?
  (lambda (list1 list2)
    (and (not (null? list2))
         (or (null? list1)
             (shorter? (cdr list1) (cdr list2)))))) 

(define shorter
  (lambda (list1 list2)
    (if (shorter? list2 list1)
        list2
        list1)))

最佳答案

您的更短?过程已经尽可能高效 - andor特殊形式short -电路,当任何计算表达式的值为 true (对于 or 特殊形式)或 false (对于 code> 和 特殊形式)。因此,一旦其中一个列表达到 null,递归就会停止。您的 shorter? 实现相当于,并且与此一样高效:

(define shorter?
  (lambda (list1 list2)
    (cond ((null? list2) #f)
          ((null? list1) #t)
          (else (shorter? (cdr list1) (cdr list2))))))

如果您想要一个更紧凑的解决方案,您可以使用命名的 let (如另一个答案中所示)或内部帮助程序将两个过程放入一个过程中,两者是等效的。我将演示后面的方法:

(define (shorter lst1 lst2)
  (define (shorter-list list1 list2)
    (cond ((null? list2) lst2)
          ((null? list1) lst1)
          (else (shorter-list (cdr list1) (cdr list2)))))
  (shorter-list lst1 lst2))

关于recursion - 复制长度函数的有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41970097/

相关文章:

c - 如何将此代码更改为递归函数?

在reduce上使用和运算符的方案

scheme - 将 guile 链接到 Rcpp

.net - .NET 平台上是否有生产就绪的类 Lisp 语言?

java - 调试器跳过递归 Java 程序中的方法

c - 如何通过指向结构的指针间接释放结构内数组中的指针并将其写入 NULL?

lisp - 在 lisp 中排序混合数据类型列表

constants - 如何在 Common Lisp 中定义函数局部常量?

recursion - 鸭图到底有什么作用?

arrays - Racket:宏输出一些奇怪的东西而不是数组