查找列表中第K个最大元素的程序

时间:2011-03-31 18:50:15

标签: prolog

我正在为kth_largest(Xs,K)编写一个逻辑程序,它实现了用于查找的线性算法 列表Xs的第k个最大元素K.该算法具有以下步骤:

  1. 将列表分成五个元素组。
  2. 有效地找到每个组的中位数,这可以使用固定数量的组来完成 比较。
  3. 递归地找到中位数的中位数。
  4. 根据中位数的中位数对原始列表进行分区。
  5. 递归地在相应的较小列表中找到第k个最大元素。
  6. 我该如何解决?我可以从列表中选择一个元素,但我不知道如何使用上面的过程获得最大的元素。这是我从列表中选择元素的定义

    select(X; HasXs; OneLessXs)  
    % The list OneLessXs is the result of removing
    % one occurrence of X from the list HasXs.
    select(X,[X|Xs],Xs).
    select(X,[Y|Ys],[Y|Zs]) :-  select(X,Ys,Zs).
    

1 个答案:

答案 0 :(得分:2)

因为没有人尝试过答案,所以我会跳进去,并希望能够详细说明要编程的程序。

我发现维基百科关于Selection algorithm的文章对于理解这种类型的“快速”(最坏情况线性时间)算法的大局非常有帮助。

但是你在问题的最后提出的问题有点简单。你写了“我该怎么做?我可以从列表中选择一个元素,但我不知道如何使用上述程序获得最大。” (我强调)

现在似乎有点混淆是否要实施“上述程序”,这是通过连续搜索中位数找到第k个最大元素的一般方法,或者您是否询问如何使用该方法找到最大的元素(特殊情况)。请注意,该配方并未专门使用在查找中间位置或第k个最大元素的过程中找到最大元素的步骤。

但是你给代码在删除该元素之后找到列表的元素和该列表的其余部分,这是一个不确定的谓词,并允许回溯列表中的所有成员。

找到最大元素的任务是确定性的(至少如果所有元素都是不同的),并且它比第k个最大元素(与其他事物相关的订单统计相关的任务)的一般选择更容易。

让我们给出一些简单的,希望非常正确的代码来找到最大的元素,然后讨论一种更优化的方法。

maxOfList(H,[H|T]) :-  upperBound(H,T), !.
maxOfList(X,[_|T]) :-  maxOfList(X,T).

upperBound(X,[ ]).
upperBound(X,[H|T]) :-
    X >= H,
    upperBound(X,T).

这个想法应该是可以理解的。我们查看列表的头部并询问该条目是否是列表其余部分的上限。如果是这样,那必须是最大值,我们就完成了(切割使它具有确定性)。如果不是,则最大值必须在列表中稍后出现,因此我们丢弃头并继续递归地搜索作为所有后续元素的上限的条目。剪切在这里是必不可少的,因为我们必须停在第一个这样的条目,以便知道它是原始列表的最大值。

我们使用了辅助谓词 upperBound / 2 ,这并不罕见,但这种实现的整体复杂性在列表长度上是最坏情况的二次方。所以还有改进的空间!

让我暂停一下,确保我不会完全偏离试图解决你的问题。毕竟你可能想要问如何使用“上面的程序”找到第k个最大的元素,所以我所描述的可能过于专业化。然而,理解一般选择算法的巧妙性可以帮助理解简单案例的细微优化,找到最大的元素。

<强>加了:

直观地说,我们可以减少最坏情况下所需的比较次数 通过列表并跟踪发现的最大值“所以 “在程序语言中,我们可以通过重新分配轻松实现这一目标 变量的值,但Prolog不允许我们直接这样做。

相反,Prolog的做法是引入额外的参数和 通过调用辅助谓词来定义谓词 maxOfList / 2 有三个参数:

maxOfList(X,[H|T]) :- maxOfListAux(X,H,T).

然后可以使用 maxOfListAux / 3 中的额外参数来跟踪 最大值“到目前为止”如下:

maxOfListAux(X,X,[ ]).
maxOfListAux(Z,X,[H|T]) :-
    ( X >= H  -> Y = X ; Y = H ),
    maxOfListAux(Z,Y,T).

这里maxOfListAux的第一个参数表示最终答案 列表中最大的元素,但在我们之前我们不知道答案 清空了清单。所以这里的第一个条款“敲定”了答案 当发生这种情况时,将第一个参数与第二个参数统一起来 (最大值“到目前为止”)就在列表尾部到达时 结束。

maxOfListAux的第二个子句使第一个参数保持未绑定状态 相应地“更新”第二个参数作为列表的下一个元素 是否超过以前的最大值。

在这种情况下,不一定要使用辅助谓词, 因为我们可能已经跟踪了使用的最大值 列表的头部而不是额外的参数:

maxOfList(X,[X]) :- !.
maxOfList(X,[H1,H2|T]) :-
    ( H1 >= H2  -> Y = H1 ; Y = H2 ),
    maxOfList(X,[Y|T]).