我试图在Prolog中找到一组的基数。众所周知,一组元素可以重复出现。我试过这个。
cardinal([], 0).
cardinal([_|Tail], N):-
removeRepeated(Tail, ListWithoutRepeated),
cardinal(ListWithoutRepeated, N1),
N is N1 + 1.
----------------------------------------------------
consult:
?- cardinal([1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5], N).
N = 6
但正确的答案是N = 5.显然,我只计算尾巴中的项目,如果头部在尾部重复则忽略。 所以我尝试过这样的事情。那就是添加头尾并重复上述过程。
join([], L, [L]).
join([Head|Tail], L, [Head|Tail2]):-
join(Tail,L, Tail2).
cardinal([], 0).
cardinal([Head|Tail], N):-
join(Tail,Head, List),
removeRepeated(List, ListWithoutRepeated),
cardinal(ListWithoutRepeated, N1),
N is N1 + 1.
但是当您查询无限循环时会生成。 有人可以帮我解决这个问题 任何人都可以帮助我,我怎么能写这个prolog声明?
修改
附上removeRepeated
removeRepeated([],[]).
removeRepeated([Head|Tail],ListWithoutRepeated):-
member(Head,Tail),
!,
removeRepeated(Tail,ListWithoutRepeated).
removeRepeated([Head|Tail],[Head|ListWithoutRepeated]):-
removeRepeated(Tail,ListWithoutRepeated).
----------------------------------------------------
consult:
?- removeRepeated([1,1,1,1,2,2,2,3,3,3,4,4,4,8], N).
N = [1, 2, 3, 4, 8]
答案 0 :(得分:4)
代码:
set_cardinality(Xs, N) :-
list_nub(Xs, Ys),
length(Ys, N).
使用list_nub/2
。可以改进此定义的终止,因为它仅在Xs
的长度固定时终止。但在我们讨论这个问题之前,请先看看你的定义。
尝试使用实际反映您定义的关系的名称。 cardinal/2
和removeRepeated/2
都会留下一个印象,即前者是红衣主教之间的关系,而后者则做了一些事情。但是关系什么都不做。好吧,他们"是"。或者,他们"关联"。但这些并不是充满动作的动词。
现在为您的第一个定义cardinal/2
。实际上,我尝试不来阅读它。特别是,因为它包含了程序员眩晕的首要原因 - 这是
递归
是的,这让我也很头晕。幸运的是,你的问题是关于Prolog的,而在Prolog中,我们经常可以隐藏很多东西并且仍然可以获得很多洞察力。这是我首先看到的东西(我没有看的东西通过打击)。
cardinal([], 0). cardinal([_|Tail], N):-removeRepeated(Tail, ListWithoutRepeated),cardinal(ListWithoutRepeated, N1),N is N1 + 1.
事实上,我可以处理。好的,空列表对应于零。听起来不错。但是,有这条规则的主管:它的内容是:
N
是列表第一个元素的独立。
即:对于cardinal([1,2],N)
和cardinal([2,2],N)
,您将获得完全相同的N
值。这怎么可能是正确的?
removeRepeated/2
(list_nub/2
可能是一个更具关系性的名称)适用于具有基础第一个参数的查询:
?- removeRepeated([1,2], X).
X = [1,2].
?- removeRepeated([1,2],[1,2]).
true.
然而,它意外地失败了:
?- removeRepeated([X,2],[1,2]).
false. % not relational
?- X = 1, removeRepeated([X,2],[1,2]).
X = 1.
因此,虽然专业化成功,但更通用的查询失败。这清楚地表明removeRepeated/2
不是纯粹的关系。有关按预期工作的实现,请参阅list_nub/2
。
答案 1 :(得分:1)
首先:有一个库lists
附带SWI-Prolog(以及其他一些版本),其中包含list_to_set/2
,可用于构建 Set :排序列表,其中每个项目只出现一次。例如:
?- list_to_set([1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5],S),length(S,N).
S = [1, 2, 3, 4, 5],
N = 5.
现在评论您的(第一个)解决方案。问题是,您removeRepeated/2
无法知道cardinal/2
中列表顶部的项目当前是什么。一个小的修复方法是将removeRepeated/2
谓词重写为removeRepeated/3
:
removeRepeated([],_,[]).
removeRepeated([H|T],H,U) :-
!,
removeRepeated(T,H,U).
removeRepeated([X|T],H,[X|U]) :-
removeRepeated(T,H,U).
并将其命名为:
cardinal([], 0).
cardinal([H|Tail],N):-
removeRepeated(Tail,H,ListWithoutRepeated),
cardinal(ListWithoutRepeated, N1),
N is N1 + 1.
请注意,它仍然效率低下,因为:
答案 2 :(得分:1)
仅使用标准谓词的解决方案是对列表进行排序,然后计算其长度:
| ?- sort([1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5], Set), length(Set, Cardinality).
Cardinality = 5
Set = [1,2,3,4,5]
yes
假设sort/2
标准谓词有一个合适的实现,这个解决方案的时间复杂度应该是(最坏情况)O(N * log(N))+ O(N)。