在函数调用自身的意义上,它是递归的。然而,它有一个重要的属性,即调用的结果完全依赖于另一个函数调用的结果;不需要当前堆栈中的值。结果由
提供
return iterativeSum(--x, ++y);
不是来自类似的东西
return iterativeSum(--x, ++y) + x;
这需要从递归调用中“回来”,对结果做一些事情,然后返回。因为结果不需要当前堆栈帧中的任何内容,所以实现(在某些语言中,取决于语义)可以消除或重用当前堆栈帧。这称为 tail-call 消除,在某些语言(如 Scheme)中是强制要求的。这就是该算法的 Scheme 实现本质上是迭代的原因:它不需要无限量的堆栈空间。
在Scheme中,尾调用消除意味着实现本质上如下,其中iterativeSumDriver是一种蹦床,或者是iterativeSumInternal提供的结果的迭代驱动程序强>。
public class IterativeSummer {
/**
* Returns a sum, computed iteratively.
*
* @param x the augend
* @param y the addend
* @return the sum of the augend and addend
*/
public int iterativeSumDriver(int x, int y) {
int[] state = new int[] { x, y };
while (state.length == 2) {
state = iterativeSumInternal(state[0], state[1]);
}
return state[0];
}
/**
* Returns the new computation state of a iterative sum
* computation. If x is 0, then returns an array of just y.
* Otherwise, returns an an array of x-1 and y+1.
*
* @param x the augend
* @param y the addend
* @return the next interal state
*/
int[] iterativeSumInternal(int x, int y) {
if (x == 0) {
return new int[] { y };
}
else {
return new int[] { x-1, y+1 };
}
}
public static void main(String[] args) {
int x = 5;
int y = 6;
int sum = new IterativeSummer().iterativeSumDriver(x,y);
System.out.println(String.format("%d + %d = %d", x, y, sum));
}
}
合适的蹦床
正如Will Ness pointed out,一个合适的蹦床并不真正了解计算中使用的状态;它只需要有一些东西可以调用,直到一个不可调用的东西被返回。这是一个可以做到这一点的版本。
public class Trampoline {
/**
* State of a computation for a trampoline.
*
* @param <T> the type of value
*/
public interface TrampolineState<T> {
/**
* Returns whether the state is a finished state.
*
* @return whether the state is a finshed state
*/
boolean isFinished();
/**
* Returns the value, if this state is finished.
*
* @return the value
* @throws IllegalStateException if the state is not finished
*/
T getValue() throws IllegalStateException;
/**
* Returns the next state, if this state is not finished.
*
* @return the next state
* @throws IllegalStateException if the state is finished
*/
TrampolineState<T> getNext() throws IllegalStateException;
}
/**
* Executes a trampolined state and its successors until a finished state is
* reached, and then returns the value of the finished state.
*
* @param state the state
* @return the value
*/
public <T> T trampoline(TrampolineState<T> state) {
while (!state.isFinished()) {
state = state.getNext();
}
return state.getValue();
}
/**
* Returns the state for for sum computation.
*
* @param x the augend
* @param y the addend
* @return the state
*/
private TrampolineState<Integer> getSumTrampolineState(int x, int y) {
return new TrampolineState<Integer>() {
@Override
public boolean isFinished() {
return x == 0;
}
@Override
public Integer getValue() {
if (!isFinished()) {
throw new IllegalStateException();
}
return y;
}
@Override
public TrampolineState<Integer> getNext() {
if (isFinished()) {
throw new IllegalStateException();
}
return getSumTrampolineState(x - 1, y + 1);
}
};
}
/**
* Returns a sum, computed by a trampolined computation.
*
* @param x the augend
* @param y the addend
* @return the sum
*/
public int sum(int x, int y) {
return trampoline(getSumTrampolineState(x, y));
}
}
另见: