【问题标题】:What the the variables in following program stores?以下程序中的变量存储了什么?
【发布时间】:2018-08-23 21:22:44
【问题描述】:
total_item([],0).
total_item([_|Rest],N) :- total_item(Rest,C), N is C+1.

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

【问题讨论】:

标签: list recursion count prolog


【解决方案1】:

倒着读:

total_item([], 0).

total_item0 映射到 []两者相关)。

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

C 映射到 RestC+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 .

【讨论】:

    【解决方案2】:

    Will 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 目标。列表中的每个元素都会导致一个未决的算术评估目标。这些未决目标必须存储在堆栈中,直到对total_item /2 谓词的递归调用终止。因此,计算大小为 N 的列表的长度需要与 N 成比例的空间(用于堆栈)。这个谓词定义不是尾递归

    但我们可以重写谓词,使其尾递归通过使用累加器来提高其空间复杂度。累加器是一个存储中间结果的参数,在这种情况下,是列表中元素数量的计数:

    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)。好多了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-01-11
      • 2010-09-18
      • 1970-01-01
      • 2014-07-13
      • 2021-04-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多