簡體   English   中英

從 Prolog 中的列表中刪除連續元素

[英]Removing consecutive elements from a list in Prolog

到目前為止,我嘗試了三個單獨的函數,其中一個是第一個調用 function,另外兩個決定是否將 append 元素傳遞給我們的結果列表,如果它與列表的頭部不匹配。 遞歸使我感到困惑,因為它使許多其他人感到困惑,所以在這里的某個地方我有一個無限循環,導致堆棧溢出。 但是我不確定很多 prolog 概念(或語法),所以我很困惑我哪里出錯了。 感謝您的幫助!

append( [X | Y], Z, [X | W]) :- append( Y, Z, W). 

remove([], []).

remove([H|T], X) :-
    append(X, [H], X),
    remove(T, H, X),
    !.

remove([Y|T], Y, X):-
    remove(T, Y, X),
    !.

remove([H|T], Y, X):-
    append(X,[H], X),
    remove(T,Y,X),
    !.```

嗯...首先, Prolog 沒有“功能”:它有predicates

如果我理解您的問題陳述,您想“從列表中刪除連續元素”,我理解這意味着“將相同元素的運行折疊為單個值”,因此列表如下:

[a,b,b,b,,c,c,d,e,e,e,e]

減少到

[a,b,c,d,e]

假設是這種情況,您不需要(或不想要) append/3 總體方案是

  • 遞歸到列表的末尾,然后
  • 當您彈出調用堆棧時,您根據返回列表的頭部重復添加或省略當前項

像這樣:

remove( []     , [] ) .
remove( [X|Xs] , Ys ) :- remove(Xs,Ts), try_add(X,Ts,Ys) .

try_add/3負責決定是否在返回列表中添加/添加一個項目。 它也是微不足道的:

  • 如果返回的列表為空,則在其前面添加候選X
  • 如果返回列表非空,則用返回列表的頭部測試候選X
    • 如果它們是可統一的,則省略候選X
    • 否則,將候選X添加到返回的列表中
try_add( X , []     ,      [X] ) .
try_add( X , [T|Ts] ,   [T|Ts] ) :- X  = T.
try_add( X , [T|Ts] , [X,T|Ts] ) :- X \= T.

將所有內容放在一起,您會得到:

remove( []     , [] ) .
remove( [X|Xs] , Ys ) :- remove(Xs,Ts), try_add(X,Ts,Ys) .

try_add( X , []     ,      [X] ) .
try_add( X , [T|Ts] ,   [T|Ts] ) :- X  = T.
try_add( X , [T|Ts] , [X,T|Ts] ) :- X \= T.

這在 O(n) 時間和空間中運行。 它的缺點是它不是尾遞歸的,這意味着給定一個足夠長的列表,它會使你的程序因堆棧溢出而崩潰。

另一種尾遞歸方法——在 O(n) 時間和 O(1) 空間中運行——是這樣的:

remove( []     , [] ) .
remove( [X|Xs] , Ys ) :- remove(Xs, [X], Ts ), reverse(Ts,Ys) .

remove( []     , Ys     , Ys ) .
remove( [X|Xs] , [T|Ts] , Ys ) :- X  = T , remove( Xs ,  [X|Ts] , Ys ) .
remove( [X|Xs] , [T|Ts] , Ys ) :- X \= T , remove( Xs ,[X,T|Ts] , Ys ) .

它的缺點是它以相反的順序構建返回列表,因此需要通過reverse/2進行另一次遍歷才能將事物以正確的順序放回原處。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM