Prolog 如何将元素尽可能向左移动?序言

Prolog 如何将元素尽可能向左移动?序言,prolog,Prolog,假设我有一个包含4个元素[0,4,0,2](可以是任何排列)的列表。列表中的每个元素都将向左移动。如果一个元素的邻居为零,那么它可以很容易地向左移动。如果邻居是非零数,则它不能向左移动。(例如:[8,0,2,3]将成为[8,2,3,0],而[0,4,0,2]将成为[4,2,0,0]) 以下是我目前的尝试: shift_left([],_):-!. shift_left([H1,H2|T],S):- H1=0, append(S,[H2|T],L1), write(L1),

假设我有一个包含4个元素[0,4,0,2](可以是任何排列)的列表。列表中的每个元素都将向左移动。如果一个元素的邻居为零,那么它可以很容易地向左移动。如果邻居是非零数,则它不能向左移动。(例如:[8,0,2,3]将成为[8,2,3,0],而[0,4,0,2]将成为[4,2,0,0])

以下是我目前的尝试:

shift_left([],_):-!.
shift_left([H1,H2|T],S):-
    H1=0,
    append(S,[H2|T],L1),
    write(L1),
    shift_left([H2|T],_).
shift_left([H1|T],_):-
    H1\=0,
    shift_left(T,[H1]).
我看了卡佩里克的答案后的第二次尝试。它工作得很好

shift_left([],[]).
shift_left([H|T],S):-
    shift_left(T,Q),
    H=0,
    append(Q,[0],S).
shift_left([H|T],S):-
    shift_left(T,Q),
    H\=0,
    S=[H|Q].

我们可以在列表上枚举,每次我们看到一个零,我们可以将它推到元素列表上,以便在我们到达列表末尾时发出:

shift_left(L, R) :-
    shift_left(L, [], R).

shift_left([], Zs, Zs).
shift_left([H|T], Zs, [H|R]) :-
    dif(H, 0),
    shift_left(T, Zs, R).
shift_left([0|T], Zs, R) :-
    shift_left(T, [0|Zs], R).
这就给了我们:

?- shift_left([8,0,2,3], R).
R = [8, 2, 3, 0] ;
false.

?- shift_left([0,4,0,2], R).
R = [4, 2, 0, 0] ;
false.

这是一个更简单的解决方案——从某种意义上说,它不太技术化——编写Willem的答案,并使用append/3作为原始代码

shift_左([],[])。
左移([H | T],S):-
左移(T,Q),
(H=0
->追加(Q[0],S)
;S=[H | Q]
).
试验

?-地图列表(左移,[8,0,2,3],[0,4,0,2]],Ss)。
Ss=[[8,2,3,0],[4,2,0,0]]。

这是一个更具技术性的解决方案。它基本上与相同,但使用库谓词并额外遍历Not零

bubble_up_zeros(List, Result) :-
    partition(not_zero, List, Not_zeros, Zeros),
    append(Not_zeros, Zeros, Result).

not_zero(X) :- dif(X, 0).

你的问题是什么?:-(最糟糕的计算复杂度答案;作为奖励,可能会填满堆栈,因为它会阻止最后一次调用优化。想想我有点为我写的东西感到羞耻。@TA_intern:当然,我知道。然而,代码的简单性必须考虑在内,特别是当询问者(尚未)时我不懂Prolog。老实说,我在调试属性变量解决方案时记性不好。我不想把这一点转移到一个Prolog新手身上。大多数时候,新来Prolog的人都会被基本语义吓到,然后如何解释协程、列表等有多有用……我想我明白了。如果你不喜欢属性变量ABLE(我猜你的意思是
dif/2
?)你可以使用
\=
\=
。但列表仍然是一个列表,“附加”意味着遍历整个列表。