二叉树prolog中的事件计数

二叉树prolog中的事件计数,prolog,binary-tree,Prolog,Binary Tree,我想实现一个代码,该代码将获取整个树中某个数字的出现次数,例如: numberOfOccurrences(7, bt(6, bt(2, bt(1, nil, nil), bt(3, nil, nil)), bt(8, bt(7, nil, nil), bt(9, nil, nil))), N). N

我想实现一个代码,该代码将获取整个树中某个数字的出现次数,例如:

numberOfOccurrences(7, bt(6, bt(2, bt(1, nil, nil),
                                   bt(3, nil, nil)),
                             bt(8, bt(7, nil, nil),
                                   bt(9, nil, nil))), N).
N = 1;

我该怎么做呢?

你试过定义吗

出现次数(7,bt(6,bt(2,bt(1,无,无),
bt(3,无,无),,
英国电信(8,英国电信(7,无,无),
bt(9,零,零),1)。
??你试过定义吗

出现次数(7,bt(6,bt(2,bt(1,无,无),
bt(3,无,无),,
英国电信(8,英国电信(7,无,无),
bt(9,无,无)),N):-
N=1。
??你试过定义吗

出现次数(7,T,N):-
T=bt(6,bt(2,bt(1,无,无),
bt(3,无,无),,
英国电信(8,英国电信(7,无,无),
bt(9,无,无),,
N=1。
??甚至可能

出现次数(7,T,N):-
T=bt(6,TL,TR),
TL=bt(2,bt(1,无,无),%
bt(3,无,无),,
TR=bt(8,bt(7,无,无),%
bt(9,无,无),,
N=1。
??你也试过定义吗

出现次数(7,T,N):-
T=bt(6,TL,TR),
N1=0,%
TL=bt(2,bt(1,无,无),
bt(3,无,无),,
NL=0,%
TR=bt(8,bt(7,无,无),
bt(9,无,无),,
NR=1,%
N为N1+NL+NR.%
??难道不是这样吗

出现次数(7,T,N):-
T=bt(6,TL,TR),
N1=0,
TL=bt(2,bt(1,无,无),
bt(3,无,无),,
发生次数(7,TL,NL),%
NL=0,
TR=bt(8,bt(7,无,无),
bt(9,无,无),,
发生次数(7,TR,NR),%
NR=1,
N是N1+NL+NR。
??而且还只是

出现次数(7,T,N):-
T=bt(6,TL,TR),
N1=0,
%%
发生次数(7,TL,NL),
%%
发生次数(7次,TR,NR),
%%
N是N1+NL+NR。
??你有没有尝试过进一步推广它,去掉最后一个人为的具体值,也用逻辑变量替换它们

出现次数(X,T,N):-%
T=bt(Y,TL,TR),%
计数一次可能发生的事件(X,Y,N1),
发生次数(X、TL、NL),%
发生次数(X、TR、NR),%
N是N1+NL+NR。

??你能继续这样想吗?

你应该试着把大问题分解成多个小问题。因此,首先:在树上操作是复杂的,列表更易于处理:

treeToList(Tree, List) :-
    % I use an accumulator, starting with an empty list.
    treeToList(Tree, [], List).

% The bottom is reached: The accumulated elements are the result.
treeToList(nil, Accu, Accu).

treeToList(bt(E, Left, Right), Accu0, List) :-
    Accu1 = [E|Accu0],              % prepend the accumulator with the current element
    treeToList(Left, Accu1, Accu2), % prepend elements of the left node
    treeToList(Right, Accu2, List). % prepend elements of the right node
在排序的列表中计数要比在未排序的列表中计数容易得多。Prolog有一个内置的谓词

?- sort([9, 7, 8, 3, 1, 2, 6], L).
L = [1, 2, 3, 6, 7, 8, 9].
您可以计算相邻值的数量,并在一个步骤中获得剩余的不同值:

removeFromFrontAndCount(_, [], [], N, N).

removeFromFrontAndCount(E, [F|Out], [F|Out], N, N) :-
    E \= F.

removeFromFrontAndCount(E, [E|In], Out, N0, N2) :-
    N1 is N0 + 1,
    removeFromFrontAndCount(E, In, Out, N1, N2).
使用该辅助对象是/3:

countAdjacent(List0, E, N) :-
    [E0|List1] = List0,
    removeFromFrontAndCount(E0, List1, List2, 1, CountE),
    (   % a semicolon is an either-or operator
        E = E0, N = CountE;
        countAdjacent(List2, E, N)
    ).
并将一切结合起来:

numberOfOccurrences(E, Tree, N) :-
    treeToList(Tree, List),
    sort(List, SortedList),
    countAdjacent(SortedList, E, N).
全部代码:

numberOfOccurrences(E, Tree, N) :-
    treeToList(Tree, List),
    sort(List, SortedList),
    countAdjacent(SortedList, E, N).


treeToList(Tree, List) :-
    treeToList(Tree, [], List).

treeToList(nil, Accu, Accu).

treeToList(bt(E, Left, Right), Accu0, List) :-
    treeToList(Left, [E|Accu0], Accu1),
    treeToList(Right, Accu1, List).


countAdjacent(List0, E, N) :-
    [E0|List1] = List0,
    removeFromFrontAndCount(E0, List1, List2, 1, CountE),
    (
        E = E0, N = CountE;
        countAdjacent(List2, E, N)
    ).


removeFromFrontAndCount(_, [], [], N, N).

removeFromFrontAndCount(E, [F|Out], [F|Out], N, N) :-
    E \= F.

removeFromFrontAndCount(E, [E|In], Out, N0, N2) :-
    N1 is N0 + 1,
    removeFromFrontAndCount(E, In, Out, N1, N2).

我对prolog非常陌生,所以这就是我得到的numberOfExcients(Ubt(),0)。NumberOfEmptures(E,bt(Root,LC,RC),N):-NumberOfEmptures(E,LC,Z),N是Z+1。我重写了我的答案。请看一看。很好的新方法!我正在用同样的旧竖琴演奏诗意起初我只想发表评论,但它却跑开了。:)@假与。从需求开始,重新编写它,直到它成为一个正确的定义。(他在年称之为“语义派生”)。以前从未知道这项工作(如果你不是在开“新”的玩笑,我最近在tag:prolog中发布了很多关于这种“泛化”代码派生技术的答案)。它总是以“从你已经拥有/知道的开始”或诸如此类的话开头你的第一步确实微不足道(属于逻辑部分),但对于初学者来说仍然很有洞察力。首先,获取(相对复杂的)查询并将其作为程序粘贴回去。我喜欢以类似的方式介绍简单递归谓词的开发,但从基本情况开始。当您介绍递归目标(没有语义上的正当性)时,会有一些挥手示意——可以详细说明。但是,这样的陈述总是吸引读者的直觉。@false将基本情况放在第一位是如此的口齿不清。:)我喜欢首先关注转换/关系的性质,关注我们正在做什么,而不是什么时候必须停止做(“停止做什么?”),因此,首先要处理非基本步骤。corecursion比递归更吸引我,它更关注本质;递归更具操作性,与终止有关,而corecursion则不关心,只关心步骤的生产率。基本情况类似于操作细节。Prolog的TRMC()在我第一次“了解”它时给我留下了深刻的印象。遵循“关注点分离”的设计理念,
countnextendent
可以进一步分为
rle/2
?- countAdjacent([1,1,1,2,2,3], E, N).
E = 1, N = 3 ;
E = 2, N = 2 ;
E = 3, N = 1 ;
false.
numberOfOccurrences(E, Tree, N) :-
    treeToList(Tree, List),
    sort(List, SortedList),
    countAdjacent(SortedList, E, N).
?- numberOfOccurrences(E, bt(6, bt(2, bt(1, nil, nil),
                                bt(3, nil, nil)),
                          bt(8, bt(7, nil, nil),
                                bt(9, nil, nil))), L).
E = 1, L = 1 ;
E = 2, L = 1 ;
E = 3, L = 1 ;
E = 6, L = 1 ;
E = 7, L = 1 ;
E = 8, L = 1 ;
E = 9, L = 1 ;
false.
numberOfOccurrences(E, Tree, N) :-
    treeToList(Tree, List),
    sort(List, SortedList),
    countAdjacent(SortedList, E, N).


treeToList(Tree, List) :-
    treeToList(Tree, [], List).

treeToList(nil, Accu, Accu).

treeToList(bt(E, Left, Right), Accu0, List) :-
    treeToList(Left, [E|Accu0], Accu1),
    treeToList(Right, Accu1, List).


countAdjacent(List0, E, N) :-
    [E0|List1] = List0,
    removeFromFrontAndCount(E0, List1, List2, 1, CountE),
    (
        E = E0, N = CountE;
        countAdjacent(List2, E, N)
    ).


removeFromFrontAndCount(_, [], [], N, N).

removeFromFrontAndCount(E, [F|Out], [F|Out], N, N) :-
    E \= F.

removeFromFrontAndCount(E, [E|In], Out, N0, N2) :-
    N1 is N0 + 1,
    removeFromFrontAndCount(E, In, Out, N1, N2).