下面是Dijkstra最短路径算法的一个实现。它的输入graph表示为源节点到目标节点和弧权重的关联列表。
我的问题是关于以下几个方面:我是否遗漏了一种简化min-path函数的方法?也许伟大而强大的loop可以做reduce的S的工作?
(defun dijkstra (source target graph)
(labels ((min-path (&optional arc-1 arc-2)
(let ((price-1 (cdr arc-1))
(price-2 (cdr arc-2)))
(cond
((and (not (null arc-1)) (not (null arc-2))) (if (< price-1 price-2)
arc-1 arc-2) )
((and (not (null arc-1)) (null (arc-2))) arc-1)
((and (not (null arc-2)) (null (arc-1))) arc-2))))
(get-best-path (visited)
(reduce #'min-path (loop for pick in visited
for start = (car pick)
for cost = (cdr pick)
append (loop for arc in (cdr (assoc start graph))
when (null (assoc (car arc) visited))
collect (cons (car arc) (+ cost (cdr arc))))))))
(loop named main-loop
with visited = (list (cons source 0))
for best-arc = (get-best-path visited)
when (not (null best-arc))
do (push best-arc visited)
until (or (null best-arc)
(eql (car best-arc) target))
finally
(format t "Found shortest path from ~A to ~A: ~A~%" source target best-arc)
(return-from main-loop (cdr best-arc)))))我是Lisp的新手,我希望得到任何建议,尤其是代码中关于Lisp坏习惯和坏Lisp风格的建议,谢谢。
UPD:新版本,有评论应用-没有警告,不像原来的版本。
(defun dijkstra (source target graph)
(labels ((min-path (&optional arc-1 arc-2)
(cond ((and arc-1 arc-2) (if (< (cdr arc-1) (cdr arc-2)) arc-1 arc-2))
(arc-1 arc-1)
(arc-2 arc-2)
(t nil)))
(get-best-path (visited)
(reduce #'min-path
(loop for pick in visited
for start = (car pick)
for cost = (cdr pick)
append (loop for arc in (cdr (assoc start graph))
unless (assoc (car arc) visited)
collect (cons (car arc) (+ cost (cdr arc))))))))
(loop with visited = (list (cons source 0))
for best-arc = (get-best-path visited)
when best-arc do
(push best-arc visited)
until (or (null best-arc) (eql (car best-arc) target))
finally (return (cdr best-arc)))))发布于 2013-03-10 21:16:09
首先,(not (null x))不是非常惯用的;只需使用x。
接下来,您没有处理cond中的所有大小写(显然您指的是(null arc-2)而不是(null (arc-2)))。如果是这样的话,我会放弃let,转而使用嵌套的ifs。
最后,回答您最初的问题:当然,loop可以做reduce所能做的一切,但是如果您对后者的意图更明确,那么就使用它吧!
编辑:unless比when (null ...)更惯用。
https://codereview.stackexchange.com/questions/23701
复制相似问题