从递归的列表中识别

时间:2015-02-08 10:34:14

标签: list recursion prolog

目前正在学习计算逻辑以及Prolog的基础知识。在我的笨拙演讲中请耐心等待我!

我遇到过一个问题,在查询包含整数的列表列表时,必须设计一种方法来计算使用递归计算所有列表的最高总和。

例如:

?- getSum([[1,3,6],[9,5,2],[3,4,7]], X).
X = 16.

应该是输出。

我相信找到列表总和的正确方法是:

sum([],0).
sum([Head|Body], Output) :- sum(Body, BodySum),
   Output is Head + BodySum.

但是我需要在显示结果之前比较总和,我是否必须在总和递归中调用另一个条件?

由于

2 个答案:

答案 0 :(得分:4)

首先发表几条评论:

命名:您可能希望为谓词命名,以便明确它的作用。并且,Prolog更喜欢names_like_thisnamesInCamelCase。也许,可以称之为max_sublist_sum,也许?

实施:在您提出的问题中,"使用递归"。 必须你使用递归,还是认为使用递归是你唯一的选择?由于这是一个微不足道的问题,因此可以使用库谓词并完全避免递归来解决它。例如,要查找每个子列表的总和:

maplist(sum_list, List_of_lists, Sums)

现在,您已将列表列表缩减为总和列表。您可以找到最大的数字列表:

max_list(List_of_numbers, Max_number)

所以,你的问题变成了:

?- maplist(sum_list, [[1,3,6],[9,5,2],[3,4,7]], Sums),
   max_list(Sums, Max_sum).
Sums = [10, 16, 14],
Max_sum = 16.

现在,实施sum_list/2max_list/2中的每一个似乎都是一个很好的练习,但一个好的起点是查看这两个中的library implementation。同样适用于definition of maplist/3

你也可以将两者交织在一起:

max_sublist_sum0([H|T], Max) :-
    sum_list(H, Sum),
    max_sublist_sum0_(T, Sum, Max).
max_sublist_sum0_([], Max, Max).
max_sublist_sum0_([H|T], M0, Max) :-
    sum_list(H, Sum),
    (   Sum > M0
    ->  max_sublist_sum0_(T, Sum, Max)
    ;   max_sublist_sum0_(T, M0, Max)
    ).

辅助谓词max_sublist_sum_/3实际上是一个折叠:

max_sum(L, M0, M) :-
    sum_list(L, Sum),
    M is max(M0, Sum).

max_sublist_sum1([H|T], Max) :-
    sum_list(H, Sum),
    foldl(max_sum, T, Sum, Max).

然而,这仍然是比原始建议更多的代码:

max_sublist_sum(L, M) :-
    maplist(list_sum, L, S),
    max_list(S, M).

有趣的是,在我的计算机上,最后一个版本对于较大的列表也是最快的,并且与其他两个版本的速度相同。

答案 1 :(得分:-1)

您不需要在递归中调用另一个条件,您必须将问题分解为计算总和和最大值。遵循max谓词的经典实现,其中第二个参数是当前最大值,这将类似于:

max([], X, X).
max([H|T], X, Y) :-
  sum(H, S),
  S < X,
  max(T, X, Y).
max([H|T], X, Y) :-
  sum(H, S),
  S >= X,
  max(T, S, Y).

getSum(L, X) :- max(L, 0, X).

通过使用if-construct或cut,你可以使这段代码更有效率和优雅,我把它留给你。