2009-08-02 135 views
1

我有一些在其實現中使用遞歸的代碼。 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()也是。爲了簡單起見,我省略了各種參數和對象解引用(例如,運行是對象實例的一種方法,並且它需要一些參數)。

無論如何,我的問題是,我怎麼把它變成非遞歸的代碼?

等效的非遞歸代碼,在我看來是:

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必要時的情況之一。

+15

重新編寫代碼以適應探查器的弱點的想法是我最近遇到的最奇怪的之一。 – 2009-08-02 22:16:43

+2

我會將這種情況列入越來越多的'奇怪的東西,C#人做' 2009-08-02 22:23:22

+1

@Dirk - 我會說這是追求自由軟件,導致他走下了這條道路。 – ChrisF 2009-08-02 22:35:02

回答

2

我想你是在正確的軌道上!在這種情況下,我沒有看到使用goto的任何實際問題。代碼中發生的事情非常清楚,人們試圖避免直接跳躍的唯一原因是在閱讀別人的代碼時可能導致混淆。

如果你保持它的整齊結構,並且在其他函數中有大部分的實現代碼,這看起來完全合理。特別是因爲你只使用非遞歸代碼進行分析:)

祝你好運然而你最終會繼續!

2

我真的不能測試,但在我看來,您可以用

Z(); 
E(); 
continue; 

A(); 
continue; 

goto end_subroutine更換goto start_subroutine我不知道如果這是真的那麼好得多雖然:)