Prolog,数字列表,哪一个更快?

时间:2015-12-20 14:08:41

标签: list numbers prolog

所以,假设我有列表[1,2,3,4,5],我希望从此列表中获取12345

这是我写的代码

l_to_n(L, N) :-
    reverse(L ,P),
    list_to_n(P,0,N).
list_to_n([H|T], C, N) :-
    C1 is C + 1,
    list_to_n(T, C1, P),
    N is H*(10**C) + P.
list_to_n([], _,0).

这是我找到的东西

l_to_n(List, N) :-
    add_zero(List,Num),
    name(N,Num).

add_zero([X|Tail1],[Y|Tail2]) :-
    !,
    Y is X+48,
    add_zero(Tail1,Tail2).
add_zero([],[]) :-
    !.

哪一个更快/更好地用于大型列表?

2 个答案:

答案 0 :(得分:3)

这两个程序无法比较:第一个计算数字,第二个计算原子。第二个显然更简单,因此可能会更有效...如果你有一个内置转换原子到整数,当然......

第一个可以优化,而不是乘法取幂,乘以10,得到幂,并且备用10**C

在SWI-Prolog中,atomic_list_concat/2可以取代第二个......

答案 1 :(得分:1)

我认为两种方式都有点 hacky :首先你首先反转你的列表,这需要 O(n)时间,更重要的是需要额外的 O(n)内存用于存储新列表。然后在不需要尾递归的情况下执行递归调用,同时需要跟踪当前位置并执行指数运算。这可以进行优化。

如果我理解第二个,你基本上要做的是将数字列表转换为ASCII字符列表。然后你希望name能够进行有效的解析。

我提出以下谓词:

l_to_n(L,N) :-
    l_to_n(L,0,N).

l_to_n([H|T],A,N) :-
    !,
    B is A*10+H,
    l_to_n(T,B,N).
l_to_n(_,N,N).

它使用累加器A。对于列表中的每个元素,累加器乘以10,并将H(该数字)添加到累加器。接下来,在列表的尾部进行尾递归。如果使用智能编译器/解释器,尾递归将阻止构建 O(n)调用堆栈。这可能很有用,因为您需要返回结果并撤消调用堆栈会导致额外的计算开销。

然而,这个谓词只能在一个方向上工作:数字列表。

<强>演示

?- l_to_n([1,4,2,5],N).
N = 1425.

?- l_to_n([1,2,3,4,5],N).
N = 12345.