Common lisp 使用递归的列表的最大值?
我的任务是在lisp中编写函数,通过使用递归查找作为函数参数给出的列表的最大值。我已经尝试过,但有一些错误。我是lisp新手,正在使用eclipse的cusp插件。这是我的代码: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,后者是实际的函数名
(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让我改变了变量的名称。我编辑了它。是的,现在看起来好多了,依我看。我会命名的