我试图写交换第一和最后一个元素的程序。
该函数采用2个参数。 列表,并在随即出现的新交换列表中的变量。
我想我是这样做的懒办法,但它的转向了是一样难受。
我要抢人头,把它放在一边 - 抢尾的最后一个元素,把它放在一边 - 采取尾,去掉最后一个元素,把它放在一边还,那么所有3追加在一起,使一个列表
我无法取出尾的最后一个元素。
我有这样的事情:
swap( [H|T], Y ) :-
% GET HEAD, LAST OF TAIL, AND TAIL WITH LAST ELEM REMOVED
% GET HEAD (NEW LAST ELEMENT)
H = NEW_LASTELEMENT,
% GET LAST ELEMENT (LAST OF TAIL, WILL BE NEW HEAD)
last(T,X), X = NEWHEAD,
% CUT END OF TAIL OFF
cutlast(T, Z), REST OF CODE . . .
.
% CUT LAST
cutlast([H | T], [H | T2]) :- T = [_|_], cutlast(T, T2).
我借了从Web cutlast谓语,但我不知道它是如何,甚至应该工作。 我一直在测试,现在将参数传递给它一个小时,他们都保持返回false。 任何援助表示赞赏。
可能只是:
swap(A, B) :-
append([First | Mid], [Last], A),
append([Last | Mid], [First], B).
更多的事实与一个元素和空列表成功,如果它的需要:
swap([X], [X]).
swap([], []).
下面是不使用递归的解决方案append/3
或reverse/2
内置插件。 我想,我发现这是很多更有效(在推论的数量)比:
swap_fl_recursive([First|A], [Last|B]) :-
swap_fl_recursive_(A, First, Last, B).
swap_fl_recursive_([Last], First, Last, [First]).
swap_fl_recursive_([X|A], First, Last, [X|B]) :-
swap_fl_recursive_(A, First, Last, B).
该解决方案将原始First
通过递归元素,直到它可以成为新的最后一个元素,并实例原来Last
回成为新的第一要素。
象其他,对于swap_fl_recursive([X], [X])
为真或swap_fl_recursive([], []).
是真实的,那些需要被添加为事实/规则。
对于定时/推断append/3
版本:
?- numlist(1,10000,L), time(swap_fl_append(L, S)).
% 20,000 inferences, 0.021 CPU in 0.021 seconds (100% CPU, 950838 Lips)
L = [1, 2, 3, 4, 5, 6, 7, 8, 9|...],
S = [10000, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
% 3 inferences, 0.000 CPU in 0.000 seconds (94% CPU, 38921 Lips)
false.
用于定时/推论reverse/2
版本:
?- numlist(1,10000,L), time(swap_fl_reverse(L, S)).
% 20,055 inferences, 0.024 CPU in 0.024 seconds (100% CPU, 841265 Lips)
L = [1, 2, 3, 4, 5, 6, 7, 8, 9|...],
S = [10000, 2, 3, 4, 5, 6, 7, 8, 9|...].
递归版本(在这个答案所示)定时/推论:
?- numlist(1,10000,L), time(swap_fl_recursive(L, S)).
% 10,000 inferences, 0.009 CPU in 0.010 seconds (99% CPU, 1059142 Lips)
L = [1, 2, 3, 4, 5, 6, 7, 8, 9|...],
S = [10000, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
% 2 inferences, 0.002 CPU in 0.002 seconds (100% CPU, 821 Lips)
false.
所有这三种方法都是成正比的列表的长度线性时间。
下面是使用内置的替代版本reverse/2
,而不是append/3
。
swap_first_last([First|A], [Last|B]) :-
reverse(A, [Last|RevMid]),
reverse([First|RevMid], B).
这也许比版本谢尔盖表现略少效率的append/3
。 像append/3
版本,如果你想swap_first_last([X], [X]).
和/或swap_first_last([], []).
是真实的,你必须将其添加为事实/谓词。 但他们并不需要的长度大于或等于2的名单。
该断言说, [Last|B]
是一样的[First|A]
与交换,如果第一个和最后一个元素[Last|RevMid]
是列表的反向A
,和B
是反向[First|RevMid]
第一reverse
反转所述第一列表(尾A
),得到具有其自己的头部和尾部的列表, [Last|RevMid]
在这一点上, Last
代表第一个列表的最后一个元素,并RevMid
代表的“中间”列表中,不包括第一和最后一个元素,但以相反的顺序 。
第二reverse
然后采取第一个列表的头, First
,并使用它作为头一个新的列表是[First|RevMid]
如果我们扭转这个名单中,我们将与“中间”名单最终以正确的顺序,并First
在年底掌掴(这个列表被称为B
),所以我们已经拿到了原来的第一个元素是这个列表的最后一个元素所有的右中间元素。 剩下要做的事情是让第一列表最后一个元素( Last
)作为前缀的头,这发生在从句的头,如同[Last|B]
通过举例的方式,让我们查询, swap_first_last([a,b,c,d,e], S).
:
- 统一
[First|A]
与[a,b,c,d,e]
屈服, First = a
和A = [b,c,d,e]
- 查询
reverse([b,c,d,e], [Last|RevMid])
其产率, [Last|T] = [e,d,c,b]
或者, Last = e
和RevMid = [d,c,b]
。 - 查询
reverse([a|[d,c,b]], B)
是reverse([a,d,c,b], B)
得到, B = [b,c,d,a]
- 实例
[Last|B]
作为[e|[b,c,d,a]]
或[e,b,c,d,a]
使用DCG :
swap_first_last(Xs,Ys) :-
phrase(([First],seq(Seq),[Last]), Xs),
phrase(([Last], seq(Seq),[First]), Ys).
seq([]) --> [].
seq([E|Es]) --> [E], seq(Es).
但是,这-类似于其他建议,不只要终止Ys
是一个列表。 第一次尝试将列表限制到相同的长度:
same_length([], []).
same_length([_|Xs], [_|Ys]) :-
same_length(Xs, Ys).
swap_first_last(Xs,Ys) :-
same_length(Xs, Ys),
phrase(([First],seq(Seq),[Last]), Xs),
phrase(([Last], seq(Seq),[First]), Ys).
但是,如果列表中的第二个元素有什么不同? 像
?- Xs = [_,a|_], Ys = [_,b|_], swap_first_last(Xs, Ys).
Xs = [b, a],
Ys = [a, b] ;
**LOOPS**
我们断言仍可能会与终止:
swap_first_last(Xs, [Last|Ys]) :-
phrase(([First],dseq(Ys,[First]),[Last]), Xs).
dseq(Xs,Xs) --> [].
dseq([X|Xs0],Xs) --> [X], dseq(Xs0,Xs).