我试图在Scheme中实现Depth First Search,但我只能让它部分工作。 这是我的代码:
(define (depth-first-search graph node neighbour path dest)
(cond ((null? neighbour) #f)
((equal? node dest) path)
((member (car neighbour) path) (depth-first-search graph node (cdr neighbour) path dest))
((memq (car neighbour) (car graph)) (depth-first-search (cdr graph) (car neighbour) (memq (car neighbour) (car graph)) (append path (list (car neighbour))) dest))
(else depth-first-search (cdr graph) path dest)))
这是我的图表,数据结构:
(define complete-graph
'((a b c d e)
(b a c)
(c a b f)
(d a e h)
(e a d)
(f c g i)
(g f h i j)
(h d g j)
(i f g j)
(j g h i)))
这就是我称之为程序的方式:
(depth-first-search complete-graph (caar complete-graph) (cdar complete-graph) (list (caar complete-graph)) 'd)
程序应该将起始节点到dest(ination)的完整路径作为列表返回,但它似乎只适用于某些起始节点和目标节点。如果我以'a和'c开头,它会返回正确的列表'(a b c),但如果我尝试使用'a和'd,我会得到#f作为回报。因此,算法中的回溯可能是错误的。但是我看了很长时间的代码,我真的找不到问题..
答案 0 :(得分:1)
假设节点'a有孩子'(b c d e),节点'b有孩子'(a c),节点......首先你需要一个将节点扩展到其子节点的函数。
(define (expand graph node)
(let ((c (assq node graph)))
(if c (cdr c) '())))
第二:你必须记住所有访问过的节点。一般来说,帽子与路径不同(在这个例子中可能无关紧要)。第三:您需要记住要访问的所有节点(来自节点扩展过程的结果)。所以定义一个辅助函数
(define (dfs* graph visited border path dest)
如果没有剩余的节点可供访问,则不存在任何道路。
(cond ((null? border) #f)
如果边框中的第一个元素等于我们的目的地,那么我们很高兴
((eq? (car border) dest) (cons (car border) path))
让我们检查所有访问过的节点。如果之前访问了边界中的第一个节点,则在没有节点扩展的情况下继续
((memq (car border) visited)
(dfs* graph visited (cdr border) path dest))
否则展开边框的第一个节点
(else (dfs* graph
(cons (car border) visited)
(append (expand graph (car border)) (cdr border))
(cons (car border) path)
dest))))
使用起始值,边界和路径调用该辅助函数:
(define (dfs graph src dst)
(dfs* graph '() (list src) '() dst)
对于第一次呼吸搜索:将扩展节点附加到边界
的末尾编辑: a)访问过和路径相同,你可以放弃其中一个 b)以相反的顺序返回路径 c)该过程不正确,路径包含所有访问过的节点。但是dfs *结果的后期处理将完成这项工作。
答案 1 :(得分:0)
您不希望在深度优先搜索时更改图形,只需更改当前节点。如果你想纯粹在功能上做事,那么你的功能应该是:
(define (depth-first-search graph node dest path)
(let dfs ((node node) (path path))
(let ((recur (lambda (node) (dfs node (cons node path)))))
; Write code here
; Recursive calls should use recur, not dfs or depth-first-search
...)))
(返回路径或#f
作为结果)。您可以使用ormap
(在Racket或SRFI-1中)迭代节点的所有邻居,返回不是#f
的第一个值。