了解Prolog中的这种气泡排序解决方案

时间:2018-08-19 17:06:46

标签: algorithm sorting recursion prolog bubble-sort

此气泡排序解决方案在Prolog中如何工作?

bubblesort([], []).
bubblesort([H], [H]).
bubblesort([H|D], R) :-
    bubblesort(D, E),
    [B|G] = E,
    (  (H =< B, R = [H|E])
    ;  (H > B,  bubblesort([B,H|G], R))
    ).

以下是示例跟踪:https://pastebin.com/T0DLsmAV

我了解该行bubbleort(D,E)负责将其归类为一个元素,但是我不知道这是如何工作的。我了解序言中列表的基本知识,但仍然无法弄清楚该解决方案的工作方式。

2 个答案:

答案 0 :(得分:1)

此代码的主要困难是选择了错误的变量名,这使得逻辑难以理解。

前两个案例显然是基本案例。第一个说“空列表已经排序”,第二个说“单例列表已经排序”。这应该是有道理的。第三种情况是让事情变得有趣。

让我们检查一下第一部分。

bubblesort([H|D], R) :-
    bubblesort(D, E),

到目前为止,所有发生的事情都是我们将结果命名为R,并将输入分为第一个元素H和一个尾部D。从那里开始,我们已经说过了,让我们对输入的尾部进行冒泡排序,并将其命名为E。也许这样做会更容易些?

bubblesort([H|T], Result) :-
    bubblesort(T, TSorted),

接下来,

    [B|G] = E,

同样,名字不好,但是作者打算在这里做的很简单:分解排序尾巴的结果,这样我们就可以讨论排序后的尾巴中的下一项是否适合该位置,或者如果需要在我们输入的开头切换位置。我们重命名:

    [HeadOfTSorted|RestOfTSorted] = TSorted,

现在我们有一个条件。从添加到排序列表的角度考虑。假设您有一些元素,例如3,我递给您一个排序列表。您想确定您的3排在前面还是其他地方。好吧,假设我给了您一个看起来像[5,7,19,23,...]的排序列表。您会知道自己的3正好在需要的位置,然后交出[3,5,7,19,23,...]。这正是该情况的第一种情况:

    (  (H =< HeadOfTSorted, Result = [H|TSorted])

现在考虑另一种情况,在这里我将以[1,2,...]开头的列表交给您。您知道您不能只是将这三个词放在开头并给我[3,1,2,...]。但是您真的不知道3的去向。它只是一开始就没有。因此,您需要做的是对列表的其余部分进行 resort ,在列表的1:[1 | resorted([3,2,...])]之后,以3开头。实际上,这是条件的另一个分支:

    ;  (H > HeadOfTSorted,  bubblesort([HeadOfTSorted,H|RestOfTSorted], R))
    ).

希望这会有所帮助!

答案 1 :(得分:1)

注意:递归解决问题的关键恰恰是 not 来思考我们代码操作的细节。想象您已经有解决方案,然后使用它来解决较小的子问题,从而找到完整的问题解决方案。


您的代码带有更多提示性的变量名,以便我可以关注它,内容如下:

bubblesort([], []).          % empty list is already sorted

bubblesort([H], [H]).        % singleton list is already sorted

bubblesort([H|T], S) :-      % `[H|T]` sorted is `S`,   *if*
    bubblesort(T, [M|R]),    %    `T` sorted is `[M|R]`,    *and*
    (                                 %   *either*,
       H =< M,                        %     in case `H` is not greater than `M`, 
             S = [H,M|R]              %       `S` is `[H,M|R]`,    
    ;                                 %   *or*
       H > M,                         %     in case `H` is greater than `M`,
             bubblesort([M,H|R], S)   %       `S` is `[M,H|R]` sorted by the same algorithm
    ).

({H代表“头”,T代表“尾”,S代表“已排序”,R代表“休息”和M是“最小值”-参见下文)。

我们通过structural induction证明了其正确性。归纳假设( IH )是此定义对于较短的列表是正确的。我们需要证明它对于更长的列表也是正确的。实际上,T[H|T]短一个元素。因此, IH [M|R]已排序。这意味着MT中的最小元素。这也意味着T是非空的(排序不会更改元素的数量),因此子句的确是互斥的。

如果H不大于T中的最小元素,则显然[H,M|R]被排序。

否则,我们对[M,H|R]进行排序。 M是最小元素,因此保证是结果中的第一元素。实际排序的是[H|R],它短了一个元素,因此通过 IH 排序就可以了。 QED

如果您觉得最后一步很可疑,请考虑用等效的替代第二种选择

    ;   H > M,                        %     in case `H` is greater then `M`,
             bubblesort([H|R], S1),   %       `S1` is `[H|R]` sorted by the same algorithm
                        S = [M|S1] 
    ).

归纳步骤的适用性更加明确。

我不确定这是bubble sort


更新:的确,measuring empirical orders of growth的推理次数随着〜n 3 (或更慢的速度),但真正的气泡排序的时钟频率为〜n 2.1 (足够接近理论上的〜n 2 ),其中 n 是列表的长度:

tbs([], []).               % 'true' bubble sort
tbs([H],[H]).
tbs(L,S):- bubble(L,B),
           ( L==B -> S=L ; tbs(B,S) ).

bubble([],[]).
bubble([A],[A]).
bubble([A,B|C],R):- 
  (  A =< B -> bubble([B|C],X), R=[A|X]
  ;            bubble([A|C],X), R=[B|X] ).