2

当我们使用 Knuth-Morris-Pratt 算法时,这是在 Scheme 中计算失败函数(我们必须返回多少步)的代码:

(define (compute-failure-function p)
    (define n-p (string-length p))
    (define sigma-table (make-vector n-p 0))
    (let loop
        ((i-p 2)
         (k 0))
      (cond
          ((>= i-p n-p)
           (vector-set! sigma-table (- n-p 1) k))
          ((eq? (string-ref p k)
                (string-ref p (- i-p 1)))
           (vector-set! sigma-table i-p (+ k 1))
           (loop (+ i-p 1) (+ k 1)))
          ((> k 0)
           (loop i-p (vector-ref sigma-table k)))
          (else ; k=0
           (vector-set! sigma-table i-p 0)
           (loop (+ i-p 1) k))))
    (vector-set! sigma-table 0 -1)
    (lambda (q)
        (vector-ref sigma-table q)))

但我不明白什么时候的部分k > 0。有人可以解释一下吗?

4

1 回答 1

2

我看到您对namedlet的语法感到困惑。这篇文章很好地解释了它是如何工作的,但也许一个语法更熟悉的例子会让事情变得更清楚。以 Python 中的这段代码为例,它将 1 到 10 的所有整数相加:

sum = 0
n = 1
while n <= 10:
  sum += n
  n += 1

print(sum)
=> 55

现在让我们尝试以递归方式编写它,我将调用我的函数loop。这是完全等价的:

def loop(n, sum):
    if n > 10:
        return sum
    else:
        return loop(n + 1, n + sum)

loop(1, 0)
=> 55

在上面的例子中,loop函数实现了一次迭代,参数n用于跟踪当前位置,参数sum累加答案。现在让我们编写完全相同的代码,但在 Scheme 中:

(let loop ((n 1) (sum 0))
  (cond ((> n 10) sum)
        (else (loop (+ n 1) (+ n sum)))))
=> 55

现在我们已经定义了一个名为的本地过程,然后loop使用初始值10它的参数自动调用它。当达到递归的基本情况时,我们返回,否则我们继续调用这个过程,为参数传递更新的值。它与 Python 代码中的完全相同!不要被语法所迷惑。nsumsum

在您的算法中,i-pk是迭代变量,分别初始化为20。根据哪个条件为真,当我们loop用更新的值再次调用i-pand时迭代将继续k,或者在(>= i-p n-p)达到这种情况时结束,此时循环退出并且计算值在变量中sigma-table。该过程以返回一个新函数结束,称为“故障函数”。

于 2020-08-18T15:54:43.653 回答