一些伪代码:
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以下。
如何将其更改为迭代?
答案 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。