Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sorting 在Prolog中对大列表排序:内存不足_Sorting_Prolog_Stack - Fatal编程技术网

Sorting 在Prolog中对大列表排序:内存不足

Sorting 在Prolog中对大列表排序:内存不足,sorting,prolog,stack,Sorting,Prolog,Stack,我试图用bubblesort在prolog中对一个10k元素列表进行排序,得到了本地堆栈外错误。Mergesort似乎是最好的选择,因为对于相同的输入,我没有得到任何错误。然而,我真的很想为具有大输入数据的bubblesort获得一些运行时间,但我不能。有什么想法吗 代码如下: %% NOTE: SWI-PROLOG USED %% generate_list(Limit, N, L): - insert upper limit and length of list N %% to ge

我试图用bubblesort在prolog中对一个10k元素列表进行排序,得到了本地堆栈外错误。Mergesort似乎是最好的选择,因为对于相同的输入,我没有得到任何错误。然而,我真的很想为具有大输入数据的bubblesort获得一些运行时间,但我不能。有什么想法吗

代码如下:

 %% NOTE: SWI-PROLOG USED

 %% generate_list(Limit, N, L): - insert upper limit and length of list N
 %% to get a random list with N numbers from 0 to limit
 generate_list(_, 0, []).
 generate_list(Limit, N, [Y|L]):-
    N =\= 0,
    random(0, Limit, Y),
    N1 is N-1,
    generate_list(Limit, N1, L).


 %% bubble(L, Ls, max):- insert list L and get max member of list by
 %% swapping members from the start of L.
 bubble([Z], [], Z).
 bubble([X,Y|L], [X|Ls], Z):- X =< Y, bubble([Y|L], Ls, Z).
 bubble([X,Y|L], [Y|Ls], Z):- X  > Y, bubble([X|L], Ls, Z).

 %% bubble_sort(List, Accumulator, Sorted_List)
 bubblesort([X], Ls, [X|Ls]).
 bubblesort(L, Accumulate, Result):- bubble(L, Ls, Max),
       bubblesort(Ls, [Max|Accumulate], Result).

 bubble_sort(L, Sorted):- bubblesort(L, [], Sorted).
但它只会运行更长的时间。最终,我再次从本地堆栈中退出。
我应该使用另一种语言,如C和malloc,还是不使用递归?

免责声明:遵循@mat的提示可能更有益

在我的实验中,本地堆栈溢出被抛出,列表长度接近2500。然后我放了一些切口:

%% bubble(L, Ls, max):- insert list L and get max member of list by
%% swapping members from the start of L.
bubble([Z], [], Z).
bubble([X,Y|L], [R|Ls], Z):-
 ( X =< Y -> (R,T)=(X,Y) ; (R,T)=(Y,X) ),
 bubble([T|L], Ls, Z).

%% bubble_sort(List, Accumulator, Sorted_List)
bubblesort([X], Ls, [X|Ls]) :- !.
bubblesort(L, Accumulate, Result):-
 bubble(L, Ls, Max),
 !, bubblesort(Ls, [Max|Accumulate], Result).

因此,它正在工作,但非常缓慢,显示出二次复杂性…

这里是
bubble/3
的一个版本,如果第一个参数被实例化,它是确定的,因此尾部调用优化(更具体地说,尾部递归优化)适用于:

对于测试不同版本,请使用可用于可靠地复制相同初始列表的查询版本,例如:

?- numlist(1, 10_000, Ls0), time(bubble_sort(Ls0, Ls)).
好处是:如果您只使用
library(clpfd)
中的
zcompare/3
而不是
compare/3
,您可以获得一个可以在各个方向使用的版本:

