在Scheme中,反转列表的函数是什么?
它需要能够处理嵌套列表。因此,如果您执行类似于(reverse '(a (b c d) e))
这样的操作,则输出应为(e (b c d) a)
。
我该如何解决这个问题?我不仅仅是在寻找答案,而是想要学习一些东西。
(define (my-reverse ls)
(define (my-reverse-2 ls acc)
(if (null? ls)
acc
(my-reverse-2 (cdr ls) (cons (car ls) acc))))
(my-reverse-2 ls '()))
这里使用一个累加器变量来翻转列表,从传入的列表中取出第一个元素,将其连接到累加器的前面。它隐藏了累加器函数,并且只公开接受列表作为参数的函数,所以调用者不必传入空列表。这就是为什么我有我的my-reverse-2函数。
(my-reverse-2 '(a (b c d) e) '()); will call
(my-reverse-2 '((b c d) e) '(a)); which will call
(my-reverse-2 '(e) '((b c d) a)); which will call
(my-reverse-2 '() '(e (b c d) a)); which will return
'(e (b c d) a)
因为my-reverse-2
函数中的最后一个函数调用是对my-reverse-2
的调用,并且返回值被直接传递(第一次调用的返回值就是第二次调用的返回值,以此类推),my-reverse-2
是尾递归优化的,这意味着它不会在堆栈上耗尽空间。因此,使用任意长度的列表调用它是安全的。
如果要应用于嵌套列表,请使用以下方式:
(define (deep-reverse ls)
(define (deep-reverse-2 ls acc)
(if (null? ls)
acc
(if (list? (car ls))
(deep-reverse-2 (cdr ls) (cons (deep-reverse (car ls)) acc))
(deep-reverse-2 (cdr ls) (cons (car ls) acc)))))
(deep-reverse-2 ls '()))
在将元素添加到列表之前,此代码会检查它是否为列表,并在是列表时先将其翻转。 由于它调用自身来反转内部列表,因此可以处理任意嵌套。
(deep-reverse '(a (b c d) e))
-> '(e (d c b) a)
,尽管有一个嵌套的列表,但结果仍按照反字母顺序排列。
它的计算过程如下:
(deep-reverse-2 '(a (b c d) e) '()); Which calls
(deep-reverse-2 '((b c d) e) '(a))
(deep-reverse-2 '(e) (cons (deep-reverse-2 '(b c d) '()) '(a)))
(deep-reverse-2 '(e) (cons (deep-reverse-2 '(c d) '(b)) '(a)))
(deep-reverse-2 '(e) (cons (deep-reverse-2 '(d) '(c b)) '(a)))
(deep-reverse-2 '(e) (cons '(d c b) '(a)))
(deep-reverse-2 '(e) '((d c b) a))
(deep-reverse-2 '() '(e (d c b) a))
'(e (d c b) a)
使用:
(define (reverse1 l)
(if (null? l)
nil
(append (reverse1 (cdr l)) (list (car l)))
)
)
解释:
规则:
这段代码可以这样理解:
reverse1
是函数名,l 是参数。如果列表为空,则返回空。
否则,调用 reverse1
函数并将 (cdr l)(即列表的尾部)附加到第一个元素 (car l) 组成的列表中。
在你的示例中(伪代码):
1st iteration
l=>(a (bcd)e)
car l => a
cdr l => (bcd)e
list(car l) =>(a)
------------------
reverse( cdr l)"+"(a)
------------------
2nd iteration
l=>((bcd)e)
car l => (bcd)
cdr l =>e
list(car l)=>(bcd)
--------------------
reverse(cdr l)"+"((bcd))+(a)
-----------------------
3rd iteration
l=>e
car l=> e
cdr l => nil
list (car l) =>(e)
-------------------------
(e (bcd)a)
nil
代替'()
。 - erjiangnil
而 Scheme 不用,但是在这个答案的顶部定义的函数实际上是 Scheme 而不是 Common Lisp。不过你需要执行类似于 (define nil '())
这样的操作才能使它起作用。 - okonomichiyaki(define/match (rev l)
[('()) '()]
[((list a ... b)) (cons b (rev a))])
> (rev '(a (b c d) e))
'(e (b c d) a)
(define (reverse-deep l)
(map (lambda (x) (if (list? x) (reverse-deep x) x)) (reverse l)))
伪代码解释:
首先按照通常的方式反转列表
然后对于反转列表中的每个元素:
- 如果该元素本身就是一个列表: 递归应用此过程
- 否则: 不要改变该元素
您可以使用foldr简单地反转列表中的元素:
(foldr (lambda (a r) (append r (list a))) empty lst)
我使用了类似于插入排序的代码:
(define deep-rev-list
(lambda (l)
(cond ((null? l) (quote ()))
((atom? (car l))
(swap-till-end (carl) (deep-rev-list (cdr l))))
(else
(swap-till-end (deep-rev-list (car l)) (deep-rev-list (cdr l)))))))
(define swap-till-end
(lambda (elm lst)
(cond ((null? lst) (cons elm '()))
(else
(cons (car lst) (swap-till-end elm (cdr lst)))))))
(define atom?
(lambda (x)
(and (not (null? x)) (not (pair? x)))))
我是凭记忆重现的。可能会有一些错误。如果有的话,我会更正代码。但使用的技术类似于《小计算机程序员》中嵌套列表的命令ments :). 我在DrRacket中进行了检查。
(deep-rev-list '((1 2) (3) ((4 5)))) 返回 (((5 4)) (3) (2 1))
(define (rvrs ls)
(if (null? ls)
empty
(append (rvrs (cdr ls)) (cons (car ls) empty))))
(reverse '(a (b c d) e))
应该得到(e (d c b) a)
,即嵌套的列表也被反转。但是对于(reverse '(a (b c (d e))))
,你期望得到什么?我会期望得到(((e d) c b) a)
,但例子表明结果应该是((b c (d e)) a)
。 - ad absurdum