在Scheme中实现深度优先搜索的问题

时间:2011-03-01 19:49:09

标签: scheme

我试图在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作为回报。因此,算法中的回溯可能是错误的。但是我看了很长时间的代码,我真的找不到问题..

2 个答案:

答案 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的第一个值。