我需要创建一个会破坏性地反转列表的程序。例如让我们说..
scm> (define L (list 1 2 3 4))
scm> (reverse! L)
(4 3 2 1)
scm> L
(1)
其中 L 成为反向列表的最后一个元素。我知道我应该使用 set-cdr!不知何故,但无法弄清楚如何实现它。
因为这看起来像家庭作业,所以我不能给你一个直接的答案。我将向您展示解决方案的一般结构,以便您了解详细信息并填写空白:
(define (reverse! lst)
  (let loop ((lst lst)
             (acc '()))
    (if (null? lst)
        acc
        (let ((tail <?1?>))
          (set-cdr! <?2?> <?3?>)
          (loop tail lst)))))
(define lst (list 1 2 3 4))
lst
> (1 2 3 4)
(reverse! lst)
> (4 3 2 1)
lst
> (1)
在上面的代码中:
let,因为需要另一个参数acc参数,作为反向列表的累加器现在,对于递归步骤:
<?1?>需要获取对列表其余部分的引用并保存它,因为我们要修改它(set-cdr! <?2?> <?3?>)。您必须将当前列表的下一个元素设置为先前累积的反向列表请注意,最后,lst引用已就地修改,现在指向列表的最后一个元素。如果您需要lst指向反向列表,那么只需执行以下操作:
(define lst (list 1 2 3 4))
lst
> (1 2 3 4)
(set! lst (reverse! lst))
lst
> (4 3 2 1)
描述的过程破坏性地反转列表并且不创建新列表(不cons使用任何操作。)
您应该阅读The Scheme Programming Language书中关于 mutators 的部分。另外,查看Scheme 中的函数。本质上,您可以使用该函数从根本上更改定义并提供另一个输出。caseset!
UCB 好家伙。
这是我为您的 HilAcke 提供的解决方案。
(define (reverse! L)
     (define (helper prev cur)
           (if (null? cur)
               prev
               (let ((next (cdr cur)))
                   (set-cdr! cur prev)
                   (helper cur next))))
     (helper '() L))
然后在定义后你可以用通常的方式检查
 (define L (list 1 2 3 4))
 (define LR (reverse! L))
 LR
 > (4 3 2 1)
    所以我想知道今天如何做到这一点,因为我需要它进行测试。对于每个包含超过 1 个元素的列表,我将cons参数中的第一个作为结果中的第一个。我做了一个新的缺点,用一个虚拟值保存新的最后一个值,然后我反转元素 2..n-1 的链接。最后我设置了第一cons和新的车last。结果是最后的结果set-cdr!。
(define (reverse! lst)
  (if (or (null? lst)
          (null? (cdr lst)))
      'soup ; an undefined value. You may use something else
      (let ((last (list 1)))
        (let loop ((prev last) (cur (cdr lst)))
          (let ((next (cdr cur)))
            (if (pair? next)
                (begin
                  (set-cdr! cur prev)
                  (loop cur next))
                (begin
                  (set-car! last (car lst))
                  (set-car! lst (car cur))
                  (set-cdr! lst prev))))))))
例子:
(define test '(() (2) (3 4) (5 6 7) (8 9 10 11 12 13 14 16)))
(for-each reverse! test)
test ; ==> (() (2) (4 3) (7 6 5) (16 14 13 12 11 10 9 8))