我对如何在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]列表
我的推理是否正确?是否有更明确的解释?
答案 0 :(得分:3)
我认为理解这个算法的关键是当列表排序时swap / 2 失败这一事实 - 空列表中没有匹配。
从这里开始第二个bubbleSort / 2规则的必要性。