【问题标题】:trace route of the quicksort algorithm - prolog快速排序算法的trace route - prolog
【发布时间】:2014-10-31 16:41:00
【问题描述】:

我有关于这个快速排序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 应用拆分规则 [2],我们有 Call: (8) split(3, [2, 4, 1, 5], _G4269, _G4270),我们有 _G4269[2|Small]_G4270Big

然后比较 3 和 2,gt(3,2) 返回 true 并且不执行剪切。继续split(X,Tail,Small,Big),即Call: (9) split(3, [4, 1, 5], _G4261, _G4273)

如果gt(X,Y) 返回 false,prolog 将执行剪切,然后应用拆分规则 [3](第 11-12 行)。

我做得对吗?为什么最后一个变量变成了一个新变量(_G4237 而不是_G4270)?因为在代码中我认为是一样的。

谁能帮我把事情弄清楚? 非常感谢!

【问题讨论】:

  • 对谓词的每次调用都有自己的变量。您的跟踪显示 _G4270 在 (8) 层深,_G4273 在 (9) 层深。所以它们是不同的。
  • 你可以信任变量名,特别是当由算法生成时!

标签: prolog stack-trace quicksort


【解决方案1】:

确切地说:您的问题涉及跟踪的这一部分:

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).

你是对的,因为使用了相同的变量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)。

然而,解释器有不可见理由将变量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] 上是同一个变量。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-11-24
    • 2018-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-14
    • 2021-09-21
    相关资源
    最近更新 更多