## 浅谈尾递归的优化方式

2009-04-01 01:00  Jeffrey Zhao  阅读(56585)  评论(41编辑  收藏  举报

# 尾递归的循环优化

int FactorialTailRecursion(int n, int acc)
{
if (n == 0) return acc;
return FactorialTailRecursion(n - 1, acc * n);
}


int FactorialLoopOptimized(int n, int acc)
{
while (true)
{
if (n == 0) return acc;

acc *= n;
n--;
}
}


int FactorialContinuation(int n, Func<int, int> continuation)
{
if (n == 0) return continuation(1);
return FactorialContinuation(n - 1, r => continuation(n * r));
}


Func<int, int> contn = r => r * n

Factorial(n)
= contn(contn - 1(...(cont2(cont1(cont0(1)))...))
= n * ((n – 1) * (...(2 * (1 * 1))...)) =
= n * (n - 1) * ... * 2 * 1
= n!

int FactorialLoopOptimized2(int n, Func<int, int> continuation)
{

while (true)
{
if (n == 0) break;

int tempN = n;
Func<int, int> newCont = r => tempN * r;

n--;
continuation = newCont;
}

return contList.Aggregate(1, (acc, cont) => cont(acc));
}


private class Continuation
{
public Continuation(Func<int, int> cont, int n)
{
this.cont = cont;
this.n = n;
}

private Func<int, int> cont;
private int n;

public int Invoke(int r)
{
return this.cont(this.n * r);
}
}

public static int FactorialLoopOptimized3(int n, Func<int, int> continuation)
{
while (true)
{
if (n == 0) break;
continuation = new Continuation(continuation, n).Invoke;
n--;
}

return continuation(1);
}


# 方法尾调用的优化

static int FactorialTailRecursion(int n, int acc)
{
if (n == 0) return acc;
return FactorialTailRecursion(n - 1, acc * n);
}


.method private hidebysig static int32 FactorialTailRecursion(int32 n, int32 acc) cil managed
{
.maxstack 8
L_0000: ldarg.0            // 加载第1个参数，即n
L_0001: brtrue.s L_0005    // 如果第一个参数不为0，则跳转到L_0005
L_0003: ldarg.1            // 运行到此，说明第1个参数为0，则加载第2个参数，即acc
L_0004: ret                // 返回（刚加载的第2个参数）
L_0005: ldarg.0            // 加载第1个参数，即n
L_0006: ldc.i4.1           // 加载数值1
L_0007: sub                // 将两者相减，即n - 1
L_0008: ldarg.1            // 加载第2个参数，即acc
L_0009: ldarg.0            // 加载第1个参数，即n
L_000a: mul                // 将两者相乘，即acc * n
// 把n - 1和acc * n作为参数递归调用
L_000b: call int32 TailRecursion.Recursion::FactorialTailRecursion(int32, int32)
L_0010: ret                // 返回递归调用结果
}


00ad00d0    push    ebp


.method private hidebysig static int32 FactorialTailRecursion(int32 n, int32 acc) cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: brtrue.s L_0005
L_0003: ldarg.1
L_0004: ret
L_0005: ldarg.0
L_0006: ldc.i4.1
L_0007: sub
L_0008: ldarg.1
L_0009: ldarg.0
L_000a: mul
L_000b: tail.
L_000c: call int32 TailRecursion.Recursion::FactorialTailRecursion(int32, int32)
L_0010: ret
}


00a600d0    push    ebp
00a600d1    mov     ebp,esp
00a600d3    push    edi
00a600d4    push    esi
00a600d5    push    ebx
00a600d6    mov     eax,ecx
00a600d8    mov     esi,edx
00a600da    test    eax,eax
00a600dc    jne     00a600e5
00a600de    mov     eax,esi
00a600e0    pop     ebx
00a600e1    pop     esi
00a600e2    pop     edi
00a600e3    pop     ebp
00a600e4    ret
00a600e5    lea     ecx,[eax-1]
00a600e8    imul    eax,esi
00a600eb    mov     edx,eax
00a600ed    mov     eax,dword ptr ds:[813068h]
00a600f3    push    0
00a600f5    push    0
00a600f7    push    1
00a600f9    push    eax
00a600fa    cmp     dword ptr [mscorwks!g_TrapReturningThreads (7204339c)],0
00a60101    je      00a6010c
00a60103    push    ecx
00a60104    push    edx
00a60105    call    mscorwks!JIT_PollGC (71d5c9d3)
00a6010a    pop     edx
00a6010b    pop     ecx
00a6010c    call    mscorwks!JIT_TailCall (71b02890)
00a60111    int     3