日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

如何用堆栈和循环结构代替递归调用--递归转换为非递归的10条军规

發(fā)布時(shí)間:2024/10/12 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何用堆栈和循环结构代替递归调用--递归转换为非递归的10条军规 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

10 Rules (steps) for replacing the recursive function with stack and while-loop

轉(zhuǎn)自http://www.codeproject.com/Articles/418776/How-to-replace-recursive-functions-using-stack-and??

First rule

  • 定義一個(gè)新的數(shù)據(jù)結(jié)構(gòu)"Snapshot".他的作用是保存隊(duì)規(guī)過(guò)程中的中間值數(shù)據(jù)和狀態(tài)信息。
  • ?"Snapshot" 結(jié)構(gòu)中包含:
  • 遞歸函數(shù)的參數(shù),但是,如果遞歸函數(shù)的參數(shù)是引用類(lèi)型的參數(shù),則無(wú)需放到Snapshot?中. 因此, 實(shí)例如下, 參數(shù)n?應(yīng)該放在Snapshot?中,而引用類(lèi)型的參數(shù)?retVal?不放Snapshot?中.
    • void SomeFunc(int n, int &retVal);
  • 遞歸的條件分類(lèi)值 "Stage"? (通常是一個(gè)int?值,可以放在 switch語(yǔ)句中,分別處理不同的情況)
    • 細(xì)節(jié)參照第六條sixth rule.
  • 存儲(chǔ)函數(shù)返回值的局部變量
  • ? // Recursive Function "First rule" example int SomeFunc(int n, int &retIdx) {...if(n>0){int test = SomeFunc(n-1, retIdx);test--;...return test; } ... return 0; } ? // Conversion to Iterative Function int SomeFuncLoop(int n, int &retIdx) { // (First rule) struct SnapShotStruct { int n; // - parameter input int test; // - local variable that will be used // after returning from the function call// - retIdx can be ignored since it is a reference. int stage; // - Since there is process needed to be done // after recursive call. (Sixth rule) }; ... }

    Second rule

  • 在函數(shù)頂層創(chuàng)建一個(gè)局部變量,用于存儲(chǔ)最終結(jié)果(遞歸函數(shù)的返回值retVal = currentSnapshot.test)。
  • 在迭代過(guò)程中,它象一個(gè)臨時(shí)變量保存每一次遞歸調(diào)用的返回值.
  • 如果遞歸函數(shù)返回類(lèi)型是空void, 忽略此步.
  • 如果有默認(rèn)的返回值,用默認(rèn)值初始化這個(gè)局部變量。
  • ? // Recursive Function "Second rule" example int SomeFunc(int n, int &retIdx) {...if(n>0) { int test = SomeFunc(n-1, retIdx); test--; ... return test; } ... return 0; } ? // Conversion to Iterative Function int SomeFuncLoop(int n, int &retIdx) {// (First rule) struct SnapShotStruct { int n; // - parameter input int test; // - local variable that will be used // after returning from the function call // - retIdx can be ignored since it is a reference.// (Second rule返回值retVal = currentSnapshot.test)
    int stage; // - Since there is process needed to be done // after recursive call. (Sixth rule) }; // (Second rule) int retVal = 0; // initialize with default returning value ... // (Second rule) return retVal; }

    Third rule

  • 建一個(gè)"Snapshot" 類(lèi)型的堆棧.
  • ? // Recursive Function "Third rule" example// Conversion to Iterative Function int SomeFuncLoop(int n, int &retIdx) { // (First rule) struct SnapShotStruct { int n; // - parameter input int test; // - local variable that will be used // after returning from the function call // - retIdx can be ignored since it is a reference. int stage; // - Since there is process needed to be done // after recursive call. (Sixth rule) }; // (Second rule) int retVal = 0; // initialize with default returning value // (Third rule) stack<SnapShotStruct> snapshotStack; ... // (Second rule) return retVal; }

    Fourth rule

  • 創(chuàng)建 "Snapshot" 實(shí)例,并初始化輸入到迭代中的參數(shù)和遞歸條件分類(lèi)的初始值"Stage" .
  • Snapshot實(shí)例壓棧stack.
  • ? // Recursive Function "Fourth rule" example// Conversion to Iterative Function int SomeFuncLoop(int n, int &retIdx) { // (First rule) struct SnapShotStruct { int n; // - parameter input int test; // - local variable that will be used // after returning from the function call // - retIdx can be ignored since it is a reference. int stage; // - Since there is process needed to be done // after recursive call. (Sixth rule) }; // (Second rule) int retVal = 0; // initialize with default returning value // (Third rule) stack<SnapShotStruct> snapshotStack; // (Fourth rule) SnapShotStruct currentSnapshot; currentSnapshot.n= n; // set the value as parameter value currentSnapshot.test=0; // set the value as default value currentSnapshot.stage=0; // set the value as initial stage snapshotStack.push(currentSnapshot); ... // (Second rule) return retVal; }

    Fifth rule

  • 建一個(gè)?while循環(huán),當(dāng) 堆棧stack 不空時(shí)執(zhí)行循環(huán)。
  • while?循環(huán)的每次迭代中, pop?出棧一個(gè)?Snapshot?對(duì)象;
  • ? // Recursive Function "Fifth rule" example// Conversion to Iterative Function int SomeFuncLoop(int n, int &retIdx) { // (First rule) struct SnapShotStruct { int n; // - parameter input int test; // - local variable that will be used // after returning from the function call // - retIdx can be ignored since it is a reference. int stage; // - Since there is process needed to be done // after recursive call. (Sixth rule) }; // (Second rule) int retVal = 0; // initialize with default returning value // (Third rule) stack<SnapShotStruct> snapshotStack; // (Fourth rule) SnapShotStruct currentSnapshot; currentSnapshot.n= n; // set the value as parameter value currentSnapshot.test=0; // set the value as default value currentSnapshot.stage=0; // set the value as initial stage snapshotStack.push(currentSnapshot); // (Fifth rule) while(!snapshotStack.empty()) { currentSnapshot=snapshotStack.top(); snapshotStack.pop(); ... } // (Second rule) return retVal; }

    Sixth rule遞歸條件分類(lèi)處理

  • 分2步處理 stages 。第一步對(duì)在當(dāng)前遞歸函數(shù)調(diào)用之前的處理,第二步是在當(dāng)前遞歸函數(shù)調(diào)用之后對(duì)返回值進(jìn)行一些運(yùn)算。
  • 如果遞歸過(guò)程要調(diào)用2個(gè)函數(shù), 就要對(duì)stages分3步處理:
  • ** (Stage 1 --> recursive call --> (returned from first recursive call) Stage 2 (recursive call within stage 1)--> (return from second recursive call) Stage 3
  • 如果有3個(gè)不同的遞歸調(diào)用,至少分4步驟處理 stages.
  • 以此類(lèi)推.
  • ? // Recursive Function "Sixth rule" example int SomeFunc(int n, int &retIdx) {...if(n>0) { int test = SomeFunc(n-1, retIdx); test--; ... return test; } ... return 0; } ? // Conversion to Iterative Function int SomeFuncLoop(int n, int &retIdx) {// (First rule) struct SnapShotStruct { int n; // - parameter input int test; // - local variable that will be used // after returning from the function call // - retIdx can be ignored since it is a reference. int stage; // - Since there is process needed to be done // after recursive call. (Sixth rule) }; // (Second rule) int retVal = 0; // initialize with default returning value // (Third rule) stack<SnapShotStruct> snapshotStack; // (Fourth rule) SnapShotStruct currentSnapshot; currentSnapshot.n= n; // set the value as parameter value currentSnapshot.test=0; // set the value as default value currentSnapshot.stage=0; // set the value as initial stage snapshotStack.push(currentSnapshot); // (Fifth rule) while(!snapshotStack.empty()) { currentSnapshot=snapshotStack.top(); snapshotStack.pop(); // (Sixth rule) switch( currentSnapshot.stage) { case 0: ... // before ( SomeFunc(n-1, retIdx); ) break; case 1: ... // after ( SomeFunc(n-1, retIdx); ) break; } } // (Second rule) return retVal; }

    Seventh rule

  • 根據(jù)不同的Switch 處理不同的Stage?
  • 做相關(guān)的處理
  • ? // Recursive Function "Seventh rule" example int SomeFunc(int n, int &retIdx) {... if(n>0) {int test = SomeFunc(n-1, retIdx); test--; ... return test; } ... return 0; } ? // Conversion to Iterative Function int SomeFuncLoop(int n, int &retIdx) {// (First rule) struct SnapShotStruct { int n; // - parameter input int test; // - local variable that will be used // after returning from the function call // - retIdx can be ignored since it is a reference. int stage; // - Since there is process needed to be done // after recursive call. (Sixth rule) }; // (Second rule) int retVal = 0; // initialize with default returning value // (Third rule) stack<SnapShotStruct> snapshotStack; // (Fourth rule) SnapShotStruct currentSnapshot; currentSnapshot.n= n; // set the value as parameter value currentSnapshot.test=0; // set the value as default value currentSnapshot.stage=0; // set the value as initial stage snapshotStack.push(currentSnapshot); // (Fifth rule) while(!snapshotStack.empty()) { currentSnapshot=snapshotStack.top(); snapshotStack.pop(); // (Sixth rule) switch( currentSnapshot.stage) { case 0: // (Seventh rule) if( currentSnapshot.n>0 ) { ... } ... break; case 1: // (Seventh rule) currentSnapshot.test = retVal; currentSnapshot.test--; ... break; } } // (Second rule) return retVal; }

    Eighth rule

  • 如果遞歸函數(shù)有返回值,在每次循環(huán)迭代時(shí),保存返回值到局部變量 (如 retVal?).
  • 這個(gè)局部變量retVal?就是循環(huán)結(jié)束后,遞歸的最終值.
  • ? // Recursive Function "Eighth rule" example int SomeFunc(int n, int &retIdx) {...if(n>0) { int test = SomeFunc(n-1, retIdx); test--; ... return test; } ... return 0; } ? // Conversion to Iterative Function int SomeFuncLoop(int n, int &retIdx) {// (First rule) struct SnapShotStruct { int n; // - parameter input int test; // - local variable that will be used // after returning from the function call // - retIdx can be ignored since it is a reference. int stage; // - Since there is process needed to be done // after recursive call. (Sixth rule) }; // (Second rule) int retVal = 0; // initialize with default returning value // (Third rule) stack<SnapShotStruct> snapshotStack; // (Fourth rule) SnapShotStruct currentSnapshot; currentSnapshot.n= n; // set the value as parameter value currentSnapshot.test=0; // set the value as default value currentSnapshot.stage=0; // set the value as initial stage snapshotStack.push(currentSnapshot); // (Fifth rule) while(!snapshotStack.empty()) { currentSnapshot=snapshotStack.top(); snapshotStack.pop(); // (Sixth rule) switch( currentSnapshot.stage) { case 0: // (Seventh rule) if( currentSnapshot.n>0 ) { ... } ... // (Eighth rule) retVal = 0 ; ... break; case 1: // (Seventh rule) currentSnapshot.test = retVal; currentSnapshot.test--; ... // (Eighth rule) retVal = currentSnapshot.test; ... break; } } // (Second rule) return retVal; }

    Ninth rule

  • 如果遞歸含有返回值,把原來(lái)遞歸函數(shù)中的關(guān)鍵字 "return" 替換成"while"循環(huán)中的關(guān)鍵字 "continue"。
    • 如果遞歸函數(shù)有返回值,如 "Eighth rule,"所述,把返回值保存到局部變量中 (如?retVal), 然后"continue"繼續(xù)循環(huán);
    • 多數(shù)情況下, "Ninth rule" 是可選的,但他有助于避免邏輯錯(cuò)誤.
    ? // Recursive Function "Ninth rule" example int SomeFunc(int n, int &retIdx) {...if(n>0) { int test = SomeFunc(n-1, retIdx); test--; ... return test; } ... return 0; } ? // Conversion to Iterative Function int SomeFuncLoop(int n, int &retIdx) {// (First rule) struct SnapShotStruct { int n; // - parameter input int test; // - local variable that will be used // after returning from the function call // - retIdx can be ignored since it is a reference. int stage; // - Since there is process needed to be done // after recursive call. (Sixth rule) }; // (Second rule) int retVal = 0; // initialize with default returning value // (Third rule) stack<SnapShotStruct> snapshotStack; // (Fourth rule) SnapShotStruct currentSnapshot; currentSnapshot.n= n; // set the value as parameter value currentSnapshot.test=0; // set the value as default value currentSnapshot.stage=0; // set the value as initial stage snapshotStack.push(currentSnapshot); // (Fifth rule) while(!snapshotStack.empty()) { currentSnapshot=snapshotStack.top(); snapshotStack.pop(); // (Sixth rule) switch( currentSnapshot.stage) { case 0: // (Seventh rule) if( currentSnapshot.n>0 ) { ... } ... // (Eighth rule) retVal = 0 ; // (Ninth rule) continue; break; case 1: // (Seventh rule) currentSnapshot.test = retVal; currentSnapshot.test--; ... // (Eighth rule) retVal = currentSnapshot.test; // (Ninth rule) continue; break; } } // (Second rule) return retVal; }

    Tenth rule (and the last...)

  • 為了實(shí)現(xiàn)從遞歸調(diào)用到迭代函數(shù)的轉(zhuǎn)換,在每次迭代中,創(chuàng)建一個(gè)新的? "Snapshot" 對(duì)象, 初始化 這個(gè)新的"Snapshot" 對(duì)象和遞歸條件分類(lèi) stage, 依據(jù)遞歸函數(shù)的參數(shù)設(shè)置他的成員變量,壓棧, 然后繼續(xù) "continue"
  • 如果遞歸函數(shù)調(diào)用之后,有其他處理過(guò)程,就需要調(diào)整當(dāng)前"currentSnapshot"中保持的遞歸條件分類(lèi) stage ,并把當(dāng)前"Snapshot"壓棧,然后再對(duì)新建的"Snapshot"壓棧。
  • ? // Recursive Function "Tenth rule" example int SomeFunc(int n, int &retIdx) {...if(n>0) { int test = SomeFunc(n-1, retIdx); test--; ... return test; } ... return 0; } ? // Conversion to Iterative Function int SomeFuncLoop(int n, int &retIdx) {// (First rule) struct SnapShotStruct { int n; // - parameter input int test; // - local variable that will be used // after returning from the function call // - retIdx can be ignored since it is a reference. int stage; // - Since there is process needed to be done // after recursive call. (Sixth rule) }; // (Second rule) int retVal = 0; // initialize with default returning value // (Third rule) stack<SnapShotStruct> snapshotStack; // (Fourth rule) SnapShotStruct currentSnapshot; currentSnapshot.n= n; // set the value as parameter value currentSnapshot.test=0; // set the value as default value currentSnapshot.stage=0; // set the value as initial stage snapshotStack.push(currentSnapshot); // (Fifth rule) while(!snapshotStack.empty()) { currentSnapshot=snapshotStack.top(); snapshotStack.pop(); // (Sixth rule) switch( currentSnapshot.stage) { case 0: // (Seventh rule) if( currentSnapshot.n>0 ) { // (Tenth rule) currentSnapshot.stage = 1; // - current snapshot need to process after// returning from the recursive call snapshotStack.push(currentSnapshot); // - this MUST pushed into stack before // new snapshot! // Create a new snapshot for calling itself SnapShotStruct newSnapshot; newSnapshot.n= currentSnapshot.n-1; // - give parameter as parameter given // when calling itself // ( SomeFunc(n-1, retIdx) ) newSnapshot.test=0; // - set the value as initial value newSnapshot.stage=0; // - since it will start from the // beginning of the function, // give the initial stage snapshotStack.push(newSnapshot); continue; } ... // (Eighth rule) retVal = 0 ; // (Ninth rule) continue; break; case 1: // (Seventh rule) currentSnapshot.test = retVal; currentSnapshot.test--; ... // (Eighth rule) retVal = currentSnapshot.test; // (Ninth rule) continue; break; } } // (Second rule) return retVal; }

    Simple Examples by types of recursion??

    • Please download?RecursiveToLoopSamples.zip
    • Unzip the file.
    • Open the project with Visual Studio.
      • This project has been developed with Visual Studio 2008
    • Sample project contains
      • Linear Recursion Example
      • Binary Recursion Example
      • Tail Recursion Example
      • Mutual Recursion Example
      • Nested Recursion Example

    More Practical Example Sources??

    The below sources contain both a recursive version and a simulated version, where the simulated version has been derived using the above methodology.?

    • epQuickSort.h
    • epMergeSort.h
    • epKAryHeap.h
    • epPatriciaTree.h

    Why do the sources contain both the simulated version and the recursive version???

    If you look at the source, you can easily notice the simulated versions look much more complex than the recursive versions.?For those who don't know what the function does, it will be much harder to figure out what the function with the loop actually does.?So I prefer to keep both versions, so people can easily test out simple inputs and outputs with the recursive version, and for huge operations, use simulated version to avoid stack overflow.?

    Conclusion???

    My belief is that when writing C/C++ or Java code, the recursive functions MUST be used with care to avoid the stack-overflow error. However as you can see from the examples, in many cases, the recursive functions are easy to understand, and easy to write with the downside of "if the recursive function call's depth goes too deep, it leads to stack-overflow error". So conversion from recursive function to?simulated function is not for increasing readability nor increasing algorithmic performance, but it is simple way of evading the crashes or undefined behaviors/errors. As I stated above, I prefer to keep both recursive version and?simulated version in my code, so I can use the recursive version for readability and?maintenance of the code, and the simulated version for running and testing the code.??It will be your choice how to write your code as long as you know the pros and cons?for the choice, you are making.??

    Reference???

    • http://www.dreamincode.net/forums/topic/51296-types-of-recursion/
    • EpLibrary 2.0?

    History??

    • 07.02.2015:- Broken link fixed
    • 09.06.2013:- Typo fixed (Thanks to ?lovewubo)?
    • 08.22.2013:- ?Re-distributed under MIT License from GPL v3?
    • 08.10.2012: - Table of contents updated?
    • 08.04.2012: - Moved the article's subsection to "Howto"?
    • 07.23.2012: - Minor fixes on the article??
    • 07.13.2012: - Table of contents modified?
      • Sections removed
      • Moved the article to Beginner section?
      • Changed the wording?
    • 07.13.2012: - Table of contents added.
      • Titles modified.
      • New sections added.
        • Difference between Recursive and Iterative function
        • Pros and Cons of Recursive and Iterative approach
    • 07.12.2012: - Sample bugs fixed.
      • Article re-organized.
      • Ninth and Tenth rule added.
      • Examples for each rule added.
    • 07.11.2012: - Submitted the article.

    License

    This article, along with any associated source code and files, is licensed under?The MIT License

    轉(zhuǎn)載于:https://www.cnblogs.com/baiyu/p/4625848.html

    總結(jié)

    以上是生活随笔為你收集整理的如何用堆栈和循环结构代替递归调用--递归转换为非递归的10条军规的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 午夜影视av | 亚洲日本一区二区三区 | 亚洲福利电影 | 黄黄的视频在线观看 | 欧美熟妇7777一区二区 | 在办公室被c到呻吟的动态图 | 国家队动漫免费观看在线观看晨光 | 欧美日韩国产黄色 | 久久中文在线 | 亚洲免费视频一区二区三区 | 中文字幕在线观看一区 | 国产又粗又黄又爽又硬 | av黄色免费观看 | 毛片内射久久久一区 | 黄色免费入口 | 国产乱free国语对白 | 国产网红av | 麻豆国产一区二区 | 亚洲av永久无码精品三区在线 | 草草影院第一页yycc.com | 免费的黄色的视频 | 久久久久亚洲av成人网人人软件 | 精品久久ai| 香港黄色网 | 国产精品美女www爽爽爽 | 中文字幕五码 | 亚洲人精品午夜射精日韩 | 久久国产影院 | 97在线视频免费观看 | 亚洲欧美日韩精品一区 | 美景之屋电影免费高清完整韩剧 | 中文字幕乱码一区二区三区 | 毛毛毛片 | 熟女av一区二区 | 欧美中文字幕在线视频 | 免费观看高清在线 | 福利av在线 | 超碰干 | 半推半就一ⅹ99av | 国产精品扒开腿做爽爽爽a片唱戏 | 天降女子| 亚洲一区视频在线播放 | 尤物精品视频 | 成人aaaa| 亚洲一区二区观看播放 | 少妇人妻邻居 | 在线观看av的网址 | 操视频网站 | 自拍偷拍第一页 | 亚洲清纯国产 | 你懂的视频网站 | 超碰免费在线 | 成人黄色免费网址 | 亚洲无码久久久久久久 | 8050午夜一级毛片久久亚洲欧 | 国产精品毛片一区二区三区 | 国产一区二区99 | v片在线看| 成人精品毛片 | 污污的网站在线观看 | 日本视频免费观看 | 97精品人妻一区二区三区香蕉 | 岛国av电影在线观看 | 色综合天天综合 | 成人黄色在线免费观看 | 国产精品对白 | 日韩一级片免费在线观看 | 韩国伦理片在线观看 | 欧美激情二区三区 | 欧美激情久久久 | 精品国产一二 | 人人爱人人插 | 高清在线一区二区 | 国产无遮挡a片又黄又爽 | 五月婷婷网站 | 在线免费观看一区二区三区 | 欧美精品一区二区免费看 | 加勒比综合| 欧美成人免费一级 | 激情五月在线观看 | 爱搞逼综合 | 捆绑无遮挡打光屁股调教女仆 | 亚洲精品成av人片天堂无码 | 亚洲三区视频 | 国产在线999| 欧美激情成人网 | 在线观看黄色网 | 国产三级中文字幕 | 金鱼妻日剧免费观看完整版全集 | 特级西西人体444www高清 | 国产一区免费看 | 天堂网2020| 久久毛片| 免费日韩一区 | 婷婷在线免费 | 一级 黄 色 片69 | 最新中文字幕av专区 | 99视频网址 | 尹人综合在线 |