是否可以通过 java 的辅助函数保留信息,而不使用静态变量。
例如,
public void foo(){
int v = 0;
fooHelper(2);
}
public void fooHelper(int depth){
v++;
fooHelper(depth-1)
}
即我想更新变量 v 而不会丢失每个递归案例的信息,而不必访问函数外部的变量。
忘记所有告诉您声明属性或在每个递归调用中更新可变对象的答案。在真正的函数式递归样式中,您通过将信息作为参数和/或返回类型传递来“保留”信息。
让我用一个简单的例子来说明,假设你想递归地计算一个int[]
. 这里,状态(递归调用之间需要保留的信息)是数组中的当前索引和到目前为止的总和。这是如何做到的:
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()
.
在范围内声明的变量(例如方法)只能在此范围内访问(例如不能在另一个方法中)。
如果信息仅与方法相关,请将变量保留在方法中。如果信息与整个对象/类状态相关,请将其保留为类成员(静态/非静态)。
例如:
public void someRecursiveMethod(int num) {
while (num < 10) {
num++;
someRecursiveMethod(num);
System.out.println("Current num = " + num);
}
}
您可以创建一个新类 (yuck),或者将变量作为参数传递并在 fooHelper 中返回。
为什么不让它成为一个实例变量(不一定是静态的)......?
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();
}
}
您可以返回一个列表或类似的数据结构:
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;
}
因为变量 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;
}
希望能帮助到你。
您可以传递一个对象来存储每个递归调用的更新。类似于下面的那个。
public static void fooHelper(int depth, HashMap map){
map.put(depth, "Call " + depth);
if (depth > 0)
{
fooHelper(depth-1, map);
}
return;
}
我认为这被称为记忆。看起来像
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 它重复计算相同的值。使用递归+记忆,它永远不会计算任何值超过一次。
感谢@Aristide 指出记忆和记忆之间的细微差别。