List Prolog程序的代码,用于检查给定列表是否为回文列表,而不使用反向操作

List Prolog程序的代码,用于检查给定列表是否为回文列表,而不使用反向操作,list,prolog,reverse,palindrome,List,Prolog,Reverse,Palindrome,这是如何使用反向操作获取回文 谓词 palin(list) findrev(list,list,list) compare(list,list) 条款 palin(List1):- findrev(List1,[],List2), compare(List1,List2). findrev([],List1,List1). findrev([X|Tail],List1,List2):- findrev(Tail,[X|List1],List2). compare(

这是如何使用反向操作获取回文

谓词

palin(list)
findrev(list,list,list)
compare(list,list)
条款

palin(List1):-
    findrev(List1,[],List2),
    compare(List1,List2).

findrev([],List1,List1).

findrev([X|Tail],List1,List2):-
    findrev(Tail,[X|List1],List2).

compare([],[]):-
    write("\nList is Palindrome").

compare([X|List1],[X|List2]):-
    compare(List1,List2).    

compare([X|List1],[Y|List2]):-
    write("\nList is not Palindrome").

但我想不做反向操作。有人能帮我吗。

只需匹配第一个和最后一个元素

first([F|L], F, L). % better inlined, but for clarity...
last(Es, L, R) :- append(R, [L], Es). % again...

palin([]).
palin([_]).
palin(L) :-
  first(L, E, X), last(X, E, Y), palin(Y).
为什么不呢

pal([]).
pal([_]).
pal(Pal) :-
    append([H|T], [H], Pal),
    pal(T).

在我看来,最优雅的方式是使用DCG,如图所示:

最一般的查询:

?- phrase(palindrome, Ps).
具体例子:

?- phrase(palindrome, [a,b,b,a]).
true .
这里有一个选择:

palindrome( Xs ) :- palindrome( Xs , [] , Xs ) .

palindrome( []     , Z , X ) .
palindrome( [X|Xs] , T , Z ) :- palindrome( Xs , [X|T] , Z ) .
尽管它实际上只是在推出自己的
reverse/2
实现

另一个选项,使用
append/3

palindrome( [] ) .
palindrome( Xs ) :- append( [X|Rest] , [X] , Xs ) , palindrome(Rest) .
第三个选项,完全避免
append/3

palindrome( []      ) .                    % The empty list is a palindrome
palindrome( [X]     ) .                    % A single-element list is a palindrome.
palindrome( [X,Y|Z] ) :-                   % A list of more than one element is a palindrome, IF...
  first( Xs , X , L1 ) ,                   % The first element and
  last(  L1 , X , L2 ) ,                   % The last element are identical, AND
  palindrome(T2)                           % what's left over is a palindrome, too.
  .

first( [X|Xs] , X , Xs ) .      % getting the first item from a list is trivial.

last( [X]     , X , []    ) .   % getting the last item from a single element list is trivial, too.
last( [X,Y|Z] , L , [X|R] ) :-  % otherwise...add the head of the list to the leftovers list,
   last( [Y|Z] , L , R )        % - and recurse down on the tail
   .                            %

这些答案中有很多使用last或append,这是非常昂贵的操作

您可以进行半个反转,然后检查相等性。 问题规定不使用反向,但这只使用了类似反向的过程,而不是完全反向

palindrome(Xs):- palindrome(Xs,[]).

palindrome(Xs, Xs).                    % [1,2,2,1] will get to pal([1,2],[1,2])
palindrome([X|Xs],Xs).                 % captures a case like [a,b,c,b,a]
palindrome([X|Xs],Ys):- palindrome(Xs, [X|Ys]).      % reverse-like process
上面可能缺少的一点是切割。虽然此处没有必要,但应用于良好实践:

palindrome(Xs):- palindrome(Xs,[]).

palindrome(Xs, Xs):- !.                    % Don't need to redo after positive match
palindrome([X|Xs],Xs):- !.                 
palindrome([X|Xs],Ys):- palindrome(Xs, [X|Ys]). 
回文的典型跟踪:

[trace] 88 ?- pal([1,2,1]).
   Call: (6) pal([1, 2, 1]) ? creep
   Call: (7) pal([1, 2, 1], []) ? creep
   Call: (8) pal([2, 1], [1]) ? creep
   Exit: (8) pal([2, 1], [1]) ? creep         % Matches rule - palindrome([X|Xs],Xs).
   Exit: (7) pal([1, 2, 1], []) ? creep
   Exit: (6) pal([1, 2, 1]) ? creep
true .
[trace] 87 ?- pal([1,2,3]).
Call: (6) pal([1, 2, 3]) ? creep
   Call: (7) pal([1, 2, 3], []) ? creep
   Call: (8) pal([2, 3], [1]) ? creep
   Call: (9) pal([3], [2, 1]) ? creep
   Call: (10) pal([], [3, 2, 1]) ? creep
   Fail: (10) pal([], [3, 2, 1]) ? creep      % Fails as [] doesn't equal [3,2,1] and can't be pulled apart
   Fail: (9) pal([3], [2, 1]) ? creep
   Fail: (8) pal([2, 3], [1]) ? creep
   Fail: (7) pal([1, 2, 3], []) ? creep
   Fail: (6) pal([1, 2, 3]) ? creep
false.
和一个非回文:

[trace] 88 ?- pal([1,2,1]).
   Call: (6) pal([1, 2, 1]) ? creep
   Call: (7) pal([1, 2, 1], []) ? creep
   Call: (8) pal([2, 1], [1]) ? creep
   Exit: (8) pal([2, 1], [1]) ? creep         % Matches rule - palindrome([X|Xs],Xs).
   Exit: (7) pal([1, 2, 1], []) ? creep
   Exit: (6) pal([1, 2, 1]) ? creep
true .
[trace] 87 ?- pal([1,2,3]).
Call: (6) pal([1, 2, 3]) ? creep
   Call: (7) pal([1, 2, 3], []) ? creep
   Call: (8) pal([2, 3], [1]) ? creep
   Call: (9) pal([3], [2, 1]) ? creep
   Call: (10) pal([], [3, 2, 1]) ? creep
   Fail: (10) pal([], [3, 2, 1]) ? creep      % Fails as [] doesn't equal [3,2,1] and can't be pulled apart
   Fail: (9) pal([3], [2, 1]) ? creep
   Fail: (8) pal([2, 3], [1]) ? creep
   Fail: (7) pal([1, 2, 3], []) ? creep
   Fail: (6) pal([1, 2, 3]) ? creep
false.

我没有给出一个解决方案,但是考虑佩林(list):-FunReV(列表,[],列表)。对于您的问题,您可以使用append([H | Tail],[H],Pal)并在Tail上使用递归性。为什么要在不反转的情况下这样做?您将采取什么方法,不是在代码中,而是至少在文字中?这确实是最优雅的解决方案。append([H | T],[H],Pal)删除Pal的第一个和最后一个元素,假设它们是相同的(如果不是Pal失败)。我继续递归地使用T。