快速排序算法的跟踪路径 - 序言

时间:2014-10-31 16:41:01

标签: prolog stack-trace quicksort

我之前有关于此快速排序here的问题。快速排序的序言代码:

gt(X,Y):- X @>Y.
conc([],List, List).
conc([Head|Tail], List1, [Head|List2]):- conc(Tail, List1, List2).

quicksort([],[]).
quicksort([X|Tail],Sorted):-
    split(X,Tail,Small,Big),
    quicksort(Small,SortedSmall),
    quicksort(Big,SortedBig),
    conc(SortedSmall,[X|SortedBig],Sorted).

[1]split(X,[],[],[]).
[2]split(X,[Y|Tail],[Y|Small],Big):-
    gt(X,Y),!,
    split(X,Tail,Small,Big).
[3]split(X,[Y|Tail],Small,[Y|Big]):-
    split(X,Tail,Small,Big).

例如,数组是[3,2,4,1,5]。这是跟踪路线的第一部分:

?- trace, quicksort([3,2,4,1,5], Sorted).
1  Call: (7) quicksort([3, 2, 4, 1, 5], _G4136) ? creep
2  Call: (8) split(3, [2, 4, 1, 5], _G4269, _G4270) ? creep
3  Call: (9) gt(3, 2) ? creep
4  Call: (10) 3@>2 ? creep
5  Exit: (10) 3@>2 ? creep
6  Exit: (9) gt(3, 2) ? creep
7  Call: (9) split(3, [4, 1, 5], _G4261, _G4273) ? creep
8  Call: (10) gt(3, 4) ? creep
9  Call: (11) 3@>4 ? creep
10 Fail: (11) 3@>4 ? creep
11 Fail: (10) gt(3, 4) ? creep
12 Redo: (9) split(3, [4, 1, 5], _G4261, _G4273) ? creep
13 Call: (10) split(3, [1, 5], _G4261, _G4264) ? creep

在第2行,prolog应用了split的规则[2],我们有Call: (8) split(3, [2, 4, 1, 5], _G4269, _G4270),我们_G4269[2|Small]_G4270为{{1} }。

然后比较3和2,Big返回true并且不执行剪切。继续使用gt(3,2)

split(X,Tail,Small,Big)

如果Call: (9) split(3, [4, 1, 5], _G4261, _G4273)返回false,prolog将执行剪切,然后应用分割的规则[3](第11-12行)。

我做对了,为什么最后一个变量变成了新变量(gt(X,Y)而不是_G4237)?因为在代码中我认为它是相同的。

任何人都可以帮我解决问题吗? 非常感谢!

1 个答案:

答案 0 :(得分:0)

准确地说:你的问题涉及这一部分的痕迹:

2  Call: (8) split(3, [2, 4, 1, 5], _G4269, _G4270) ? creep
3  Call: (9) gt(3, 2) ? creep
4  Call: (10) 3@>2 ? creep
5  Exit: (10) 3@>2 ? creep
6  Exit: (9) gt(3, 2) ? creep
7  Call: (9) split(3, [4, 1, 5], _G4261, _G4273) ? creep

对应于对:

的调用
split(X,[Y|Tail],[Y|Small],Big):-
    gt(X,Y),!,
    split(X,Tail,Small,Big).

并且你没有 VISIBLE 获得不同变量的原因,因为使用了相同的变量Big。我承认这令人困惑。而且,您可以获得相同的变量。这可以显示直接调用split(3, [2, 4, 1, 5], S, B)跟踪(使用swi v6.6.6):

[trace]  ?- split(3, [2, 4, 1, 5], S, B).
   Call: (6) split(3, [2, 4, 1, 5], _G4537, _G4538) ? creep
   Call: (7) gt(3, 2) ? creep
   Call: (8) 3@>2 ? creep
   Exit: (8) 3@>2 ? creep
   Exit: (7) gt(3, 2) ? creep
   Call: (7) split(3, [4, 1, 5], _G4630, _G4538) ? creep

使用相同的变量(_G4538)。

但是,解释程序可以 INVISIBLE 将变量X统一为全新的Y并使用Y代替X在后续计算中。这是你的例子中发生的事情。您可以在调试时使用命令g(目标)来获取回溯,该回溯将显示当前具有当前变量绑定的堆栈跟踪。回到你的例子,当你到达

7  Call: (9) split(3, [4, 1, 5], _G4261, _G4273) ? 

键入g以进行回溯,并获得类似以下内容:

  [9] split(3, [4, 1, 5], _G4261, _G4273)
  [8] split(3, [2, 4, 1, 5], [2|_G4261], _G4273)
  [7] quicksort([3, 2, 4, 1, 5], _G4136)
   Call: (9) split(3, [4, 1, 5], _G4261, _G4273) ? 

现在你可以看到_G4273是深度相同的变量[8]和[9]。