Prolog列表排列

时间:2015-11-24 20:34:32

标签: list prolog permutation

我有以下代码生成列表的所有可能的排列,但我无法弄清楚它为什么会起作用。

remove(X,[X|T],T).
remove(X,[F|T],[F|T1]) :- remove(X,T,T1).

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

有人可以给我一些解释或者请我参考吗?

1 个答案:

答案 0 :(得分:1)

我只是拿起Prolog,所以我不知道正确的术语,但我认为逻辑如下:

remove(X,L,T)的规则很简单,它将T定义为从L中删除X的列表。例如,给定T = [1],哪个L满足X = 2?答案是[1,2]或[2,1]。

对于perm,让我们以烫发([1,2,3],P)为例。

  1. 根据定义,如果W是[2,3]的permuation,则P是[1,2,3]的置换,其中W是P,其中1被移除。
  2. 假设我们通过回溯的魔力以某种方式知道W是[2,3]或[3,2],那么P必须是[1,2,3],[2,1,3],[2,3] ,1],...
  3. 我们如何发现[2,3]的排列是[2,3]或[3,2]?它发生在W2是[3]的排列时,其中W2是P2,其中2被移除。
  4. 假设我们知道W2是[3],那么P2必须是[2,3]或[3,2]。
  5. 我们如何发现[3]的排列是[3]?它发生在W3是[]的排列时,其中W3是P3,其中3被移除。由于基本情况W3必须是[],因此P3必须是[3]。
  6. 刚刚了解了跟踪模式,它提供了逐步说明:

    ?- trace.
    true.
    
    [trace] 2 ?- perm([1,2],X).
       Call: (7) perm([1, 2], _G22903) ? creep
       Call: (8) perm([2], _G22988) ? creep
       Call: (9) perm([], _G22988) ? creep
       Exit: (9) perm([], []) ? creep
       Call: (9) remove(2, _G22988, []) ? creep
       Exit: (9) remove(2, [2], []) ? creep
       Exit: (8) perm([2], [2]) ? creep
       Call: (8) remove(1, _G22903, [2]) ? creep
       Exit: (8) remove(1, [1, 2], [2]) ? creep
       Exit: (7) perm([1, 2], [1, 2]) ? creep
    X = [1, 2] ;
       Redo: (8) remove(1, _G22903, [2]) ? creep
       Call: (9) remove(1, _G22984, []) ? creep
       Exit: (9) remove(1, [1], []) ? creep
       Exit: (8) remove(1, [2, 1], [2]) ? creep
       Exit: (7) perm([1, 2], [2, 1]) ? creep
    X = [2, 1] ;
       Redo: (9) remove(1, _G22984, []) ? creep
       Fail: (9) remove(1, _G22984, []) ? creep
       Fail: (8) remove(1, _G22903, [2]) ? creep
       Redo: (9) remove(2, _G22988, []) ? creep
       Fail: (9) remove(2, _G22988, []) ? creep
       Fail: (8) perm([2], _G22988) ? creep
       Fail: (7) perm([1, 2], _G22903) ? creep
    false.