Lisp - 爬山

发布于 2024-11-04 14:25:16 字数 1593 浏览 1 评论 0原文

好吧,我有一个 BFS 的 Lisp 实现,我正在尝试将其转换为爬山搜索。

我的 BFS 代码如下所示:

; The list of lists is the queue that we pass BFS.  the first entry and 
; every other entry in the queue is a list.  BFS uses each of these lists and 
; the path to search.  

(defun shortest-path (start end net)   
  (BFS end (list (list start)) net))

;We pass BFS the end node, a queue containing the starting node and the graph 
;being searched(net)   

(defun BFS (end queue net)
  (if (null queue) ;if the queue is empty BFS has not found a path so exit
      nil
      (expand-queue end (car queue) (cdr queue) net)))

(defun expand-queue (end path queue net)
  (let ((node (car path)))
    (if (eql node end)   ; If the current node is the goal node then flip the path
                         ; and return that as the answer
        (reverse path)
        ; otherwise preform a new BFS search by appending the rest of 
        ; the current queue to the result of the new-paths function
        (BFS end (append queue (new-paths path node net)) net))))

; mapcar is called once for each member of the list new-paths is passed
; the results of this are collected into a list
(defun new-paths (path node net)
  (mapcar #'(lambda (n) (cons n path))
         (cdr (assoc node net))))

现在,我知道,我需要扩展看起来最接近目标状态的节点,而不是像在 BFS 中那样总是扩展左节点。
我使用的图表如下所示:

(a (b 3) (c 1))  
(b (a 3) (d 1))

我有一个转换函数可以使其与上述 BFS 实现一起使用,但现在我需要使用这种图表格式将其转换为爬山。

我只是不知道从哪里开始,一直在尝试,但没有成功。我知道我主要需要更改 expand-queue 函数来展开最近的节点,但我似乎无法创建一个函数来确定哪个节点最接近。

感谢您的帮助!

Ok I have a Lisp implementation of BFS that I am trying to convert to do a hill climbing search.

Here is what my BFS code looks like:

; The list of lists is the queue that we pass BFS.  the first entry and 
; every other entry in the queue is a list.  BFS uses each of these lists and 
; the path to search.  

(defun shortest-path (start end net)   
  (BFS end (list (list start)) net))

;We pass BFS the end node, a queue containing the starting node and the graph 
;being searched(net)   

(defun BFS (end queue net)
  (if (null queue) ;if the queue is empty BFS has not found a path so exit
      nil
      (expand-queue end (car queue) (cdr queue) net)))

(defun expand-queue (end path queue net)
  (let ((node (car path)))
    (if (eql node end)   ; If the current node is the goal node then flip the path
                         ; and return that as the answer
        (reverse path)
        ; otherwise preform a new BFS search by appending the rest of 
        ; the current queue to the result of the new-paths function
        (BFS end (append queue (new-paths path node net)) net))))

; mapcar is called once for each member of the list new-paths is passed
; the results of this are collected into a list
(defun new-paths (path node net)
  (mapcar #'(lambda (n) (cons n path))
         (cdr (assoc node net))))

Now, I know that instead of always expanding the left node as I do in the BFS I need to expand the node that seems closest to the goal state.
The graph I am using looks like this:

(a (b 3) (c 1))  
(b (a 3) (d 1))

I have a conversion function to make this work with the above BFS implementation, but now I need to turn this into Hill climbing using this graph format.

I'm just not sure where to begin, and have been trying things to no avail. I know I mainly need to change the expand-queue function to expand the closest node, but I can't seem to make a function to determine which node is closest.

Thanks for the help!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

煞人兵器 2024-11-11 14:25:16

将内容附加到列表末尾是错误的。这是列表中成本最高的操作。
复制整个列表,然后附加另一个列表。您在递归过程中使用它,这意味着每次扩展节点以创建新路径时,它都会完成。

如果您将项目放入队列,则需要查看执行此操作的顺序。在广度优先的情况下,在进入下一个级别之前,人们会访问一个级别中的每个节点。爬山法需要您使用加权函数对候选者进行“最佳”排序。因此,您需要某种函数从当前节点和下一个候选节点计算数值。然后,您需要对候选者进行排序并首先扩展“最佳”节点。对于 LIFO(后进先出)队列,这意味着最有希望的节点需要最后推送,以便它第一个被扩展。请注意,后进先出队列非常适合单链表。 FIFO(先进先出)则不然。

计算机科学的一个典型思想是数据抽象。如果 LIFO QUEUE 是这样的数据结构,您需要定义诸如 MAKE-LIFO-QUEUE、EMPTY-QUEUE-P 等函数,...然后您将使用这些函数来代替 LIST、NULL 等,它们的目的是数据结构更加清晰。这会使你的代码变得更长,但由于 Lisp 列表是通用的并且可以(滥用)用于各种使用场景,因此仅查看列表操作并不能明确其意图。这对于更复杂的图算法尤其重要。

Appending things to the end of a list is wrong. This is the most costly operation with a list.
The whole list gets copied and then the other list is appended. You use it in a recursive procedure, which means that it will done each time you expand a node to create new paths.

If you put items on a queue, you need to look in which order you are doing this. With breadth first, one visits each node in a level, before moving to the next level. Hill-climbing would require that you sort the candidates for the 'best' by using a weighting function. So you need some kind of function computing a numeric value from a current node and the next node candidate. Then you need to sort the candidates and expand first the 'best' node. For a LIFO (last in, first out) queue this means that the most promising node needs to be pushed last, so that it will be the first to be expanded. Note that LIFO queues are a good fit for singly linked lists. FIFO (first in, first out) not so.

A typical idea of computer science is data abstraction. If a LIFO QUEUE is such a data structure, you need to define functions like MAKE-LIFO-QUEUE, EMPTY-QUEUE-P, ... Theses functions you would then use instead of LIST, NULL and others and they make the purpose of the data structure clearer. This makes your code longer, but since Lisp lists are generic and can be (ab-)used for all kinds of usage scenarios, looking at list operations alone does not make their intention clear. Especially important is this for more complicated graph algorithms.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文