【问题标题】:Prolog - divide list into 3 partsProlog - 将列表分为 3 部分
【发布时间】:2023-04-10 18:27:01
【问题描述】:

我正在尝试将 Prolog 中的列表分成 3 个相等的部分(...嗯,尽可能相等)。 我的算法如下:

  1. 找出初始列表的大小。
  2. 使用两个额外参数调用该过程(列表的大小和一个计数器,它会告诉我何时应该停止向一个列表添加元素并开始向另一个列表添加元素)

过程如下:

有4个参数:

div3(InitialList,FirstNewList,SecondNewList,ThirdNewList).

带有 2 个额外参数:

div3(InitialList,FirstList,SecondList,ThirdList,InitialListSize,Counter).

这是我的代码:

div3([],[],[],[]).
div3([X],[X],[],[]).
div3([X,Y],[X],[Y],[]).
div3([X,Y,Z],[X],[Y],[Z]).
div3([X | Y],A,B,C) :- length([X | Y],Sz),
                       Sz1 is 0,
                       div3([X | Y],A,B,C,Sz,Sz1).

div3([X | Y],A,B,C,Sz,Sz1) :- Sz1 < Sz//3, % am I done adding to the 1st list?
                              append(X,L,A), % add to the 1st list
                              Sz2 is Sz1+1, % increment the counter
                              div3(Y,L,B,C,Sz,Sz2),!.

div3([X | Y],A,B,C,Sz,Sz1) :- Sz1 < 2*Sz//3, % am I done adding to the 2nd list?
                              append(X,L,B), % add to the 2nd list
                              Sz2 is Sz1+1, % increment the counter
                              div3(Y,A,L,C,Sz,Sz2),!.

div3([X | Y],A,B,C,Sz,Sz1) :- Sz1 < Sz, % am I done adding to the 3rd list?
                              append(X,L,C),% add to the 3rd list
                              Sz2 is Sz1+1, % increment the counter
                              div3(Y,A,B,L,Sz,Sz2),!.

【问题讨论】:

    标签: list split prolog


    【解决方案1】:

    我认为您的代码的第一部分几乎是正确的... 您正在寻找的是具有 3 个基本案例和一个递归子句的递归谓词。

    div3([], [], [], []).
    div3([X], [X], [], []).
    div3([X,Y], [X], [Y], []).
    div3([X,Y,Z|Tail], [X|XTail], [Y|YTail], [Z|ZTail]):-
      div3(Tail, XTail, YTail, ZTail).
    

    【讨论】:

    • 我不相信。我就是这么简单。这完美地工作。非常感谢。
    【解决方案2】:

    递归谓词 div3/5 的代码中没有结束情况,前 3 个子句仅适用于 div3/3 调用(这就是为什么调用像 div3([4,2,42],X,Y ,Z) 成功)

    另外,您使用一个元素而不是列表调用 append/3,因此它会失败(除非您有一个列表列表,但即使在这种情况下,它也不是您想要的)

    我建议切换到更“声明性”的方法,也许使用像 get_N_elements(List,List_N,Rest) 这样的谓词来避免代码重复

    【讨论】:

      【解决方案3】:

      如果保持源顺序无关紧要,以下就足够了。

      divide( []        , []     , []     , []     ) .  % we're done when the source list is exhausted, OR ...
      divide( [X]       , [X]    , []     , []     ) .  % - it's only got 1 element, OR ...
      divide( [X,Y]     , [X]    , [Y]    , []     ) .  % - it's only got 2 elements
      divide( [X,Y,Z|T] , [X|Xs] , [Y|Ys] , [Z|Zs] ) :- % otherwise, split three elements amount the result lists and
        divide(T,Xs,Ys,Zs)                              % - recurse down.
        .                                               %
      

      上面的代码对列表进行分区

      [a,b,c,d,e,f,g]
      

      进入

      • [a,d,g]
      • [b,e]
      • [c,f]

      如果您希望保持顺序,这将起作用,描述什么构成正确的解决方案(例如,长度尽可能相等的列表)并让append/3 找到正确的解决方案:

      divide( L , X , Y , Z ) :-
        append(X,T,L)               , % split X off as a prefix of the source list L
        append(Y,Z,T)               , % divide the remainder (T) into a prefix Y and suffix Z
        length(X,X1)                , % compute the length of X
        length(Y,Y1)                , % compute the length of Y
        length(Z,Z1)                , % compute the length of Z
        min_max([X1,Y1,Z1],Min,Max) , % determine the shortest and longest such length
        Max - Min =< 1 ,              % and ensure that the delta is 1 or less
        .
      
      min_max([],0,0) .
      min_max([H|T],Min,Max) :-
        min_max(T,H,H,Min,Max)
        .
      
      min_max([],Min,Max,Min,Max) .
      min_max([H|T], T1 , T2 , Min , Max ) :-
        ( H < T1 -> T3 = H ; T3 = T1 ) ,
        ( H > T2 -> T4 = H ; T4 = T2 ) ,
        min_max(T,T3,T4,Min,Max)
        .
      

      上面基本都说了

      将列表 L 分成 3 个子列表 X、Y 和 Z,使得 每个子列表不超过 1 个。

      在这种情况下,您应该会看到列表

      [a,b,c,d,e,f,g]
      

      分为

      • [a,b]
      • [c,d]
      • [e,f,g]

      应该注意,这是不确定的,回溯会找到所有可能的此类解决方案。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-07-25
        • 1970-01-01
        • 1970-01-01
        • 2017-10-04
        • 1970-01-01
        • 2014-11-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多