?- bubble(Ls0, Ls, Max).
Ls0 = [Max],
Ls = [] ;
Ls0 = [Max, _G677],
Ls = [_G677],
_G677#=<Max+ -1,
zcompare(<, _G677, Max) ;
Ls0 = [Max, _G949, _G952],
Ls = [_G949, _G952],
_G952#=<Max+ -1,
_G949#=<Max+ -1,
zcompare(<, _G952, Max),
zcompare(<, _G949, Max) ;
etc.
?-气泡(Ls0、Ls、最大值)。
Ls0=[Max],
Ls=[];
Ls0=[最大值,_G677],
Ls=[[u G677],

_G677#=因为有两个答案,没有人明确指出你陷入“本地堆栈外”麻烦的原因(Mat在对你的问题的评论中说你的谓词不是确定性的,但没有确切解释原因)

您定义的两个谓词,即
bubblesort/3
bubble/3
,具有互斥子句。但是Prolog(至少SWI Prolog)不承认这些是相互排斥的。因此,创建了选择点,您不会得到尾部递归优化,也可能不会进行垃圾收集(如果您想知道选择的实现在何时何地进行了多少,则需要使用选择的实现进行度量)

你有两个不同的问题

问题1:仅包含一个元素的列表 这个问题在两个谓词中都会出现。在最简单的谓词中:

foo([_]).
foo([_|T]) :-
    foo(T).
然后:

?- foo([a]).
true ;
false.
这并不奇怪;考虑:

?- [a] = [a|[]].
true.
您可以使用一种称为滞后的技术来解决此问题:

然后:

bar_1/2
的定义中,第一个子句的第一个参数是空列表;第二个子句的第一个参数是非空列表(至少有一个元素和一个尾部的列表)。当所有子句显然都是独占的时,Prolog不会创建选择点。什么是明显的方法取决于实现,但通常,当所有子句的第一个参数都是具有不同函子的术语时,就不会创建选择点

尝试以下操作(您可能会得到不同的结果,但消息是相同的):

请参阅和Mat的答案,以了解如何使用它使程序具有确定性

马特在他的回答中使用了这种方法,如果我看得没错的话

问题2:条款主体中的约束(条件) 这就是
bubble/3
的第二和第三个子句的问题。在教科书中选择两个元素中的最小值的“正确”示例中:

min(A, B, B) :- B @< A.
min(A, B, A) :- A @=< B.
但是:

你可以用两种方法来解决这个问题:要么做Mat正在做的事情,也就是说,使用
compare/3
,这将决定性地成功;或者,通过做Capelical正在做的事情,也就是使用if-then-else

垫子:

helper
random\u pos\u ints/2
是一个简单的谓词,可以用
maplist
表示:

generate_list(Limit, Len, List) :-
    length(List, Len),
    maplist(random(0, Limit), List).    

尾部递归优化在您的情况下没有帮助,因为您的谓词不是确定性的:参数索引无法区分
bubble/3
的不同子句。您可以重写子句(引入辅助谓词和滞后参数),这样就可以通过第一个参数索引来区分它们,而不会牺牲纯度或单调性。不要试图引入任何杂质!相反,使用例如
compare/3
和一个辅助谓词,其中
>
按照@mat的提示使用
compare/3
是可以的,但前提是OP不在乎他是否只对数字进行排序。很难知道这是否是最初的意图。我得到的执行时间比您显示的要慢得多(例如,
?-generate_list(1002000,L),time(bubble_sort(L,S))。%329209251推断,
)。您是否更改了答案中未显示的内容?正如我所说:执行时间取决于生成的随机列表。要重现结果,您必须非常幸运,并生成与我案例中生成的列表完全相同的列表。请使用具有相同列表的确定性测试用例对两个版本进行比较。我已在发布了比较代码,此查询显示了问题:
?-generate_list(100200,L)、time(bubble_sort_m(L,S))、time(bubble_sort_c(L,c))。
@capelical您正在swish上的代码中使用
zcompare
!将其更改为
compare
,它将恢复“正常”(由于缺少创建和删除选择点,速度更快)。@capelical:是的,我无意中发布了
zcompare/3
版本本身,而不是不太通用的版本。我已经修好了!谢谢但是我仍然不明白为什么选择点没有在bar谓词中创建?成功后不应该仍然检查bar_1([H | t],:-bar_1(t,H)子句吗?我试图寻找这种技术,但没有找到much@user3161227我将把这个添加到答案中。。。你也可以试着让你的问题的标题更一般一些:至少加上“避免选择点创建”之类的东西
?- foo([a]).
true ;
false.
?- [a] = [a|[]].
true.
bar([H|T]) :-
    bar_1(T, H).
bar_1([], _).
bar_1([H|T], _) :-
    bar_1(T, H).
?- bar([a]).
true.
?- functor([], Name, Arity).
Name = [],
Arity = 0.

?- functor([_|_], Name, Arity).
Name = '[|]',
Arity = 2.
min(A, B, B) :- B @< A.
min(A, B, A) :- A @=< B.
?- min(1,2,1).
true.
?- min(2,1,1).
true ;
false.
min_m(A, B, Min) :-
    compare(Order, A, B),
    min_order(Order, A, B, Min).
min_order(<, A, _, A).
min_order(=, A, _, A).
min_order(>, _, B, B).
min_c(A, B, Min) :-
    (   B @< A
    ->  Min = B
    ;   Min = A
    ).
generate_list(Limit, Len, List) :-
    length(List, Len),
    random_pos_ints(List, Limit).

random_pos_ints([], _).
random_pos_ints([H|T], Limit) :-
    random(0, Limit, H),
    random_pos_ints(T, Limit).
generate_list(Limit, Len, List) :-
    length(List, Len),
    maplist(random(0, Limit), List).