我有一些在其实现中使用递归的代码。 profiler which I'm using对递归函数调用效果不佳,所以我想把它重写为非递归函数。
目前的代码是这样的:
void Parse(Foo foo)
{
A()
for (;;)
{
B();
if (C())
return;
if (D())
{
Run();
}
E();
}
}
void Run()
{
X();
if (Y())
{
Parse();
}
Z();
}
以上是伪代码。字母A,B,C,D,E,X,Y和Z是方法,Parse()和Run()也是如此。为简单起见,我遗漏了各种参数和对象解引用(例如,Run是一个对象实例的方法,它需要一些参数)。
无论如何,我的问题是,如何将其转换为非递归代码?
在我看来,等效的非递归代码是:
void Parse(Foo foo)
{
//create a local stack variable to emulate recursion
Stack<Foo> foos = new Stack<Foo>();
foos.Add(foo());
start_subroutine:
A()
for (;;)
{
B();
if (C())
{
//instead of returning from a recursive call
if (foos.Count > 1)
{
foo = foos.Pop();
goto end_subroutine;
}
return;
}
if (D())
{
//instead of invoking Run as a subroutine, bring its functionality inline
//Run();
X();
if (Y())
{
//instead of calling self recursively
//Parse();
//push onto a local stack variable and jump
foos.Add(foo);
goto start_subroutine;
}
end_subroutine:
Z();
}
E();
}
}
我可以这样做,但我不知道如何不使用goto;而且我不记得曾经有人写过这是goto必要的情况之一。
答案 0 :(得分:2)
我认为你走在正确的轨道上!在这种情况下,我没有看到使用goto的任何实际问题。非常清楚代码中发生了什么,并且人们试图避免直接跳跃的唯一原因是它在阅读其他人的代码时会导致混淆。
如果你保持结构整齐,并将大部分实现代码放在其他函数中,这看起来完全合理。特别是因为您只使用非递归代码进行性能分析:)
祝你好运,但最终还是继续进行!
答案 1 :(得分:2)
我无法对此进行测试,但在我看来,您可以用
替换goto start_subroutine
A();
continue;
和goto end_subroutine
与
Z();
E();
continue;
我不确定这是否真的好多了:)