【问题标题】:Prolog: How to find and remove minimum list element?Prolog:如何查找和删除最小列表元素?
【发布时间】:2012-12-29 16:26:12
【问题描述】:

我是 Prolog 的新手。

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

非常感谢!

【问题讨论】:

  • > 关闭为不是一个真正的问题
  • @ДМИТРИЙМАЛИКОВ,不幸的是,人们很快就会关闭他们不喜欢的问题。它可能已关闭,因为没有明显的 OP 研究迹象。

标签: prolog


【解决方案1】:

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

:- 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 也适用于“其他方向”:

?- 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.

【讨论】:

    【解决方案2】:

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

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

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

    空列表没有定义——空列表没有最少元素。

    minimum_elt([],X,X).
    

    如果列表中没有更多元素,我们目前得到的就是答案。

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

    这里有两种情况:A &lt; M,否则:

        A < M, minimum_elt(B,A,X).
    
    minimum_elt([A|B],M,X):- 
    
        A >= M, minimum_elt(B,M,X).
    

    没什么好说的了,程序到此结束。


    编辑:除了,您还想删除该元素。这改变了事情。唔。一种明显的方法是首先找到最小 elt,然后将其删除。我们必须再次比较所有元素,这次与之前找到的最小元素进行比较。我们可以在一次扫描中做到这一点吗?

    在 Lisp 中我们可以。要从列表中删除任何元素,我们只需将 previous 节点的尾指针重置为指向被删除后的 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).    
    

    【讨论】:

      【解决方案3】:

      让我帮你google一下。

      How could you find a minimum of a list..

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

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

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

      ?- 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].
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-07-18
        • 1970-01-01
        • 2016-02-12
        • 2017-09-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多