簡體   English   中英

如何消除這種類型的遞歸?

[英]How to eliminate this type of recursion?

這比簡單的左遞歸或尾調用遞歸要復雜一些。 所以我想知道如何消除這種遞歸。 正如您在下面看到的,我已經保留了自己的堆棧,因此 function 不需要參數或返回值。 但是,它仍在將自己調高(或調低)到某個水平,我想把它變成一個循環,但現在我已經為此撓頭了一段時間。

這是簡化的測試用例,用 printf("dostuff at level #n") 消息替換所有“真實邏輯”。 這是在 Go 但問題適用於大多數語言。 使用循環和 goto 是完全可以接受的(但我玩過這個並且它變得令人費解,失控並且看起來無法開始); 但是,應避免使用額外的輔助函數。 我想我應該把它變成某種簡單的 state 機器,但是……哪個? ;)

至於實用性,這是以每秒大約 2000 萬次的速度運行(堆棧深度可以在以后從 1 到 25 max 不等)。 這是維護我自己的堆棧必然比 function 調用堆棧更穩定/更快的情況。 (此 function 中沒有其他 function 調用,只有計算。)另外,沒有產生垃圾 = 沒有收集垃圾。

所以這里是:

func testRecursion () {
    var root *TMyTreeNode = makeSomeDeepTreeStructure()
    // rl: current recursion level
    // ml: max recursion level
    var rl, ml = 0, root.MaxDepth
    // node: "the stack"
    var node = make([]*TMyTreeNode, ml + 1)

    // the recursive and the non-recursive / iterative test functions:
    var walkNodeRec, walkNodeIt func ();

    walkNodeIt = func () {
        log.Panicf("YOUR ITERATIVE / NON-RECURSIVE IDEAS HERE")
    }

    walkNodeRec = func () {
        log.Printf("ENTER LEVEL %v", rl)
        if (node[rl].Level == ml) || (node[rl].ChildNodes == nil) {
            log.Printf("EXIT LEVEL %v", rl)
            return
        }
        log.Printf("PRE-STUFF LEVEL %v", rl)
        for i := 0; i < 3; i++ {
            switch i {
            case 0:
                log.Printf("PRECASE %v.%v", rl, i)
                node[rl + 1] = node[rl].ChildNodes[rl + i]; rl++; walkNodeRec(); rl--
                log.Printf("POSTCASE %v.%v", rl,  i)
            case 1:
                log.Printf("PRECASE %v.%v", rl, i)
                node[rl + 1] = node[rl].ChildNodes[rl + i]; rl++; walkNodeRec(); rl--
                log.Printf("POSTCASE %v.%v", rl,  i)
            case 2:
                log.Printf("PRECASE %v.%v", rl, i)
                node[rl + 1] = node[rl].ChildNodes[rl + i]; rl++; walkNodeRec(); rl--
                log.Printf("POSTCASE %v.%v", rl,  i)
            }
        }
    }

    // test recursion for reference:
    if true {
        rl, node[0] = 0, root
        log.Printf("\n\n=========>RECURSIVE ML=%v:", ml)
        walkNodeRec()
    }

    // test non-recursion, output should be identical
    if true {
        rl, node[0] = 0, root
        log.Printf("\n\n=========>ITERATIVE ML=%v:", ml)
        walkNodeIt()
    }

}

更新——經過這里的一些討論,並進一步思考:

我剛剛編寫了以下偽代碼,理論上應該可以滿足我的需要:

curLevel = 0
for {
    cn = nextsibling(curLevel, coords)
    lastnode[curlevel] = cn
    if cn < 8 {
        if isleaf {
            process()
        } else {
            curLevel++
        }
    } else if curLevel == 0 {
        break
    } else {
        curLevel--
    }
}

當然,棘手的部分是為我的自定義用例填寫 nextsibling() 。 但是,作為在保持我需要的深度優先遍歷順序的同時消除內部遞歸的通用解決方案,這個粗略的大綱應該以某種形式實現。

我不太確定我明白你想做什么,因為你的遞歸代碼看起來有點奇怪。 但是,如果我了解您的 TMyTreeNode 的結構,那么這就是我對非遞歸版本所做的。

// root is our root node
q := []*TMyTreeNode{root}
processed := make(map[*TMyTreeNode]bool
for {
  l := len(q)
  if l < 1 {
    break // our queue is empty
  }
  curr := q[l - 1]
  if !processed[curr] && len(curr.childNodes) > 0 {
    // do something with curr
    processed[curr] = true
    q = append(q, curr.childNodes...)
    continue // continue on down the tree.
  } else {
    // do something with curr
    processed[curr] = true
    q := q[:l-2] // pop current off the queue
  }
}

注意:這將 go 任意深入到結構中。 如果這不是您想要的,則需要進行一些修改。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM