如何将java for循环转换为递归?

时间:2014-02-09 01:10:38

标签: java loops

我有三个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]);
             }
        }
    }

2 个答案:

答案 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] 对于某些“小”的值。看看你的筹码有多深!