繁体   English   中英

prolog 是 X 数字 A、B、C 的中位数

[英]prolog is X the median of numbers A, B, C

我刚开始学习 prolog 时遇到了一些麻烦。 我不确定如何测试 X 是否是 A、B、C 的中位数。我的第一个想法是列出 A、B、C 的列表,然后对其进行排序。 然后我会检查 X 是否等于第二个数字。 问题是我不知道如何取三个值并将它们变成一个列表(如果可以的话)。 这甚至是最有效的方法吗? 老实说,我不知道所以任何网站都会有帮助。

这是一个非常基本的解决方案,排序只接受 3 个值,但它应该可以解决问题。

  is_median_of_sorted([_, ValueToCheck, _],ValueToCheck).

  sorted_list_of_3([A,B,C],R) :- 
      A>B, A>C, B>C, R = [A,B,C];
      A>C, A>B, C>B, R = [A,C,B];
      B>A, B>C, A>C, R = [B,A,C];
      B>C, B>A, C>A, R = [B,C,A];
      C>A, C>B, A>B, R = [C,A,B];
      C>B, C>A, B>A, R = [C,B,A].

  is_median_of_3(List, ValueToCheck) :-
      sorted_list_of_3(List,SortedList),
      is_median_of_sorted(SortedList, ValueToCheck).

要检查它,请查询:

    is_median_of_3([1,10,4],4). 

或者,如果您想检查给定列表的中位数:

    is_median_of_3([1,10,4],X).

您也可以通过浏览器查看: https : //swish.swi-prolog.org/p/three_values_median.pl

它的作用是: is_median_of_3首先获取一个匹配的排序列表,然后再次检查is_median_of_sorted它只选择列表的第二个元素。

希望我能帮上忙。

如果您想创建一个模块化程序,您必须将所有元素插入一个列表中,对其进行排序并找到中位数。 这可以通过这种方式完成:

findMedian([H|_],0,H):- !.
findMedian([_|T],C,X):-
    C1 is C-1,
    findMedian(T,C1,X).

median(L,X):-
    msort(L,SortedL),
    length(SortedL,Len),
    Len2 is Len//2,
    findMedian(SortedL,Len2,X).

?- median([1,10,4,5,7],X).
X = 5
?- median([1,10,4,5,7],5).
true

此解决方案也适用于具有偶数个元素的列表,返回列表中间之后的元素(例如 4 个元素, [0,1,2,3] ,它返回2 )。 在这种情况下,您必须决定要做什么(失败,返回中间 ecc 中的两个元素...)

编辑:正如评论中所建议的,您应该使用msort/2而不是sort/2因为sort/2删除重复的元素。

我会选择一个类似于@damianodamiano 的解决方案,但我会在不使用length/2情况下找到列表的中间元素:

median(List, Median) :-
    msort(List, SortedList),
    middle_element(SortedList, SortedList, Median).

middle_element([], [M|_], M).
middle_element([_], [M|_], M).
middle_element([_,_|Xs], [_|Ys], M) :-
    middle_element(Xs, Ys, M).

检查 X 是否是 A、B、C 的中位数? ”的简单答案是:

is_median_of_3(A,B,C,X):-
    msort([A,B,C],[_,X,_]).

如果[A,B,C]排序由任何列表(三个元素)组成,其中X作为中间元素[A,B,C]这将尝试匹配。


我不知道无处不在,但在swish 中,有来自msort残差:

msort([2,8,4],L).



L = [2, 4, 8],
_residuals = []

L = [2, 4, 8],
_residuals = [_1080]

L = [2, 4, 8],
_residuals = [_1122, _1128]

L = [2, 4, 8],
_residuals = [_1170, _1176, _1182]

L = [2, 4, 8],
_residuals = [_1224, _1230, _1236, _1242]

L = [2, 4, 8],
_residuals = [_1284, _1290, _1296, _1302, _1308]

L = [2, 4, 8],
_residuals = [_716, _722, _728, _734, _740, _746]

L = [2, 4, 8],
_residuals = [_788, _794, _800, _806, _812, _818, _824]

L = [2, 4, 8],
_residuals = [_866, _872, _878, _884, _890, _896, _902, _908]

等等...

另外,我无法在tutorialspoint 中对其进行测试,因为它似乎已损坏。

遵循生成和测试方法,您可以编写:

median(List,Median) :-
    dif(List,[]), msort(List,SList), length(List,Len),
    append(Low,[Median],Tmp), append(Tmp,High,SList),
    length(Low,LowLen), div(Len,2)=:=LowLen, !.

这有一个方便的声明性阅读: Median值是一个非空List的值, SList List的排序版本SList分成两半LowHigh ,即。 MedianList值分布的“中间元素”。

事实上,上面的程序通过检查SList是否可以写成列表串联Low + [Median] + High来确定Median ,使得Low的长度是SList长度的SList 由于从不使用High (即它是一个单例),程序可以通过用_替换它来重写,如下所示:

median(List,Median) :-
    dif(List,[]), msort(List,SList), length(List,Len),
    append(Low,[Median],Tmp), append(Tmp,_,SList),
    length(Low,LowLen), div(Len,2)=:=LowLen, !.

自然,也可以区分列表长度为奇数的情况和偶数的情况,因此在后一种情况下返回两个中值元素的平均值:

median(List,Median) :-
    is_list(List), dif(List,[]), 
    msort(List,SList), length(List,Len),
    median(SList,Len,Median).
    
median(SList,Len,Median) :-
    Len mod 2 =:= 1, 
    append3(Low,[Median],_,SList),
    length(Low,LowLen), div(Len,2)=:=LowLen, !.
median(SList,Len,Median) :-
    Len mod 2 =:= 0, 
    append3(Low,[M1,M2],_,SList),
    length(Low,LowLen), div(Len,2)=:=LowLen + 1,
    Median is (M1+M2)/2, !.

append3(L1,L2,L3,L) :- append(L1,L2,T), append(T,L3,L).

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM