尾递归合并算法

时间:2014-11-23 09:50:09

标签: erlang mergesort tail-recursion

我实现了递归mergesort算法:

-module(ms).
-import(lists,[sublist/3,delete/2,min/1,reverse/1]).
-export([mergesort/1]).

mergesort([])->
    [];
mergesort([N])->
    N;
mergesort(L)->
    mergesort(split(1,L),split(2,L),[]).

mergesort(L1,L2,[])->
    case {sorted(L1),sorted(L2)} of
    {true,true}->
        merge(L1,L2,[]);
    {true,false}->
        merge(L1,mergesort(split(1,L2),split(2,L2),[]),[]);
    {false,true}->
        merge(mergesort(split(1,L1),split(2,L1),[]),L2,[]);
    {false,false}->
        merge(mergesort(split(1,L1),split(2,L1),[]),mergesort(split(1,L2),split(2,L2),[]),[])
    end.

merge([],[],R)->
    reverse(R);
merge(L,[],R)->
    merge(delete(min(L),L),[],[min(L)|R]);
merge([],L,R)->
    merge([],delete(min(L),L),[min(L)|R]);
merge([H1|T1],[H2|T2],R) when H1 < H2 ->
    merge(T1,[H2|T2],[H1|R]);
merge([H1|T1],[H2|T2],R) when H1 >= H2 ->
    merge([H1|T1],T2,[H2|R]).


split(1,L)->
    sublist(L,1,ceiling(length(L)/2));
split(2,L)->
    sublist(L,ceiling(length(L)/2+1),length(L)).

ceiling(X) when X < 0 ->    
    trunc(X);
ceiling(X) ->    
    T = trunc(X),
    case X - T == 0 of
        true -> T;
        false -> T + 1
    end.

但是我对mergesort/3不是尾递归(TR)这一事实感到厌烦,而且很冗长。

我想这里的问题是我并不是特别注意TR&#39;模板&#39;我将在这里使用 - 我理解我将如何实现一个TR函数,例如可以用一个系列来定义 - 只是将参数移动到系列中的函数,但是对于我们合并一个的情况子列表有条件地对列表其余部分的自然递归,我是无知的。

因此,我想问一下:

1)我怎样才能mergesort/3 TR?

2)我可以使用哪些资源来深入理解erlang尾递归?

1 个答案:

答案 0 :(得分:2)

你的merge-sort不是尾递归的,因为mergesort / 3中调用的最后一个函数是merge / 3。你将mergesort称为merge的参数,因此堆栈必须增长 - 上层称为mergesort / 3尚未完成,其堆栈帧不能被重用。 要用TR方法编写它,你需要尽可能地考虑它。每个TR函数都可以轻松地重写为迭代循环。考虑:

loop(Arg) ->
    NewArg = something_happens_to(Arg),
    loop(NewArg) or return NewArg.

data = something;
while(1){
    ...
    break loop or modify data block
    ...
} // data equals to NewArg at the end of iteration

这是我的TR合并排序示例。它是自下而上的思维方式。我在你的模块中使用了merge / 3函数。

ms(L) ->
    ms_iteration([[N] || N <- L], []).

ms_iteration([], []) -> % nothing to do
    [];
ms_iteration([], [OneSortedList]) -> % nothing left to do
    OneSortedList;
ms_iteration([], MergedLists) ->
    ms_iteration(MergedLists, []); % next merging iteration
ms_iteration([L], MergedLists) -> % can't be merged yet but it's sorted
    ms_iteration([], [L | MergedLists]);
ms_iteration([L1, L2 | ToMergeTail], MergedLists) -> % merging two sorted lists
    ms_iteration(ToMergeTail, [merge(L1, L2, []) | MergedLists]).

这里很好地解释了:http://learnyousomeerlang.com/recursion