【问题标题】:How to Reverse Elements of A List And Its Sub-lists in LISP? [duplicate]如何在 LISP 中反转列表及其子列表的元素? [复制]
【发布时间】:2021-05-24 09:14:17
【问题描述】:

我有以下代码:

(defun list-append (L1 L2)
  "Appending L1 by L2."
  (if (null L1)
      L2
      (cons (car L1) (list-append (cdr L1) L2))))

(defun list-reverse (L)
  "Create a new list containing the elements of L in reversed order."
  (if (null L)
      nil
      (list-append (list-reverse (cdr L)) 
                   (list (car L))))) 

当我运行以下命令时:

(list-reverse '(a (b c) ((l k (t)) h i)))

我得到的输出是这样的:

(((L K (T)) H I) (B C) A)

但是,我试图让它反向打印出列表及其子列表,如下所示:

((I H ((T) K L)) (C B) A)

关于如何修改代码来做到这一点的任何建议?

【问题讨论】:

标签: lisp common-lisp clisp


【解决方案1】:

这是一种不可怕的方法。特别是previous question 的公认解决方案在算法上是可怕的:任何反转列表的方法都说:'要反转一个(可能很长的列表),首先反转它的 cdr 然后附加汽车 应该会让你的皮肤发痒:这种方法就是“lisp 很慢”的原因。其他两个答案更好,但都明确地改变了状态(这很好,但可能并不总是在教学上很好)。

所以这里有一个答案:是功能性的(不改变状态),并且使用了一种不可怕的算法。

首先,假设我们有一个名为reverse-thing 的函数,它将对“事物”进行适当的反转,这意味着:如果它是一个列表,则反转它,如果它不是一个列表,则不要。给定这个函数,我们可以计算出一个将列表反转到其他列表的算法:

将一个列表反转到另一个列表

  • 如果列表为空,则返回我们要反转的列表
  • 否则,将列表的其余部分反转到通过将列表第一个的 reverse-thing 与我们要反转到的列表相结合而生成的列表。

这个变成函数很简单:

(defun reverse-onto (list onto)
  (if (null list)
      onto
    (reverse-onto (rest list)
                  (cons (reverse-thing (first list))
                        onto))))

所以这个函数需要一个reverse-thing 的定义,这样它才能完成它的工作。那么这将如何运作?

扭转一件事:

  • 如果是列表,则使用reverse-onto将其反转到(),空列表;
  • 如果不是列表,则按原样返回。

再一次,这很容易变成一个函数:

(defun reverse-thing (thing)
  (if (listp thing)
      (reverse-onto thing '())
    thing))

我们完成了:reverse-thing 是我们想要编写的函数。

请注意,这些函数永远不会改变任何东西,并且永远不会超越它们在每一步中反转的列表的第一个缺点:这里没有“将这个东西附加到这个巨大的列表的(副本)”。另请注意,reverse-into 是尾递归的,因此在优化尾调用的实现中(标准不要求),堆栈的数量将与嵌套深度而不是列表长度成正比。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-18
    • 2016-02-08
    • 2017-12-31
    • 1970-01-01
    相关资源
    最近更新 更多