在列表中查找第二个最小值

时间:2017-01-04 22:13:01

标签: prolog

我已经定义了在列表中找到最小值的谓词,例如

greater(X,Y):- X > Y.
isLower(X,Y):- X < Y.


findmin( [X]   , X ).
findmin( [H|T] , P ):- findmin(T,P1) , isLower(H,P1), P is H.
findmin( [H|T] , P) :- findmin(T,P1) , greater(H , P1), P is P1.

但是我很难修改此代码以找到第二个最小值,包括嵌套列表。

我如何确保将返回第二个最小值?

3 个答案:

答案 0 :(得分:4)

我的意思是这主要是作为一个笑话,但这里是:

find_second_min(L, Min2) :- sort(L, [_, Min2|_]).

所以,排序肯定会把你所有的物品整理好。只需查看顶部,您就可以获得最低限度。如果你想要两个最小的,你可以看看前两个元素:

find_mins(L, Min1, Min2) :- sort(L, [Min1, Min2|_]).

如您所知,排序为O(N log N),而您只能找到O(N)中的最小值。所以要找到一个值,这可能是太多的工作。但它很可爱。

答案 1 :(得分:3)

您可以简单地将P列为包含两个最小数字的列表。然后你需要检查每个元素是否小于P中的较大元素,如果是,则替换它。然后最后,两者中较大的一个是第二大元素。

顺便说一句,您实际上不需要定义自己的greater / isLower - 为什么不使用内置的运算符> / {{1}在他们的位置?

如果<H完全一样大,这也可以让您更容易发现代码中的错误。

所以,我会这样做:

P1

答案 2 :(得分:1)

首先,您10.0的实施效率不高:

findmin/2

因为它不使用尾递归。你最好将它转换为带尾递归和累加器的子句。

您可以 - 正如@DanielLyons所建议的那样对列表进行排序,然后检索第二个元素,但这需要 O(n log n)时间复杂度进行排序步骤。然而,在大多数Prolog系统中,分类是在低级别C中完成的;但最终,如果列表非常大,那么线性apporach将胜过它。

您还可以通过将两个值存储到列表中来使用@ FelixDombek的方法。人们可以通过以下方式略微提高这种方法的效率:

  • 不使用列表,只是两个参数,因为它将节省模式匹配和元组构造;和
  • 使用if-then-else方法保存比较。

这导致将程序转换为:

findmin([H|T],P):- findmin(T,P1) , isLower(H,P1), P is H.