我有三个for循环,我希望将它们变成递归方法,因为我想为任何数量的for循环执行此操作。我在网上搜索,但似乎没有人完全符合我的需要,例如这个人将递归转换为for循环 Turning a recursive function into a for loop? 代码:
int x = 3;
for (int i = 0; i < x; i++) {
for (int j = 0; j < x; j++) {
for (int k = 0; k < x; k++){
list.add(array[i] + array[j] + array[k]);
}
}
}
答案 0 :(得分:2)
将for
循环视为一个将循环索引值作为参数的小匿名函数。为了开始循环的下一次迭代,该函数可以使用循环索引参数的新值返回对自身的调用。
像这样:
Object loop(int i, Object data) {
if (i > 0) {
return loop(i - 1, evolve(data));
} else {
return data;
}
}
这与此相同:
for ( ; i > 0; i--) {
data = evolve(data);
}
在某些语言中,尤其是Scheme,谁知道可能是Java 8或9,编译器保证编译递归函数,例如函数loop
,就像它编译for
一样循环上面。
在其他语言中,包括Java的当前版本和过去版本,几乎所有编译器都会创建一个构建大调用堆栈的可执行文件。当调用堆栈很大时,它甚至可能溢出允许的大小并使程序崩溃。
答案 1 :(得分:2)
一边讨厌,让我们这样做! [1]
假设:
int x = 3;
for (int i = 0; i < x; i++) {
for (int j = 0; j < x; j++) {
for (int k = 0; k < x; k++){
list.add(array[i] + array[j] + array[k]);
}
}
}
让我们考虑每个循环是它自己的递归函数 - 因为这使得递归情况更容易!这也是我所知道的将循环转换为递归的唯一“非思维”方法。递归深度将限制为3*x => i+j+k
,因此对于小的 [2] x
来说,它“相当安全”。
在Java中,每个循环都需要一个单独的方法来编码这个结构。 (在具有高阶函数的语言中,这三个函数可能被抽象地组合在一起......但不是在Java [7]中。)
void loopI(int i) {
if (i < x) {
loopJ(0); // "start j loop"
loopI(i++); // "next i loop" / recurrence case
}
// "end loop" / base case
}
void loopJ(int j) {
if (j < x) {
loopK(0);
loopJ(j++);
}
}
void loopK(int k) {
if (k < x) {
list.add(array[i] + array[j] + array[k]);
loopK(k++);
}
}
// do it!
loopI(0);
所有这些都可以组合成一个递归函数,但这使得处理递归情况有点困难,因为“思考”并且需要额外的条件(或者可能是mod表达式)来推进国家。
以下是组合递归函数的示例(当x
为0时,这是不正确的)。与上面的三种方法不同,堆栈深度将增长到x^3 => i*j*k
。这个很容易杀死Java的递归限制 - 即使是x
的小值 - 因为Java [7] 没有拥有tail-call optimization。
void loop(int i, int j, int k) {
list.add(array[i] + array[j] + array[k]);
// advance states
k++;
if (k == x) { k = 0; j++; }
if (j == x) { j = 0; i++; }
if (i == x) { i = 0; }
// terminate on all wrap-around
if (i == 0 && j == 0 && k == 0) { return; }
// recurse
loop(i, j, k);
}
[1] YMMV,仅用于理论目的 - 我喜欢递归,但它不适合Java中的这种情况。
[2] 对于某些“小”的值。看看你的筹码有多深!