合并两个有序列表ProLog

时间:2018-05-12 00:23:53

标签: prolog

嘿所以这是我的代码到目前为止。我只是在prolog的初学者,但我需要它在学校

firstElement([_|_], [Elem1|List1], [Elem2|List2]):- 
     Elem1 =< Elem2, merge([Elem1] , List1, [Elem2|List2]);
     merge([], [Elem2], List2).

merge([Head|Tail], [Elem1|List1], [Elem2|List2]):-
     Elem1 =< Elem2,!, add(Elem1,[Head|Tail],[Head|Tail1]),
     merge([Head|Tail1], List1, [Elem2|List2]);
     add(Elem2,[Head|Tail],[Head|Tail1]),
     merge([Head|Tail1], [Elem1|List1], List2).

merge([Head|Tail], [], [Elem2|List2]):- 
     add(Elem2,[Head|Tail],[Head|Tail1]).

merge([Head|Tail], [Elem1|List1], []):-
     add(Elem1,[Head|Tail],[Head|Tail1]).

merge([Head|Tail], [], []).

add(X,[],[X]).

add(X,[Y|Tail],[Y|Tail1]):-
    add(X,Tail,Tail1).

我发现每次合并时它都会忘记最后一个数字,所以它最终会回归。

1 个答案:

答案 0 :(得分:4)

我认为你的代码已经非常混乱了。一个完整的解决方案可以没有帮助者,只有几个条款。

首先让我们讨论涉及空列表的两个基本案例:

merge(X, [], X).
merge([], X, X).

你没有这些,但我看到某种认识,你需要特别在你的第二和第三个条款中处理空列表,但我认为你感到困惑和过于复杂。这两个条款实际上涵盖了三种情景。这两个列表都是空的情况是由他们两个覆盖的免费赠品,但由于这种情况可以解决merge([], [], []),所以它已被覆盖。这里的一个重要想法是,如果你耗尽任何一个列表,因为它们已经排序,你在另一个列表中留下的是你的结果。想一想。

这留下了有趣的案例,我们在两个列表中都有一些项目。基本上你想要做的是选择两者中较小的一个,然后重复整个其他列表和你选择的较小值的剩余部分。这是一个条款:

merge([L|Ls], [R|Rs], [L|Merged]) :-
  L @< R,
  merge(Ls, [R|Rs], Merged).

以下是您应该注意的事项:

  • “结果”在递归构造的余数之前加L
  • merge的递归调用使用[R|Rs]重建整个第二个列表。

应该可以通过查看这个来构建另一个子句。

作为Prolog的中级用户,我自然会对使用两个子句来做这项工作有点怀疑,因为它会创建不必要的选择点。作为初学者,你很想用切割来消除这些选择点,这对你来说很糟糕。更中间的方法是使用条件运算符将两个必要的子句包含在一个中:

merge([L|Ls], [R|Rs], [N|Ns]) :-
    (   L @< R -> 
        N = L, merge(Ls, [R|Rs], Ns)
    ;   —- other case goes here
    ).

专家可能会使用if_/3来构建它:

@<(X,Y,true) :- X @< Y.
@<(X,Y,false) :- X @>= Y.

merge([L|Ls], [R|Rs], [N|Ns]) :-
    if_(@<(L,R),
        (N = L, merge(Ls, [R|Rs], Ns)),
        ( -- other case here )).

无论如何,我希望这有助于说明情况。