我将如何提高效率(Scheme)?

时间:2012-12-27 19:50:17

标签: scheme

我有这段代码:

(define tree `(A (B (C)) (D (E)) (C (E))))

(define (prog1 graph)
    (let ([seen `()])
      (define (sub g)
          (cond 
              [(member (car g) seen) `()]
              [else 
               (set! seen (cons (car g) seen))
               (cond
                 [(null? (cdr g)) (list (car g))]
                 [else
                  (cons (car g) (map sub (cdr g)))])])) 
    (delete `() (sub graph))))

(define delete
  (lambda (x y)
      (if (null? y )
            `()
      (if (eqv? (car y) x)
           (delete x (cdr y))
      (cons (car y) (delete x (cdr y)))))))

它打印一个连接图,其中所有节点都出现一次。

正在运行(prog1 tree)

打印:(A (B (C)) (D (E)))

我已经研究了lisp中的各种深度优先搜索(类似于我正在尝试做的事情),并且它们看起来更加优雅,有些使用迭代方法。我知道程序效率不高(在大树上它运行得很慢)所以我该如何提高这段代码的效率呢?

谢谢,詹姆斯

2 个答案:

答案 0 :(得分:1)

在大多数情况下,此代码中的瓶颈不是树遍历,而是member查找。函数的复杂性似乎大致为O(M * N),其中M是不同节点的数量,N是总节点的数量。 M作为一个因素进入这个因素的原因是因为你在线性列表中查找节点,这需要时间与列表的长度成比例(在你的情况下,它与不同节点的数量成正比)。 p>

摆脱M的方法是使用更有效的数据结构进行查找。例如,R6RS定义了哈希表。

答案 1 :(得分:1)

member过程每次调用时都会对列表执行O(n)查找。这不是我们想要快速测试集合成员资格的原因,因为你应该使用一个数据结构,为集合中添加元素和测试元素成员资格提供O(1)复杂性,理想情况下是一个Set数据结构或者它的位置是Hash表。例如,在Racket中尝试替换这些行(或使用Scheme解释器中的默认哈希表实现):

(let ([seen `()]) => (let ([seen (make-hash)])

[(member (car g) seen) `()] => [(hash-has-key? seen (car g)) '()]

(set! seen (cons (car g) seen)) => (hash-set! seen (car g) 'ok)

此外,通常您希望在代码中使用quotes'()而不是quasiquotes`(),请参阅链接以了解差异以及何时适当使用quasiquoting。

最后,您可以使用内置的remove程序,无需实施自己的delete