【问题标题】:Prolog - generate fibonacci seriesProlog - 生成斐波那契数列
【发布时间】:2017-11-13 08:59:41
【问题描述】:

我想编写为给定 N 生成斐波那契数列的谓词。

fibon(6, X) -> X = [0,1,1,2,3,5].

我有一个谓词来生成斐波那契数列的第 N 个元素:

fib(0, 0).
fib(1, 1).
fib(N, F) :-
    N > 1,
    N1 is N - 1,
    N2 is N - 2,
    fib(N1, F1),
    fib(N2, F2),
    F is F1 + F2.

并且我尝试写 fibon/2,但它不起作用:

fibon(N, [H|T]) :-
    fib(N, H),
    N1 is N - 1,
    fibon(N1, T).

我是这样解决的:

at_the_end(X, [], [X]).
at_the_end(X, [H|T], [H|T2]) :-
    at_the_end(X, T, T2).

revert([], []).
revert([H|T], Out) :-
    revert(T, Out1),
    at_the_end(H, Out1, Out).

fib(0, 0).
fib(1, 1).
fib(N, F) :-
    N > 1,
    N1 is N - 1,
    N2 is N - 2,
    fib(N1, F1),
    fib(N2, F2),
    F is F1 + F2.

fibon(0, [0]).
fibon(N, [H|T]) :-
    fib(N, H),
    N1 is N - 1,
    fibon(N1, T).

fibonacci(In, Out) :-
    fibon(In, Out1),
    revert(Out1, Out).

【问题讨论】:

  • fibon/2 递归的基本情况在哪里?如果N = 0 会发生什么?或者N < 0
  • 事实上,现在可以了。我会实现这个问题。
  • 你真的应该在你的递归子句中有一个N > 0 条件,以避免由于N 变为fibon(0, []),因为@987654331 @ 不是斐波那契数。如果您没有斐波那契数 (0),那么您应该有一个空列表,是吗?

标签: prolog fibonacci


【解决方案1】:

如果您乐于颠倒序列的结果顺序,则可以这样做:

纤维(0,[0])。 fib(1, [1,0])。 fib(N, [R,X,Y|Zs]) :- N > 1, N1 是 N - 1, fib(N1, [X,Y|Zs]), R 是 X + Y。

然后?- fib(15,Z). 给我[610, 377, 233, 144, 89, 55, 34, 21, 13, 8, 5, 3, 2, 1, 1, 0]

很容易加入reverse/3 谓词:

反向([],Z,Z)。 反向([H|T],Z,A):-反向(T,Z,[H|A])。

【讨论】:

    【解决方案2】:

    您可以通过使递归谓词尾递归来加快速度:

    fib_seq(0,[0]).                   % <- base case 1
    fib_seq(1,[0,1]).                 % <- base case 2
    fib_seq(N,Seq) :-
       N > 1,
       fib_seq_(N,SeqR,1,[1,0]),      % <- actual relation (all other cases)
       reverse(SeqR,Seq).             % <- reverse/2 from library(lists)
    
    fib_seq_(N,Seq,N,Seq).
    fib_seq_(N,Seq,N0,[B,A|Fs]) :-
       N > N0,
       N1 is N0+1,
       C is A+B,
       fib_seq_(N,Seq,N1,[C,B,A|Fs]). % <- tail recursion
    

    首先让我们观察您的示例查询是否按预期工作:

    ?- fib_seq(6,L).
    L = [0, 1, 1, 2, 3, 5, 8] ;
    false.
    

    请注意,该列表没有六个元素,如您在帖子开头的示例中那样,而是七个。这是因为谓词从零开始计数(顺便说一句,这与您添加到帖子中的谓词 fibonacci/2 的行为相同)。

    为了比较(与@Enigmativity 帖子中的fib/2)原因,我们要么从fib_seq/2 中删除目标reverse/2(然后你会得到除N=0 和N=1 之外的所有解决方案以相反的顺序):

    ?- time((fib(50000,L),false)).
    % 150,001 inferences, 0.396 CPU in 0.396 seconds (100% CPU, 379199 Lips)
    false.
    
    ?- time((fib_seq(50000,L),false)).
    % 150,002 inferences, 0.078 CPU in 0.078 seconds (100% CPU, 1930675 Lips)
    false.
    

    或者保留 fib_seq/2 原样,并使用附加目标 reverse/2 测量 fib/2(然后 fib/2 解决方案中的 R 对应于 fib_seq/2 解决方案中的 L):

    ?- time((fib(50000,L),reverse(L,R),false)).
    % 200,004 inferences, 0.409 CPU in 0.409 seconds (100% CPU, 488961 Lips)
    false.
    
    ?- time((fib_seq(50000,L),false)).
    % 200,005 inferences, 0.088 CPU in 0.088 seconds (100% CPU, 2267872 Lips)
    false.
    

    在旁注中,我会敦促您在尝试获得更大的列表时将您的谓词 fibonacci/2 与发布的解决方案进行比较,例如 N > 30。

    【讨论】:

      【解决方案3】:

      使用scanl 只是为了好玩。和一些标准的 dcgs。

      :-use_module(library(clpfd)).
      
      my_plus(X,Y,Z):-
          Z#>=0,
          Z#=<1000, % Max size optional
          Z#=X+Y.
      
      list([])     --> [].
      list([L|Ls]) --> [L], list(Ls).
      
      concatenation([]) --> [].
      concatenation([List|Lists]) -->
              list(List),
              concatenation(Lists).
      
      fib(Len,List1):-
          X0=1,
          length(List1,Len),
          length(End,2),
          MiddleLen #= Len - 3,
          length(Middle,MiddleLen),
          phrase(concatenation([[X0],Middle,End]), List1),
          phrase(concatenation([[X0],Middle]), List2),
          phrase(concatenation([Middle,End]), List3),
          scanl(my_plus,List2,X0,List3).
      

      【讨论】:

        【解决方案4】:

        如果您想收集斐波那契数列的第一个 N 元素列表,您可以使用以下规则。只需记住初始化前 2 个谓词即可。

        fib(0, [1]).
        fib(1, [1, 1]).
        
        fib(N, L) :-
            N > 1,
            N1 is N - 1,
            N2 is N - 2,
            fib(N1, F1),
            last(F1, L1),
            fib(N2, F2),
            last(F2, L2),
            L_new is L1 + L2,
            append(F1, [L_new], L). 
        

        【讨论】:

        • 您的意思是append(F1, [L_new], L).F 未在 fib 中定义。
        • 是的,我的错。我会改正的!感谢您的评论
        猜你喜欢
        • 2011-12-18
        • 2015-04-25
        • 1970-01-01
        • 2020-07-16
        • 1970-01-01
        • 2012-04-26
        • 2011-02-20
        • 2013-02-24
        • 1970-01-01
        相关资源
        最近更新 更多