java在递归函数中保留信息

时间:2012-04-22 05:48:59

标签: java recursion

是否可以通过java的辅助函数保留信息,而不使用静态变量。

例如,

public void foo(){
    int v = 0;
    fooHelper(2);
}

public void fooHelper(int depth){
    v++;
    fooHelper(depth-1)
}

即我想更新变量v而不丢失每个递归情况的信息,而不必访问函数外的变量。

8 个答案:

答案 0 :(得分:24)

忘记告诉你声明属性的所有答案,或者在每次递归调用中更新可变对象。在真正的函数式递归样式中,您可以通过将其作为参数和/或返回类型传递来“保留”信息。

让我用一个简单的例子来说明,假设你想要递归地计算int[]中元素的总和。这里, state (需要在递归调用之间保留的信息)是数组中的当前索引和到目前为止的总和。这是如何做到的:

public int sum(int[] array) {
    return sum(array, 0, 0); 
}

private int sum(int[] array, int idx, int acc) {
    if (idx == array.length)
        return acc;
    return sum(array, idx+1, acc+array[idx]);
}

这样称呼:

int[] array = {1, 2, 3};
System.out.println(sum(array));

正如您所看到的,不需要声明(静态或实例)属性,也不需要传递和修改可变对象(列表,映射) - 我甚至不使用局部变量,因为需要所有必需的信息解决问题是作为方法参数出现的。

在您的问题的代码中,v变量应该执行acc参数在我的答案中所做的事情,即:每次调用递归时修改累计值。最后,您只需要从辅助函数(不能有void返回类型)返回累积值,这就是您在foo()中获取值的方式。

答案 1 :(得分:1)

在范围内声明的变量(例如方法)只能在此范围内访问(例如,不在其他方法中)。

如果信息仅与方法相关,请将变量保留在方法中。如果信息与整个对象/类状态相关,请将其保留为类成员(静态/非静态)。

例如:

public void someRecursiveMethod(int num) {
    while (num < 10) {
        num++;
        someRecursiveMethod(num);
        System.out.println("Current num = " + num);
    }
}

答案 2 :(得分:0)

你可以创建一个新类(yuck),或者将变量作为参数传递并在fooHelper中返回。

答案 3 :(得分:0)

为什么不把它变成一个实例变量(不一定是静态的)...... ??

public class Recursive {
    int v = 0;
    public void foo(){

        fooHelper(2);
        System.out.println(v);
    }

    public void fooHelper(int depth){
        v++;
        if(depth-1!=0)//Added this because I was getting an StackOverflowError
        fooHelper(depth-1);
    }

    public static void main(String[] args) {
        Recursive r = new Recursive();
        r.foo();
    }
}

答案 4 :(得分:0)

您可以返回列表或类似的数据结构:

public List<Integer> fooHelper( int v, int depth ){
    if( depth == 0 ) return new ArrayList();

    v++;
    List<Integer> result = fooHelper( v, depth-1 );

    result.add( new Integer(v) );

    return result;
}

答案 5 :(得分:0)

因为变量v是基本类型,所以对它做出的更改在函数范围之外是不可见的。您可以在类中声明变量v,比如State,并将状态对象传递给递归函数以获得所需的效果。

public void foo(){
    State state = new State();
    fooHelper(state, 2);
}

public void fooHelper(State state, int depth){
    state.v++;
    fooHelper(state, depth-1);
}

class State {
    int v;
}

希望它有所帮助。

答案 6 :(得分:0)

您可以传递一个对象来存储每个递归调用的更新。像下面那样的东西。

public static void fooHelper(int depth, HashMap map){
      map.put(depth, "Call " + depth);
      if (depth > 0)
      {
        fooHelper(depth-1, map);
      }
      return;
    }

答案 7 :(得分:0)

我认为这称为memoization。它看起来像

class Fibonacci
{
     public Map < Integer , Integer > memorized = new HashMap < > ( ) ;

     public int fib ( int n )
     {
           if ( memoized . containsKey ( n ) )
           {
                 return memoized . get ( n ) ;
           }
           else
           {
                 int fib = // calculate recursively
                 memoized . put ( n , fib ) ;
                 return fib ;
           }
     }
}

您应该能够从此算法中获得不错的(非最佳)性能。递归斐波纳契算法具有可怕性能的主要原因是b / c它重复计算相同的值。使用递归+ memoization,它永远不会多次计算任何值。

感谢@Aristide指出了记忆和记忆之间的细微差别。