将其从递归更改为迭代

时间:2013-04-22 15:20:51

标签: algorithm recursion iteration

一些伪代码:

 func F(int x. int y, array p){
       p[x] = 1;
       if (x<=y){
          for each item in getItems(x,p){
              p = F(item,y,p);
          }
       }
       return p;
    }

getItems()返回一个基于x和p的数字数组,并且对于这个问题并不重要,但是它会返回一些x和x之上和下方的数字。然而,这意味着如果x太大,那么我会炸掉递归堆栈,因为它会深深地挖掘到x以下。

如何将其更改为迭代?

2 个答案:

答案 0 :(得分:1)

您可以通过模拟调用堆栈来实现:

struct stackentry {
    int x;
    Item item; // see exercise for reader, below
};

func F(int x, int y, array p){
   dynamic_list_of_stackentry mystack;
  start:
   p[x] = 1;
   if (x<=y){
      for each item in getItems(x,p){
          mystack.push(stackentry(x, item));
          x = item
          goto start
        resume:
          x = mystack.top().x;
          item = mystack.top().item;
          mystack.pop();
      }
   }
   if mystack.size() > 0:
      goto resume
   return p;
}

作为练习留下:更改迭代,以便您可以存储作为堆栈条目的一部分的当前正在迭代的集合(来自getItems())以及您当前在其中的位置。

我并不是说这是优雅的代码,但你可以从非递归函数的起点重构,它与递归函数的作用相同。例如,您的下一步可能是:

func F(int x, int y, array p){
   dynamic_list_of_int mystack;
   mystack.push(x)
   while not mystack.empty() {
       x = mystack.top();
       mystack.pop();
       p[x] = 1;
       if (x <= y) {
           for each item in reversed(getItems(x,p)) {
               mystack.push(item);
           }
       }
   }
   return p;
}

答案 1 :(得分:0)

您可以通过添加一个防止双重处理x值的保护来保持递归版本(没有堆栈溢出)

func F(int x. int y, array p){
   if(p[x] != 1) {
       p[x] = 1;
       if (x<=y){
           for each item in getItems(x,p){
               p = F(item,y,p);
          }
       }
   }
   return p;
}

如果您的某些数组值可能已初始化为1,则将其更改为

if(p[x] != null) {
    p[x] = null;

即。指定一个您知道在初始数组中未使用的值。然后,当函数完成其处理时,遍历数组并将所有空值设置为1。