Prolog:如何查找和删除最小列表元素?

时间:2013-01-15 14:35:01

标签: prolog

我是Prolog的新手。

我需要帮助编写一个谓词来查找和删除列表中的最小元素。

非常感谢!

3 个答案:

答案 0 :(得分:2)

如果所有列表项都是整数,我们可以使用

:- use_module(library(clpfd)).

我们使用maplist/2(#=<)/2定义zmin_deleted/2same_length/2select/3

zmin_deleted(Zs1,Zs0) :-
   same_length(Zs1,[_|Zs0]),
   maplist(#=<(Min),Zs1),
   select(Min,Zs1,Zs0).

示例查询:

?- zmin_deleted([3,2,7,8],Zs).
  Zs = [3,7,8]
; false.

?- zmin_deleted([3,2,7,8,2],Zs).
  Zs = [3,  7,8,2]
; Zs = [3,2,7,8  ]
; false.

请注意,zmin_deleted/2也适用于&#34;其他方向&#34;:

?- zmin_deleted(Zs,[3,2,7,8]).
  _A in inf..2, Zs = [_A, 3, 2, 7, 8]
; _A in inf..2, Zs = [ 3,_A, 2, 7, 8]
; _A in inf..2, Zs = [ 3, 2,_A, 7, 8]
; _A in inf..2, Zs = [ 3, 2, 7,_A, 8]
; _A in inf..2, Zs = [ 3, 2, 7, 8,_A]
; false.

答案 1 :(得分:1)

让我为你辩护。

How could you find a minimum of a list.

无论如何,有一个很好的min_list谓词。

?- min_list([1,2,2,3],X).
X = 1.

这是一个小例子如何从列表中删除一些元素(注意,所有2都已消失):

?- delete([1,2,2,3],2,X).
X = [1, 3].

如果您只想删除元素的第一次,请使用select

?- select(2, [2,1,2,2,3], X), !.
X = [1, 2, 2, 3].

所以你的最终答案可能是这样的:

delete_min(A, C) :-
  min_list(A, B),
  select(B, A, C), !.

?- delete_min([1,1,2,3],X).
X = [1, 2, 3].

答案 2 :(得分:0)

再次,只需在列表中使用结构递归。列表由节点[H|T]构成,即具有两个字段的复合数据结构 - head H tail T 。 Head是节点中保存的数据(列表元素),T是列表的其余部分。

我们通过滚动列表找到最小元素,同时保留一个额外的数据 - 迄今为止所见的最小元素:

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

空列表案例没有定义 - 空列表没有最小元素。

minimum_elt([],X,X).

如果列表中没有其他元素,那么我们到目前为止就是答案。

minimum_elt([A|B],M,X):- 

这里有两种情况:A < M或其他:

    A < M, minimum_elt(B,A,X).

minimum_elt([A|B],M,X):- 

    A >= M, minimum_elt(B,M,X).

没有什么可说的了,所以这就完成了程序。


编辑:除了,您还要删除该元素。这会改变一切。嗯。一个明显的方法是首先找到最小的elt,然后删除它。我们必须再次比较所有元素,这次是针对之前找到的最小元素。我们可以一次扫描吗?

在Lisp中我们可以拥有。要通过手术删除列表中的任何元素,我们只需将上一个节点的尾指针重置为指向删除后的 next 节点。然后使用这种方法,我们扫描输入列表一次,将前一个节点的引用保持到目前为止找到的最小元素,当我们找到越来越小的元素时交换它。然后,当我们到达列表的末尾时,我们只是通过手术删除最小节点。

但在Prolog中,我们无法重置事物。 Prolog是设置一次语言。所以看起来好像我们需要两次传递列表...或者我们可以尝试非常聪明,并在我们去的时候构建所有可能的列表,每次我们找到新候选者时将它们排序最小的元素。

rem_min([A|B],L):-
    % two possibilities: A is or isn't the minimum elt
    rem_min(B,A,([A|Z],Z,Z),L).

rem_min([],A,(With,Without,Tail),L):- Tail = [],
    % A is indeed the minimal element
    L = Without.

rem_min([H|T],A,(With,Without,Tail),L):- H >= A, Tail=[H|Z],
    rem_min(T,A,(With,Without,Z),L).

rem_min([H|T],A,(With,Without,Tail),L):- H < A,  % use this H
    copy_the_list(With,Tail,W2,T2),              % no good - quadratic behaviour
    Tail=[H|Z], T2=Z,
    rem_min(T,A,(With,W2,Z),L).

copy_the_list([A|B],T,[A|C],C):- var(B), !, T=B.            % fresh tail
copy_the_list([A|B],T,[A|C],T2):- copy_the_list(B,T,C,T2).

所以看起来我们无法避免第二次传球,但至少我们可以保存所有多余的比较:

rem_min([A|B],L):- N=[A|_], rem_min(B,A,N,[N|Z],Z,L).

rem_min([],_A,N,L2,Z,L):- Z=[], N=[_,1], % finalize the minimal entry
    scan(L2,L).
rem_min([H|T],A,N,L2,Z,L):- H >= A, Z=[H|Z2], rem_min(T,A,N,L2,Z2,L).
rem_min([H|T],A,N,L2,Z,L):- H < A,       % use this H
    N2=[H|_], N=[_],                     % finalize the non-minimal entry
    Z=[N2|Z2], rem_min(T,H,N2,L2,Z2,L).

scan( [], []).
scan( [[_,1]|B],C):- !, scan(B,C).       % step over the minimal element
scan( [[A]|B],[A|C]):- !, scan(B,C).     % previous candidate
scan( [A|B], [A|C]):- !, scan(B,C).