以下程序中存储的变量是什么?

时间:2018-08-23 21:22:44

标签: list recursion count prolog

total_item([],0).
total_item([_|Rest],N) :- total_item(Rest,C), N is C+1.

该程序将数组作为输入并计算该列表中的项目总数。但是我没有得到确切的变量N和C存储的内容。任何解释将不胜感激。谢谢

2 个答案:

答案 0 :(得分:2)

向后阅读:

total_item([], 0).

total_item映射0[]关联这两个)。

total_item([_ | Rest], N) :- 
    total_item( Rest,       C    ), 
                       N is C + 1 .

C映射到Rest,将C+1映射到[_ | Rest]-列表比列表Rest长一个元素。

以生成方式工作的最通用查询可以看到此信息:

2 ?- total_item(L, C).
L = [],
C = 0 ;
L = [_G1464],
C = 1 ;
L = [_G1464, _G1467],
C = 2 ;
L = [_G1464, _G1467, _G1470],
C = 3 ;
L = [_G1464, _G1467, _G1470, _G1473],
C = 4 .

答案 1 :(得分:2)

Ness的答案将为您提供对该谓词定义的清晰理解。但是,您可以从中学到更多。让我们跟踪一个简单的调用。在这里,我使用的是GNU Prolog,但大多数Prolog系统提供相同的跟踪功能:

| ?- trace.
The debugger will first creep -- showing everything (trace)

yes
{trace}
| ?- total_item([1,2,3], N).
      1    1  Call: total_item([1,2,3],_285) ? 
      2    2  Call: total_item([2,3],_354) ? 
      3    3  Call: total_item([3],_378) ? 
      4    4  Call: total_item([],_402) ? 
      4    4  Exit: total_item([],0) ? 
      5    4  Call: _430 is 0+1 ? 
      5    4  Exit: 1 is 0+1 ? 
      3    3  Exit: total_item([3],1) ? 
      6    3  Call: _459 is 1+1 ? 
      6    3  Exit: 2 is 1+1 ? 
      2    2  Exit: total_item([2,3],2) ? 
      7    2  Call: _285 is 2+1 ? 
      7    2  Exit: 3 is 2+1 ? 
      1    1  Exit: total_item([1,2,3],3) ? 

N = 3

(1 ms) yes

您可以在前四行中看到谓词导致遍历列表直到结束,然后 我们计算出待处理 N is C + 1目标。列表中的每个元素都会产生一个未决的算术评估目标。必须将这些未完成的目标存储在 stack 中,直到对total_item /2谓词的递归调用终止为止。结果,计算大小为N的列表的长度需要与N成正比的空间(用于堆栈)。该谓词定义不是 tail-recursive

但是我们可以重写谓词,通过使用累加器使其成为 tail-recursive 来提高其空间复杂度。累加器是一个参数,用于存储中间结果,在这种情况下,该结果到目前为止是列表中元素数量的计数:

total_item(List, Total) :-
    total_item(List, 0, Total).

total_item([], Total, Total).
total_item([_| Rest], Total0, Total) :-
    Total1 is Total0 + 1,
    total_item(Rest, Total1, Total).

让我们追寻相同的目标:

| ?- total_item([1,2,3], N).
      1    1  Call: total_item([1,2,3],_285) ? 
      2    2  Call: total_item([1,2,3],0,_285) ? 
      3    3  Call: _382 is 0+1 ? 
      3    3  Exit: 1 is 0+1 ? 
      4    3  Call: total_item([2,3],1,_285) ? 
      5    4  Call: _435 is 1+1 ? 
      5    4  Exit: 2 is 1+1 ? 
      6    4  Call: total_item([3],2,_285) ? 
      7    5  Call: _488 is 2+1 ? 
      7    5  Exit: 3 is 2+1 ? 
      8    5  Call: total_item([],3,_285) ? 
      8    5  Exit: total_item([],3,3) ? 
      6    4  Exit: total_item([3],2,3) ? 
      4    3  Exit: total_item([2,3],1,3) ? 
      2    2  Exit: total_item([1,2,3],0,3) ? 
      1    1  Exit: total_item([1,2,3],3) ? 

N = 3

(1 ms) yes

请注意,累加器(辅助total_item/3谓词中的第二个参数)如何随着列表的增加而增加。有了这个定义,就没有悬而未决的目标,这意味着空间复杂度是O(1)而不是O(N)。好多了。