【问题标题】:Prolog Recursion Doesn't Stop as ExpectedProlog 递归没有按预期停止
【发布时间】:2018-04-24 08:01:45
【问题描述】:

大家好,这是我的第一篇文章,所以如果您对如何提问有任何建议,我会全力以赴。等等我的问题我正在尝试使用递归对数字列表进行排序,我有一个my_max/2 谓词返回列表的最大值,所以在返回之后我从列表中选择该值,然后将其添加到我的排序中列表。然后我用新列表递归。

我的问题是谓词似乎可以工作并找到正确的列表,但是当谓词退出时,它会将所有列表恢复到原始状态,基本上撤消了谓词所做的所有工作。我认为这与 Prolog 如何回溯有关?

%finds the max of a list, if the list is empty return int_min

my_max([],-2147483647).
my_max(L,M):-select(M,L,Rest), \+ (member(E,Rest),E>M).

%calls the my_max predicate store it in X, combines x and sorted and appends 
%it to sorted2,then it takes X out of unsorted and creates Unsorted2 then  
%recurse with unsorted2 and sorted2 should stop and output when unsorted is 
%empty or []

my_sort([],S).
%my_sort([],S):-write(S). for test    
my_sort(Unsorted,Sorted):-
   my_max(Unsorted,X),
   append(Sorted,[X],Sorted2),
   select(X,Unsorted,Unsorted2),
   my_sort(Unsorted2,Sorted2).

我添加了 write 只是为了表明它对列表进行了排序。输出应该是S=[3,2,1,1]

Output from the trace

【问题讨论】:

  • 我不了解 Prolog,但您的代码对我来说毫无意义。 my_sort([], S). 不是声明对空列表进行排序会给出任意结果S

标签: recursion prolog


【解决方案1】:

首先,当我加载你的文件时:

Warning: Singleton variables: [S]

由于基本情况:

my_sort([],S).

问题在于,基本情况表明空列表与单例变量 S 匹配,因此请尝试:

?- my_sort([],[1,2]).
true ;
false.

?- my_sort([],hello).
true ;
false.

在这两种情况下my_sort/2 都不应该成功。所以你的基本情况应该是空列表:

my_sort([],S). 

而不是在基本情况下构建完整的排序列表,您可以通过递归构建它并在基本情况下留下一个空列表:

my_sort([],[]).
my_sort(Unsorted,Sorted):-
   my_max(Unsorted,X),
   select(X,Unsorted,Unsorted2),
   my_sort(Unsorted2,Sorted2),  %  <- continue to find the sorted sublist
   append(Sorted2,[X],Sorted).  %  <-place max at the end of sorted

在上面的Sorted2是Sorted的子列表,所以你递归地找到子问题的列表Sorted2,然后添加最大值。这是在每个步骤中递归完成的,在基本情况下,您将有空列表。

为了更好地理解它,这里有一个示例说明:
假设您要对[2,1,3] 列表进行排序。

  • 查找max = 3查找排序为[2,1](后面所有递归调用后会添加3)
  • 查找max = 2 查找排序为[1]
  • 查找max = 1查找排序为[]这是[]
  • 添加max = 1 -> Sorted = [1]
  • 添加max = 2 -> Sorted = [2]
  • 最后添加max = 3 -> Sorted = [1,2,3] 示例:

    ?- my_sort([4,1,3,2],L)。 L = [1, 2, 3, 4] ; 假的。


一些优化

在每个步骤中,您通过遍历未排序列表在 O(n) 步中找到最大值,其中 n 是未排序列表的长度。再次追加 O(n)。再次选择 O(n)。因此,总体而言,在每个步骤中,您需要进行 3 次 O(n) 计算。

为避免您可以按降序构建列表,因此您不需要在 O(n) 中使用 append。

您的最大谓词也可以返回 Rest 列表,这样您就可以避免排序谓词中的 select/3 以减少另外 N 步:

my_sort([],[]).

my_sort(Unsorted,[X|Sorted]):-
   my_max(Unsorted,X,Unsorted2),
   my_sort(Unsorted2,Sorted).

例子:

?- my_sort([4,1,3,2],L).
L = [4, 3, 2, 1] ;
false.

现在使用 reverse/2 得到升序:

?- my_sort([4,1,3,2],L),reverse(L,L1).
L = [4, 3, 2, 1],
L1 = [1, 2, 3, 4] ;
false.

这会执行 O(N) 步骤来反转列表,但只有一次不在每个递归调用中!!

【讨论】:

  • 感谢您的回复,这对您有很大帮助。我想知道您或其他人是否可以穿过痕迹?我对递归实际上是如何发生的感到困惑?我有使用 C、Java 等其他语言的经验……但没有像 Prolog 这样的语言。
  • 不客气!!!至于你关于跟踪的问题,也许最好问一个不同的问题,这样更多的人会看到它并可以提供帮助......
猜你喜欢
  • 2015-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多