以递归方式将列表附加到列表列表

时间:2011-03-05 21:56:00

标签: list prolog

我想解决的问题如下:

我给出了一个排序列表,我必须在列表中配对第一个和最后一个项目。然后我必须将列表中的第2个和(最后1个)项配对,直到列表为空或剩下1个元素。然后我必须返回对的列表。

我决定针对这个问题采取的步骤是首先检查列表的长度是否大于1.如果不是,则表示我们有一个0或1个元素的列表。

然后我获取给定列表中的第一个和最后一个项目,从列表中删除它们,配对它们,然后在新列表上递归调用相同的谓词。一旦我一直走到0/1项目,然后我会弹回并将它们附加到我的返回列表中。

我遇到的问题是,当我尝试将对L = [first,last]附加到我的返回列表时,它会出错。我的代码列在下面。

T是我的输入列表。

first/2只获取列表中的第一项。 pair/3P1P2删除了一些信息,然后创建L = [P1,P2]

getMatches(T,K,ReturnList) :-
   (  length(T,Val),
      Val > 1, 
      first(T,P1), 
      last(T, P2),
      delete(T,P1,G),
      delete(G,P2,H),
      pair(P1,P2,L),
      getMatches(H,K,ReturnList),
      append(L,K,ReturnList)
   ;  first(T,_),
      K = []
   ).

使用示例: 如果是T = [1, 2, 3, 4, 5]那么 ReturnList = [[1,5], [2, 4]]应该成立。

3 个答案:

答案 0 :(得分:2)

我们根据常用的列表谓词append/3定义list_pairs/2

list_pairs([] , []).
list_pairs([_], []).
list_pairs([A,B|Xs0], [A-Z|Yss]) :-
   append(Xs, [Z], [B|Xs0]),
   list_pairs(Xs, Yss).

请注意,我们不会将一对XY表示为列表[X,Y],而是将其作为复合X-Y。这个惯例也是惯用的,广泛的,也是更有效的!

以下是list_pairs/2最常见查询

?- list_pairs(Es, Pss).
   Es = []                 , Pss = []
;  Es = [_]                , Pss = []
;  Es = [A,B]              , Pss = [A-B]
;  Es = [A,_,B]            , Pss = [A-B]
;  Es = [A,B,C,D]          , Pss = [A-D,B-C]
;  Es = [A,B,_,C,D]        , Pss = [A-D,B-C]
;  Es = [A,B,C,D,E,F]      , Pss = [A-F,B-E,C-D]
;  Es = [A,B,C,_,D,E,F]    , Pss = [A-F,B-E,C-D]
;  Es = [A,B,C,D,E,F,G,H]  , Pss = [A-H,B-G,C-F,D-E]
;  Es = [A,B,C,D,_,E,F,G,H], Pss = [A-H,B-G,C-F,D-E]
...

答案 1 :(得分:2)

这是对this earlier answer的跟进,并对其进行了改进 避免创造无用的选择点和 将O(N 2 )的Big-O复杂度降低到O(N)。

list_pairs_lin([], []).
list_pairs_lin([X|Xs], XYs) :-
   reverse(Xs, Ys),
   ahead_keys_values_pairs(Xs, [X|Xs], Ys, XYs).

ahead_keys_values_pairs([], _, _, []).
ahead_keys_values_pairs([_|Fs0], [X|Xs], [Y|Ys], [X-Y|XYs]) :-
   maybe_ahead(Fs0, Fs),
   ahead_keys_values_pairs(Fs, Xs, Ys, XYs).

maybe_ahead([], []).
maybe_ahead([_|Xs], Xs).

让我们用SWI-Prolog 7.3.15运行一些查询!

使用list_pairs_lin/2时,我们仍然可以得到合理的答案吗?

?- length(Es, N), numlist(1, N, Es), list_pairs_lin(Es, Pss).
   N = 1, Es = [1]                , Pss = []
;  N = 2, Es = [1,2]              , Pss = [1-2]
;  N = 3, Es = [1,2,3]            , Pss = [1-3]
;  N = 4, Es = [1,2,3,4]          , Pss = [1-4,2-3]
;  N = 5, Es = [1,2,3,4,5]        , Pss = [1-5,2-4]
;  N = 6, Es = [1,2,3,4,5,6]      , Pss = [1-6,2-5,3-4]
;  N = 7, Es = [1,2,3,4,5,6,7]    , Pss = [1-7,2-6,3-5]
;  N = 8, Es = [1,2,3,4,5,6,7,8]  , Pss = [1-8,2-7,3-6,4-5]
;  N = 9, Es = [1,2,3,4,5,6,7,8,9], Pss = [1-9,2-8,3-7,4-6]
...

是的!复杂性怎么样?

?- set_prolog_flag(toplevel_print_anon, false).
true.

?- numlist(1, 5000, _Xs), time(list_pairs(_Xs,_)).
% 6,252,500 inferences, 2.302 CPU in 2.301 seconds (100% CPU, 2716404 Lips)
true ;              % succeeds, but leaves behind useless choicepoint
% 2,503 inferences, 0.001 CPU in 0.001 seconds (100% CPU, 1716259 Lips)
false.              % terminates universally

?- numlist(1, 5000, _Xs), time(list_pairs_lin(_Xs,_)).
% 10,003 inferences, 0.003 CPU in 0.003 seconds (100% CPU, 3680523 Lips)
true.                % succeeds deterministically

答案 2 :(得分:1)

getMatches(List, ReturnList) :-        % getMatches/2
    getMatches(List, [], Answer),
    reverse(Answer, ReturnList),
    !.

getMatches(List, ListAns, ListAns) :-  % getMatches/3
    length(List, L),
    L < 2.
getMatches([H | Tail], List, Ans) :-
    last(Tail, Last),
    delete(Tail, Last, NewTail),
    append([[H, Last]], List, NewList),
    getMatches(NewTail, NewList, Ans).

?- getMatches([1,2,3,4,5],X).
X = [[1, 5], [2, 4]].