如何从两个已经排序的列表中创建一个排序列表

时间:2012-10-03 17:19:23

标签: list sorting merge prolog

在Prolog中,我必须弄清楚如何将两个已排序的列表组合成一个排序列表。换句话说:从2个列表中我必须比较头并将最小值添加到新列表中。我想我已经走得很远,但不知何故它只是不起作用,我无法弄清楚为什么不行。 BTW我没有任何错误。它只是给了false

所以,我希望有人可以告诉我我做错了什么。

sort([],L,L).
sort(L,[],L).
sort([Head1|Tail1],[Head2|Tail2],L) :- 
    Head1 < Head2 -> append([Head1],L,L2), sort(Tail1,[Head2|Tail2],L2) ; 
    Head1 > Head2 -> append([Head2],L,L2), sort([Head1|Tail1],Tail2,L2) ; 
    Head1 == Head2 -> append([Head1],L,L2), append([Head2],L2,L3), 
                                            sort(Tail1,Tail2,L3).

3 个答案:

答案 0 :(得分:3)

您应该稍微简化一下代码:

sort([],L,L).
sort(L,[],L).
sort([Head1|Tail1], [Head2|Tail2], L) :- 
    Head1 < Head2 -> L = [Head1|R], sort(Tail1,[Head2|Tail2],R) ;
    Head1 > Head2 -> L = [Head2|R], sort([Head1|Tail1],Tail2,R) ;
    L = [Head1,Head2|R], sort(Tail1,Tail2,R).

试验:

?- sort([1,2,4,5,18],[1,3,5,10],R).
R = [1, 2, 3, 4, 5, 10, 18] .

命名这样的谓词 sort 确实会产生误导, merge 会好得多....

编辑 L = [Head1,Head2|R]而不是L = [Head1|R],其中Head1 = Head2(之前的测试失败)与sort / 2 Prolog语义不同,删除了重复项。

答案 1 :(得分:2)

在SWI Prolog中,有merge/3内置谓词就是这样做的。所以你不应该把你的谓词称为“排序”;不是。这是“合并”。

接下来,让我们阅读你的定义。

merge([H1|T1], [H2|T2], L) :-

表示合并两个列表会生成合并列表L。到目前为止,非常好。

    H1 < H2 -> append([H1],L,L2), merge(T1,[H2|T2],L2) 

表示,如果H1 < H2答案列表添加前缀 L H1,则会L2,这是合并的结果。等等,什么?那有意义吗?

Prolog不是基本的。我们写的不是“命令”来“做”东西(好吧,它们是,但是以迂​​回的方式)。如果我们想说H1L的首要元素,我们会说:

               L = [H1|L2],        merge(T1,[H2|T2],L2) 
        %% or: append([H1],L2,L), 

等。现在这是有道理的。 :)

答案 2 :(得分:1)

从您问题中的代码中提示,您正在合并已排序的数字列表。 如果这些数字都是整数,并且如果您的Prolog系统提供,请考虑使用此处提供的代码。为什么呢?

  • 实施保留
  • 代码是单调的,使其健壮且灵活:即使在处理非地面数据时,也始终获得逻辑上合理的答案。
  • 主谓词sorted1_sorted2_merged/3表现得像真实的关系。
  • 与内置sort/2不同,此代码保留所有重复项(完全相同的多重性)。
  • 关于要合并的列表中的相同项目,它表现得合理: 输入#1中与输入#2中的某些项相等的项先于合并结果中的项。
  • 实施是有效的,因为它不会使无用的选择点与sorted1_sorted2_merged([1,3,5],[2,4,5,6],Zs)等目标一样。

没有任何进一步的麻烦...这是代码:

:- use_module(library(clpfd)).

sorted1_sorted2_merged([]    ,Ys,Ys).
sorted1_sorted2_merged([X|Xs],Ys,Zs) :-
   sorted2_hd1_tl1_merged(Ys,X,Xs,Zs).

hd1_tl1_hd2_tl2_merged(X,Xs,Y,Ys,Zs) :-
   zcompare(Op,X,Y),
   op_hd1_tl1_hd2_tl2_merged(Op,X,Xs,Y,Ys,Zs).

sorted1_hd2_tl2_merged([]    ,Y,Ys,[Y|Ys]).
sorted1_hd2_tl2_merged([X|Xs],Y,Ys,Zs) :- 
   hd1_tl1_hd2_tl2_merged(X,Xs,Y,Ys,Zs).

sorted2_hd1_tl1_merged([]    ,X,Xs,[X|Xs]).
sorted2_hd1_tl1_merged([Y|Ys],X,Xs,Zs) :-
   hd1_tl1_hd2_tl2_merged(X,Xs,Y,Ys,Zs).

op_hd1_tl1_hd2_tl2_merged(<,X,Xs,Y,Ys,[X|Zs]) :-
   sorted1_hd2_tl2_merged(Xs,Y,Ys,Zs).
op_hd1_tl1_hd2_tl2_merged(=,X,Xs,Y,Ys,[X|Zs]) :- 
   sorted1_hd2_tl2_merged(Xs,Y,Ys,Zs).
op_hd1_tl1_hd2_tl2_merged(>,X,Xs,Y,Ys,[Y|Zs]) :- 
   sorted1_hd2_tl2_merged(Ys,X,Xs,Zs).

对一些疑问!第一:

?- sorted1_sorted2_merged([1,3,4,6],[2,4,5,5,7],Xs).
Xs = [1,2,3,4,4,5,5,6,7].         % succeeds deterministically

它是否也适用于“其他方向”?

?- sorted1_sorted2_merged([1,3,4,6],Ys,[1,2,3,4,4,5,5,6,7]).
Ys = [2,4,5,5,7] ;                % succeeds, but leaves behind choicepoint
false.

?- sorted1_sorted2_merged(Xs,[2,4,5,5,7],[1,2,3,4,4,5,5,6,7]).
Xs = [1,3,4,6] ;                  % succeeds, but leaves behind choicepoint
false.

最后,一个非常普遍的用途:

?- sorted1_sorted2_merged(Xs,Ys,[0,1,2,3]).
Xs = [       ], Ys = [0,1,2,3] ;
Xs = [0,1,2,3], Ys = [       ] ;
Xs = [0      ], Ys = [  1,2,3] ;
Xs = [0,1    ], Ys = [    2,3] ;
Xs = [0,1,2  ], Ys = [      3] ;
Xs = [0,1,  3], Ys = [      2] ;
Xs = [0,  2,3], Ys = [      1] ;
Xs = [0,    3], Ys = [  1,2  ] ;
Xs = [0,  2  ], Ys = [  1,  3] ;
Xs = [  1,2,3], Ys = [0      ] ;
Xs = [    2,3], Ys = [0,1    ] ;
Xs = [      3], Ys = [0,1,2  ] ;
Xs = [    2  ], Ys = [0,1,  3] ;
Xs = [  1    ], Ys = [0,  2,3] ;
Xs = [  1,2  ], Ys = [0,    3] ;
Xs = [  1,  3], Ys = [0,  2  ] ;
false.