我知道如何为2个列表做到这一点:
append([],L,L).
append([H|T],L,[H|R]):-append(T,L,R).
但如何为3做呢?不使用2个附加列表两次。
答案 0 :(得分:4)
append3(Xs, Ys, Zs, XsYsZs) :-
append(Xs, YsZs, XsYsZs),
append(Ys, Zs, YsZs).
尽可能高效。费用约为| Xs
| + | Ys
|推论。但是,您可能尝试使用以下约2 | Xs
| + | Ys
|来定义它。推论。
append3bad(Xs, Ys, Zs, XsYsZs) :-
append(Xs, Ys, XsYs),
append(XsYs, Zs, XsYsZs).
此外,终止是much better in the first case:
append3(Xs, Ys, Zs, XsYsZs)
terminates_if b(Xs),b(Ys);b(XsYsZs)
意味着需要知道Xs
和Ys
或XsYsZs
才能使append3/4
终止
......与
append3bad(Xs, Ys, Zs, XsYsZs)
terminates_if b(Xs),b(Ys);b(Xs),b(XsYsZs)
^^^^^
代表append3bad/4
,其中XsYsZs
还不够,但另外还必须知道Xs
。
答案 1 :(得分:4)
要有效地附加列表,请考虑使用差异列表。差异列表是使用具有两个列表的术语表达的列表。最常见的表示法使用(-)/2
作为该术语的函子。例如,列表[1,2,3]
可以表示为:
[1,2,3| Tail]-Tail.
通过跟踪列表尾部,即开放端,您可以有效地执行多个操作。例如,您可以通过实例化尾部将元素附加到O(1)中的列表末尾:
add_to_end_of_list(List-Tail, Element, List-Tail2) :-
Tail = [Element| Tail2].
或者简单地说:
add_to_end_of_list(List-[Element| Tail2], Element, List-Tail2).
让我们试一试:
?- add_to_end_of_list([1,2,3| Tail]-Tail, 4, Result).
Tail = [4|_G1006],
Result = [1, 2, 3, 4|_G1006]-_G1006.
现在,附加两个列表是相似的,也是O(1)。我们不想附加元素,而是追加元素列表:
dappend(List1-Tail1, Tail1-Tail2, List1-Tail2).
例如:
?- dappend([1,2,3 | Tail1]-Tail1, [4,5,6| Tail2]-Tail2, Result).
Tail1 = [4, 5, 6|Tail2],
Result = [1, 2, 3, 4, 5, 6|Tail2]-Tail2.
我留给你作为练习,用差异列表回答你自己的问题。请注意,从差异列表到关闭列表,只是将开放端实例化为空列表的问题。例如:
?- dappend([1,2,3 | Tail1]-Tail1, [4,5,6| Tail2]-Tail2, Result-[]).
Tail1 = [4, 5, 6],
Tail2 = [],
Result = [1, 2, 3, 4, 5, 6].
但是,从关闭列表到差异列表确实要求您遍历列表,即O(n):
as_difflist([], Back-Back).
as_difflist([Head| Tail], [Head| Tail2]-Back) :-
as_difflist(Tail, Tail2-Back).
构建差异列表的成本当然可能是也可能不是问题,具体取决于您获取初始列表的方式以及您在应用程序中追加列表的频率。
答案 2 :(得分:4)
希望我能理解这个问题(我不认为以下内容比其他解决方案更有效),但你的意思是这样吗?
append([],[],L,L).
append([],[H|T],L,[H|R]) :- append([],T,L,R).
append([H|T],L0,L1,[H|R]) :- append(T,L0,L1,R).