如何反转清单?

时间:2010-11-03 22:08:11

标签: recursion scheme reverse

Scheme中列表的功能是什么?它需要能够处理嵌套列表。

因此,如果您执行(reverse '(a (b c d) e))之类的操作,则会获得(e (b c d) a)作为输出。

我该如何处理这个问题?我不只是在寻找答案,而是能帮助我学习的东西。

7 个答案:

答案 0 :(得分:20)

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

这使用累加器变量来反转列表,将第一个元素从传入列表中取出并将其传递到累加器的前面。它隐藏了累加器获取功能并且只暴露了获取列表的函数,因此调用者不必传入空列表。这就是为什么我有我的反向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)

答案 1 :(得分:19)

(define (reverse1 l)
  (if (null? l)
     nil
     (append (reverse1 (cdr l)) (list (car l)))
  )
)

说明:

规则:
1.如果列表为空,则反向列表也为空 2.否则在列表的反向尾部后面添加列表的第一个元素

以这种方式查看此代码:

reverse1是函数的名称,l是参数
如果list为空,则reverse也为空 否则使用(cdr l)调用reverse1函数,这是列表的尾部,并将其附加到您作为列表制作的第一个alement(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)

答案 2 :(得分:2)

这是一种可以创建适用于嵌套列表的反向函数的方法:

(define (reverse-deep l)
  (map (lambda (x) (if (list? x) (reverse-deep x) x)) (reverse l)))

伪代码说明:
首先按照通常的方式反转列表 然后对于反转列表中的每个元素:
- 如果元素本身就是一个列表:递归地应用该过程 - 否则:请勿触摸元素

答案 3 :(得分:1)

您可以使用foldr简单地反转列表中的元素:

(foldr (lambda (a r) (append r (list a))) empty lst)

答案 4 :(得分:1)

这是Racket中的反向功能,我更喜欢Scheme。 它仅使用匹配模式匹配功能。

(define/match (rev l)
    [('()) '()]
    [((list a ... b)) (cons b (rev a))])

> (rev '(a (b c d) e))
'(e (b c d) a)

答案 5 :(得分:1)

我的解决方案:

(define (rvrs ls)
  (if (null? ls)
    empty
    (append (rvrs (cdr ls)) (cons (car ls) empty))))

答案 6 :(得分:0)

我使用的代码类似于插入排序

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

我正在从记忆中复制它。可能存在一些错误。如果是这样的话,将纠正代码。但是使用的技术类似于THe Little Schemer :)中给出的嵌套列表的命令。我在DrRacket中检查过它

(deep-rev-list'((1 2)(3)((4 5))))返回(((5 4))(3)(2 1))