Common lisp 使用递归的列表的最大值?

Common lisp 使用递归的列表的最大值?,common-lisp,Common Lisp,我的任务是在lisp中编写函数,通过使用递归查找作为函数参数给出的列表的最大值。我已经尝试过,但有一些错误。我是lisp新手,正在使用eclipse的cusp插件。这是我的代码: (defun maximum (l) (if (eq((length l) 1)) (car l) (if (> (car l) (max(cdr l))) (car l) (max (cdr l)) )) 我认为您的问题在于您引用的是max,而不是max,后者是实际的函数名

我的任务是在lisp中编写函数,通过使用递归查找作为函数参数给出的列表的最大值。我已经尝试过,但有一些错误。我是lisp新手,正在使用eclipse的cusp插件。这是我的代码:

(defun maximum (l)
  (if (eq((length l) 1)) (car l)  
   (if (> (car l) (max(cdr l)))
    (car l) 
     (max (cdr l))
))

我认为您的问题在于您引用的是
max
,而不是
max
,后者是实际的函数名

此代码的行为正确:

(defun maximum (l)
  (if (= (length l) 1)
      (car l)
      (if (> (car l) (maximum (cdr l)))
          (car l)
          (maximum (cdr l)))))

如果这不是一个家庭作业问题,你应该喜欢这样的问题:

(defun maximum (list)
  (loop for element in list maximizing element))
(defun my-max (lst)
  (labels ((rec-max (lst actual-max)
             (if (null lst)
                 actual-max
                 (let ((new-max (if (> (car lst) actual-max) (car lst) actual-max)))
                   (rec-max (cdr lst) new-max)))))
    (when lst (rec-max (cdr lst) (car lst)))))
甚至:

(defun maximum (list)
  (reduce #'max list))
(但对于空列表,两者的行为不同)

如果您真的需要递归解决方案,您应该尝试使您的函数更高效,和/或尾部递归。请看一下Diego和Vatine的答案,以获得更加惯用和高效的递归实现

现在,关于您的代码:

这在“口齿不清”方面是非常错误的,即使你似乎对如何解决手头的问题有想法。我怀疑您是否花了很多时间学习lisp基础知识。括号被弄乱了——缺少一个右括号,在
((长度l)1)
中,您应该注意,已计算列表中的第一个元素将用作运算符。另外,您并没有真正递归,因为您正在尝试调用
max
(而不是
最大化
)。最后,不要使用
#eq
进行数值比较。此外,如果您以传统的方式格式化和缩进代码,那么您的代码将更具可读性(不仅仅是对其他代码)


<>你真的应该考虑花一些时间在一个基本的LISP教程上,因为你的问题清楚地显示了对Lisp的最基本的东西,比如评价规则的缺乏理解。

< P>编写的代码暗示了一些有趣的低效性。(它没有它们,因为您正在调用
cl:max
,而不是递归调用您自己的函数)

Common Lisp中的函数调用通常不会被记忆,因此如果您在一个长列表中调用
最大值
,您将以指数运行时结束

您可以做一些事情来提高性能

第一件事是将最大值带到递归中,依赖于它返回给您

第二个是永远不要使用成语
(=(length list)1)
。也就是说,在list length中是O(n),但在true list中相当于
(null(cdr list))
,后者是O(1)

第三种是使用局部变量。在公共Lisp中,它们通常由
let
引入。如果您执行了以下操作:

(let ((tail-max (maximum (cdr l))))
   (if (> (car l) tail-max)
     (car l)
     tail-max))

我相信,你会立即从指数变为二次。如果结合起来做
(null(cdrl))
的事情,你会下降到O(n)。如果你也把迄今为止看到的最大值带到列表中,你会下降到O(n)时间和O(1)空格。

我没有看到真正递归的答案,我写了一个答案只是为了练习Common Lisp(目前正在学习)。前面包含递归版本的答案效率很低,因为它递归调用两次
最大值
。您可以这样写:

(defun maximum (list)
  (loop for element in list maximizing element))
(defun my-max (lst)
  (labels ((rec-max (lst actual-max)
             (if (null lst)
                 actual-max
                 (let ((new-max (if (> (car lst) actual-max) (car lst) actual-max)))
                   (rec-max (cdr lst) new-max)))))
    (when lst (rec-max (cdr lst) (car lst)))))

这是(尾部)递归和O(n)。

如果我需要在迭代中执行max代码,而不是递归,那么代码将如何?? 我首先做了一个数组

(do do-array (d l)
          setf b (make-array (length d))
          (do (((i=0)(temp d)) 
               ((> i (- l 1)) (return))
               (setf (aref b i) (car temp))
               (setq i (+ i  1))
               (setq temp (cdr temp))))

我做了这个,希望它有帮助,它是递归的

(defun compara ( n lista)
   (if(endp lista)
       n
       (if(< n (first lista))
          nil
          (compara n (rest lista)))))

(defun max_lista(lista)
    (if (endp lista)
        nil
        (if(compara (first lista) (rest lista))
             (first lista)
             (max_lista(rest lista)))))
(数据比较(n列表a)
(如果(endp lista)
N
(如果(
正确的尾部递归解决方案

(defun maximum (lst)
    (if (null lst)
        nil
        (maximum-aux (car lst) (cdr lst))))

(defun maximum-aux (m lst)
    (cond
        ((null lst) m)
        ((>= m (car lst)) (maximum-aux m (cdr lst)))
        (t (maximum-aux (car lst) (cdr lst)))))

我在上面没有看到递归:-)
max
!=<代码>最大值。此外,函数应该编写为尾部调用优化,以避免堆栈爆炸。通过向上传递所有信息(例如max to date)来实现这一点。递归在哪里?内置的
max
功能是什么?:)如果这个答案听起来太苛刻:有两种情况,为什么要用Lisp递归地解决这个问题。要么是家庭作业,要么是你出于兴趣而想学这门语言。现在,如果你感兴趣,我希望你能试着把基本知识做好。每一本初学者书籍或教程都将涵盖评估规则,并具有适当的缩进/格式。如果是家庭作业,这些事情也应该在第一节课中向你解释。您的逻辑是正确的,但是您还需要学习您正在编写代码的语言。另外,确保编辑器与parens匹配。是。我回来只是想在我的答案中添加这些效率提示,以及如何使解决方案更加地道——现在,我只需添加一个指向您答案的指针即可这会调用两次
maximum
,效率很低。我认为没有人给出这个解决方案,因为这可能是一个家庭作业问题。您的代码看起来还可以,但因为您正在学习Lisp:像
max\uu
maxx
ll
m
lst
这样的名称实际上并不习惯。大多数口齿不清的人强烈喜欢连字符的、自我解释的名字。此外,由于CL是一个Lisp-2,因此可以将变量绑定到名称,如
list
,而不会出现问题。最后,虽然实现通常会优化尾部调用(使用正确的设置),但这不是标准所要求的。我知道这只是一个练习,但在CL.danlei中,迭代/应用风格通常是首选的。关于变量的名称,您是对的。我也同意更具功能性的风格是合适的(这就是为什么我对你的答案投了更高的票),但问题是关于递归的,我倾向于回答问题:)足够公平。这是直截了当的答案,这就是为什么我投了赞成票是的,你知道,学习更通用的Lisp让我改变了变量的名称。我编辑了它。是的,现在看起来好多了,依我看。我会命名的