Prolog中冒泡排序算法的声明解释

时间:2013-04-25 10:12:19

标签: prolog bubble-sort

我对如何在Prolog中实现BubbleSort算法的实现有所怀疑。

我非常清楚BubbleSort算法是如何工作的,所以我的疑问只与Prolog的一阶逻辑和声明性解释有关。

这是我的代码:

bubbleSort(List, SortedList) :- swap(List, List1),
                                !,
                                bubbleSort(List1, SortedList).

bubbleSort(SortedList, SortedList).

/* swap predicate swap the two element if X come after Y in lexicographical order */
swap([X,Y|Tail], [Y,X|Tail]) :- X @> Y.

/* If it is not true that X come after Y in lexicographical order let the head in its
   original position and call the swap predicate on the sublist */ 
swap([Z|Tail], [Z|Tail1]) :- swap(Tail, Tail1).

所以我对这个程序的声明性解释有一些疑问:

该程序的核心是 bubbleSort / 2 谓词,它执行List的扩展,在其中执行相邻元素的最终交换。

所以 swap / 2 谓词的工作方式如下:

1)如果子列表(X)中的第一个元素遵循字典顺序中子列表(Y)中的第二个元素,那么它就不好了,所以执行交换。

2)否则X和Y的顺序正确并尝试在子列表上执行te swap Tail

例如,如果我执行以下查询:

[trace]  ?- bubbleSort([3,2,1], Sorted).

我获得:

Call: (7) bubbleSort([3, 2, 1], _G399) ? creep
Call: (8) swap([3, 2, 1], _G478) ? creep
Call: (9) 3@>2 ? creep
Exit: (9) 3@>2 ? creep
Exit: (8) swap([3, 2, 1], [2, 3, 1]) ? creep
Call: (8) bubbleSort([2, 3, 1], _G399) ? creep

此处在原始列表中调用 bubbleSort / 2 的第一个版本。要为TRUE,请调用 swap / 2 谓词的第一个版本,检查列表的前两个元素是否彼此不按字典顺序排列,此事实为TRUE,因此交换这些元素。现在验证了 swap / 2 谓词,然后通过回溯和(以满足 bubbleSort / 2 )再次调用 bubbleSort2 现在说原来的list to order是交换后的列表(交换第一个和第二个元素的列表)

所以再次召唤bubbleSort并发生:

Call: (8) bubbleSort([2, 3, 1], _G399) ? creep
Call: (9) swap([2, 3, 1], _G484) ? creep
Call: (10) 2@>3 ? creep
Fail: (10) 2@>3 ? creep
Redo: (9) swap([2, 3, 1], _G484) ? creep
Call: (10) swap([3, 1], _G480) ? creep
Call: (11) 3@>1 ? creep
Exit: (11) 3@>1 ? creep
Exit: (10) swap([3, 1], [1, 3]) ? creep
Exit: (9) swap([2, 3, 1], [2, 1, 3]) ? creep 

所以现在它尝试在列表[2,3,1]上满足 swap / 2 但是现在这不是真的,前两个元素彼此不是字典顺序,所以 swap / 2 谓词的第一个版本失败,所以它使用第二个版本,只需在子列表** [3,1]上调用 swap / 2 ,这是真的3不要跟随1,所以交换它,我获得[1,3]列表。

这里我有第一个疑问:在这个子列表上交换后(从[3,1]到[1,3])我获得了这一行中的列表:[2,1,3]:

Exit: (9) swap([2, 3, 1], [2, 1, 3]) ? creep 

为什么呢?这是因为在满足swap(Tail,Tail1)谓词之后:

swap([Z|Tail], [Z|Tail1]) :- swap(Tail, Tail1).

我有 Tail1是[1,3] 所以Z是旧头2而[Z | Tail1]是 [2,1,3] ?< / p>

然而,现在它结束了冒泡排序算法的第一个扩展,它采用了列表末尾的“更大”元素

执行继续以相同的方式但我对程序执行的结束有疑问:

   Redo: (10) bubbleSort([1, 2, 3], _G399) ? creep
   Exit: (10) bubbleSort([1, 2, 3], [1, 2, 3]) ? creep
   Exit: (9) bubbleSort([2, 1, 3], [1, 2, 3]) ? creep
   Exit: (8) bubbleSort([2, 3, 1], [1, 2, 3]) ? creep
   Exit: (7) bubbleSort([3, 2, 1], [1, 2, 3]) ? creep
Sorted = [1, 2, 3].

所以最后在有序列表上调用 bubbleSort / 2 谓词:

 Redo: (10) bubbleSort([1, 2, 3], _G399) ? creep

其中[1,2,3] List1

现在我处于 bubbleSort / 2 谓词的第二个版本,这个:

bubbleSort(SortedList, SortedList).

其中要排序的列表和排序列表是相同的(因此这意味着原始列表被整齐排序)。

这是什么?基础案例,一旦验证,说程序执行必须结束?

因此,请执行回溯以确认所有之前的 bubbleSort / 2 已经过验证,直到第一个 bubbleSort / 2 调用,并说这已被激活并统一排序[1,2,3]列表

我的推理是否正确?是否有更明确的解释?

1 个答案:

答案 0 :(得分:3)

我认为理解这个算法的关键是当列表排序时swap / 2 失败这一事实 - 空列表中没有匹配。

从这里开始第二个bubbleSort / 2规则的必要性。