在我的另一个答案fib/2
中提供的朴素递归实现的时间复杂度为 O(φ^ N ),其中 φ 是黄金比例,即指数时间。这是一个尾递归实现,其时间复杂度为 O( N ),即线性时间:fib/2
fib(N, F) :-
fib(N, 0, s(0), F, F).
fib(0, A, _, A, _).
fib(s(0), _, B, B, _).
fib(s(s(N)), A, B, s(F), s(X)) :-
sum(A, B, S),
fib(s(N), B, S, s(F), X).
sum(0, N, N).
sum(s(N1), N2, s(S)) :-
sum(N1, N2, S).
示例查询
最一般的查询(所有参数都是免费的):
?- fib(N, F).
F = N, N = 0
; F = N, N = s(0)
; F = s(0), N = s(s(0))
; F = s(s(0)), N = s(s(s(0)))
; F = s(s(s(0))), N = s(s(s(s(0))))
; F = N, N = s(s(s(s(s(0)))))
; F = s(s(s(s(s(s(s(s(0)))))))), N = s(s(s(s(s(s(0))))))
; F = s(s(s(s(s(s(s(s(s(s(s(s(s(0))))))))))))), N = s(s(s(s(s(s(s(0)))))))
; …
带有第一个参数的查询是免费的:
?- fib(N, 0).
N = 0
; false.
?- fib(N, s(0)).
N = s(0)
; N = s(s(0))
; false.
?- fib(N, s(s(0)).
N = s(s(s(0)))
; false.
?- fib(N, s(s(s(0))).
N = s(s(s(s(0))))
; false.
?- fib(N, s(s(s(s(s(0)))))).
N = s(s(s(s(s(0)))))
; false.
?- fib(N, s(s(s(s(s(s(s(s(0))))))))).
N = s(s(s(s(s(s(0))))))
; false.
带有第二个免费参数的查询:
?- fib(0, F).
F = 0
; false.
?- fib(s(0), F).
F = s(0)
; false.
?- fib(s(s(0)), F).
F = s(0)
; false.
?- fib(s(s(s(0))), F).
F = s(s(0))
; false.
?- fib(s(s(s(s(0)))), F).
F = s(s(s(0)))
; false.
?- fib(s(s(s(s(s(0))))), F).
F = s(s(s(s(s(0)))))
; false.