我觉得你的代码很奇怪。例如,您的第三个子句:what's W
for?好像你的意思是:
difference([],[],_).
第二个问题:在第四个子句中,没有什么可以阻止 H 和 D 成为具有相同绑定的自变量。我怀疑你的意思是这样的:
difference([H|T1],[D|T2],T3) :- H \= D, difference(T1,[D|T2],[H|T3]).
修复这些东西似乎可以修复谓词以给出一个合理的答案:
| ?- difference([1,4,4], [1,4], R).
R = [4]
我认为您的前几个条款试图处理不同类型的基本情况,对吗?例如:
difference(L, [], L) % handles the case where the second list is exhausted
difference([], _, []) % handles the case where the first list is exhausted
difference([], [], W) % handles the case where the lists are exhausted at the same time
这样做的一个问题是 L = [] 是一个合法的绑定,所以第一个和第三个子句的意思是一样的。您可能可以安全地删除第三个,因为它会在第一个上匹配并产生相同的答案。第二个子句更有趣,因为它似乎在说不管我们到目前为止做了什么工作,如果第一个列表为空,则结果为空。我觉得这种可能性有点不和谐——你真的可能想要这两种基本情况吗?:
difference([], L, L).
difference(L, [], L).
我仍然不相信,但是在我更好地了解您要完成的工作之前,我可能无法提供更多帮助。例如,应该发生difference([1, 4], [1, 4, 4], R)
什么?我假设你可能想要R = [4]
,但你的代码会产生R = []
。
另外,我觉得不太可能
difference([],[],W):- write(X).
这将是一个有用的调试策略,因为 Prolog 将为 X 生成一个新的变量绑定,因为它没有任何东西可以引用。
我所有更改的最终版本如下所示:
difference(L, [], L) :- !.
difference([], L, L) :- !.
difference([H|T1], [D|T2], T3) :- D \= H, difference(T1, [D|T2], [H|T3]).
difference([H|T1], [H|T2], T3) :- difference(T1, T2, T3).
编辑:这是否满足您的要求?
not_in1(X, Left, Right) :- member(X, Left), \+ member(X, Right).
not_in(X, Left, Right) :- not_in1(X, Left, Right).
not_in(X, Left, Right) :- not_in1(X, Right, Left).
differences(Left, Right, Differences) :-
findall(X, not_in(X, Left, Right), Differences).
?- differences([1,2,3,4], [1,3,5], X).
X = [2,4,5]
如果是这样,我会尝试让您的原始代码生成匹配的答案。
编辑2:好的,所以上面解决方案的问题是它是O(N ^ 2)。在最坏的情况下(两个完全不同的列表),它将不得不将列表 1 中的每个项目与列表 2 中的每个项目进行比较。它没有利用两个列表都是有序的这一事实(我相信这就是你所说的“纵坐标”)。
结果看起来更像您的原始代码,但您的原始代码没有利用项目已订购这一事实。这就是为什么第四和第五种情况看起来令人困惑的原因:您应该根据哪个数字更大来递归列表中的一个或另一个。更正后的代码如下所示:
differences([], Result, Result).
differences(Result, [], Result).
differences([H|Ls], [H|Rs], Result) :- differences(Ls, Rs, Result).
differences([L|Ls], [R|Rs], [L|Result]) :-
L < R,
differences(Ls, [R|Rs], Result).
differences([L|Ls], [R|Rs], [R|Result]) :-
L > R,
differences([L|Ls], Rs, Result).
您可以看到这产生与 O(N^2) 方法相同的结果:
?- differences([1,2,3,4], [1,3,5], X).
X = [2,4,5]
你是对的,你确实需要两种基本情况。这样任何一个列表的其余部分都将成为结果的一部分。大概这些将是最大值([5]
在示例中)。
现在我有三个归纳案例:一个 for <
,一个 for>
和一个 for =
。相等的情况很直观:在两个列表上重复,丢弃两个列表的头部。下一种情况基本上是说如果左头小于右头,则将其添加到结果中并在左尾重复出现。在这种情况下,权利不变。另一个案例是这个案例的镜子。
希望这可以帮助!