对其他计算器使用递归结果时递归到迭代

时间:2018-04-09 15:12:12

标签: java loops recursion stack iteration

理论上应该可以将每个递归方法写入迭代方法。

我知道递归函数是尾递归的时候很容易。例如,计算阶乘可以像这样递归:

// Recursive:
long fact(long n){
  return fact(n, 1);
}
long fact(long n, long r){
  return n==1 ?
    r
   :
    fact(n-1, r*n);
}

Try it online.

或者喜欢这个迭代:

// Iterative:
int fact(int n){
  int r = 1;
  for(; n>1; n--)
    r *= n;
  return r;
}

Try it online.

这很简单,因为我们不会将递归方法的结果用于其他内容,而且我们只有一个递归调用,我们将n减少1次迭代。

我也知道你应该为大多数递归迭代转换保留一个堆栈。例如,快速排序可以像这个递归一样完成:

// Recursive:
void quicksort(int[] array, int left, int right){
  if(left >= right) return;
  int index = partition(array, left, right);
  quicksort(array, left, index-1);
  quicksort(array, index+1, right);
}

Try it online.

或者喜欢这个迭代:

// Iterative:
void quicksort(int[] array, int left, int right){
  int[] stack = new int[1024]; // Example size, alternative an actual java.util.Stack could be used
  int i=0;
  stack[i++] = left;
  stack[i++] = right;

  while(i>0){
    right = stack[--i];
    left = stack[--i];
    if(left >= right) continue;
    int index = partition(array, left, right);
    stack[i++] = left;
    stack[i++] = index-1;
    stack[i++] = index+1;
    stack[i++] = right;
  }
}

Try it online.

但我现在想将以下递归方法转换为迭代形式:

// Recursive:
int f(int n){
  return n<1 ?
    0
   :
    n%2+1 + 3*f(n/2);
}

Try it online.

在这种情况下,它使用递归结果,并将结果乘以3.我不完全确定如何进行此迭代。我试过这样的事情:

// Iterative:
int f(int n){
  int[] stack = new int[1024]; // Example size, alternative an actual java.util.Stack could be used
  int i=0;
  stack[i++] = n;
  while(i > 0){
    n = stack[--i];
    if(n < 1)
      stack[i++] = 0;
    stack[i++] = n%2+1 + 3*stack[--i];
  }
  return stack[0];
}

显然它不起作用,因为i=1在进入while之前,它在n = stack[--i]变为0,然后在stack[i++] = n%2+1 + ...变为1,然后0再次出现在3*stack[--i],因此它在第一次迭代后停止,只返回stack[0]。当我使用递归调用的结果和其他计算(在这种情况下乘以3)时,我应该如何将上面的递归方法转换为迭代方法?

至于原因:我想将上面的这个递归方法移植到一个没有任何功能的基于堆栈的语言,因此我需要迭代方法(带堆栈)。

2 个答案:

答案 0 :(得分:1)

好的,我已经弄清楚了。我首先需要用n%2+1部分填充整个堆栈,每次迭代除以2。一旦n < 1,我需要一个内循环来计算结果。

以下是我最终的结果:

// Recursive:
int f(int n){ // i.e. n=2
  int[] stack = new int[1024]; // Example size, alternative an actual java.util.Stack could be used 
  int i=0;
  while(i >= 0){
    stack[i++] = n%2+1;
    n/=2;
    if(n < 1){
      while(i > 0){
        n = 3*n + stack[--i];
      }
      return n;
    }
  }
  return -1; // It should never come here, but the method need a return-statement
}

Try it online.

答案 1 :(得分:1)

我最后得到了一些类似的东西(仅在看到你的自我答案后)

int iterf(int n){

    //can also be implemented with an array. easier with list. 
    List<Integer> sum = new ArrayList<>();

    while (true) {
        if( n < 1 ) { //equivalent to if(n<1) return 0;
            sum.add(0);
            break;
        }
        //for each n, fill list with the fixed argument part: (n%2)+1
        sum.add((n%2)+1); 
        n=n/2;
    }

    //add to each list element 3 time the next element 
    //equivalent to 3*f(n/2);
    for(int i = sum.size()-2; i >=0; i--) {
        sum.set(i, sum.get(i) + (3*(sum.get(i+1))));
    }

    return sum.get(0);
}