java 循环替代递归_请问循环能代替所有递归吗?

当然能。

所谓递归无非就是函数(直接或间接)调用自己,所以我们先看一下简单的函数调用。

假设有一个函数长这样:

int foo() {

int X = 4

int Y = bar(14);

return X*Y;

}

你可以把它变成这样:

int foo() {

foo_stack_frame = gcalloc { X: int; Y: int }

foo_stack_frame->X = 4;

foo_stack_frame->Y = bar(14);

return foo_stack_frame->X * foo_stack_frame->Y;

}

其中gcalloc就是指从GC heap上分配一个什么东西,这里分配的是一个map,用于保存foo的stack frame。

然后,foo可以变成这样:

int foo(continuation C) {

foo_stack_frame = gcalloc { C: continuation; X: int; Y: int }

foo_stack_frame->C = C;

foo_stack_frame->X = 4;

continuation Next = { foo2, foo_stack_frame };

return bar(Next, 14);

}

int foo2(continuation C, int Y) {

foo_stack_frame = C->stack_frame;

foo_stack_frame->Y = Y;

continuation Next = foo_stack_frame->C;

return Next->F(Next, foo_stack_frame->X * foo_stack_frame->Y);

}

这里的continuation你可以认为就是一个“返回地址”,这个等下再说。

你很可能会问,这么一大堆变换到底是在干神马?

嗯,其实这一堆就只变换干了一件事,那就是——把所有的函数调用变成了tail call。

大家都知道,tail call是可以直接优化成goto的,所以我们必须记录下原本的返回地址,把它传递给被tail call的函数,这样它就可以在结束的时候直接返回到最初的调用者那里。

如果对每个函数都做这样的变换,让每个函数调用都是tail call,那我们就彻底干掉了stack,整个程序只用goto就搞定。

PS. 对上面内容有兴趣的童鞋可以去看看 http://en.wikipedia.org/wiki/Continuation-passing_style

PPS. 其实从“理解”这个角度而言,递归往往更容易更清晰,因为它天生就是一个把高复杂度问题分解为低复杂度的过程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值