Scheme深度优先搜索图函数

时间:2010-05-05 16:23:15

标签: recursion scheme racket

这是一个功课问题,我正在尝试在Scheme中执行深度优先搜索功能,这是我到目前为止编写的代码:

(define explore
(λ(node visited)
  (let* ([neighbors             (force (cdr node))]
         [next        (nextNode visited neighbors)]
         [is-visited        (member? node visited)])

    (cond

      ;if I have no unvisited neighbours print current node and go up one level
      [(equal? next #f)
       (begin
         (display (car node))
         (display " "))]

      ;if current node is not visited and I have unvisited neighbors
      ;print current node,mark as visited and visit it's neighbors
      [(and (equal? is-visited #f) (not (equal? next #f)))
       (begin
         (display (car node))
         (display " ")
         (explore next (cons node visited)))])

    ;go and visit the next neighbor
    (if (not (equal? (nextNode (cons next visited) neighbors) #f ))
     (explore (nextNode (cons next visited) neighbors) (cons node visited))))))  

'node'是当前节点
'visited'是一个巫婆列表,我跟踪我访问过的节点 'nextNode'是一个函数,返回第一个未访问的邻居(如果有的话)或#f,否则为
'会员?'测试节点是否在访问列表中

Graph表示使用相邻的使用letrec对节点的引用,这就是我在'neighbors'中使用force的原因: 例如:
(letrec([node1(list“NY”(delay(list node2 node3)))],其中node2和node3被定义为node1

我正在处理的问题是,当我退出递归时,我访问过的列表无法跟踪我访问过的某些节点,我该如何解决这个问题?

2 个答案:

答案 0 :(得分:1)

您必须将新访问列表作为递归调用的返回值。您要么必须修改探索,以便它返回其访问列表,或者定义一个辅助函数,而不是探索。然后在你递归之后,你将不得不使用函数返回的新访问列表。

编辑: 也许更好的方法是重新调整你的功能。我认为它比它需要的更复杂。你只是在进行深度优先遍历,对吗?不是真的搜索?你可以尝试更像这样的东西,使用显式堆栈来跟踪要访问的节点,以及访问的节点列表:


(define dft
  (lambda (graph)
    (helper graph '(1) '())))

(define helper
  (lambda (graph stack visited)
    (if (empty? stack)
      '() ;we're done. you've got a nice list of visited nodes now, what will you do with it? Return it?
      (let ([currentNode (car stack)])
        (if (member? currentNode visited) 
            (helper graph 
                    ;what do you think the next two parameters are?
                    )
            (begin
              (display currentNode)
              (helper graph 
                      ;what do you think the next two parameters are?
                      ))))))

由于这是一个家庭作业问题,我已经为辅助函数留下了两个参数供你填写。这种方法最好的方法是将它更改为广度优先遍历非常简单。

这是一个提示:两种不同情况的参数会略有不同。

答案 1 :(得分:0)

我也回答了here

执行此操作的一种方法是返回列表,以便在更高级别的递归时访问它。

另一种方法是将列表存储在递归之外的变量中。换句话说,没有存储在堆栈中。由于为此使用全局变量不是一个好主意,我们需要进行一些局部递归。

以下代码是一种愚蠢的方式来反转列表,但它确实说明了我所说的技术。

(define (letrecreverse lst)
  (letrec ((retlist '())
           (reverse (lambda (lst)
                      (if (null? lst)
                          '()
                          (begin
                            (set! retlist (cons (car lst) retlist))
                            (reverse (cdr lst)))))))
    (reverse lst)
    retlist))

(letrecreverse '(1 2 3 4))
;outputs '(4 3 2 1)

你可以为你的目的采用这种技术吗?