研究了一天的尾遞歸 還是又一些不明白


一列數的規則如下: 1、1、2、3、5、8、13、21、34......  求第30位數是多少, 用遞歸算法實現。
答:public class MainClass 
    { 
        public static void Main()   
        { 
            Console.WriteLine(Foo(30)); 
        } 
        public static int Foo(int i) 
        { 
            if (i <= 0) 
                return 0; 
            else if(i > 0 && i <= 2) 
                return 1; 
            else return Foo -1) + Foo(i - 2); 
        } 
    } 


 為了演示這尾遞歸執行的順序  我只執行  Foo(5),   執行i從5到2   等於2返回1    當返回1  下個步驟是執行的什么??是執行Foo(i - 2)這個函數嗎???




19 个解决方案

#1


我不知道你這個問題中糾結“尾遞歸”這個詞兒有什么意義呢?

如果要打印一下程序運行時的輸入參數 i,你就打印輸出好了。電腦打印出來執行順序,而用不着用“下個步驟是執行的什么”這種靠瞎猜的做法啊。

#2


基本上,兩點學習要點:

1. 要動手打印(例如 WriteLine 或者 Debug.Pring)、調試操作、測試驅動。要自己動手然后理解。這是你學的東西,而不是看天書。

2. 避免標題黨。在你還明明什么都沒有看見的時候,起碼不要欺騙自己而說皇帝一定穿了新裝。

#3


都返回了,還執行什么?

#4


你這個哪里是尾遞歸了,再說csc又不支持尾遞歸優化,研究也沒用。

#5


引用 2 樓 sp1234 的回復:
基本上,兩點學習要點:

1. 要動手打印(例如 WriteLine 或者 Debug.Pring)、調試操作、測試驅動。要自己動手然后理解。這是你學的東西,而不是看天書。

2. 避免標題黨。在你還明明什么都沒有看見的時候,起碼不要欺騙自己而說皇帝一定穿了新裝。


我知道沒有啥意義 只是想知道它的執行規律 返回了 下一步執行哪個操作?

#6


無論你想知道哪一步, 都可以用單步跟蹤來實現的。 

學會調試

#7


Foo(i)當I是1或2時,函數都返回1,此時,遞推完成;以后就回歸了,見下圖,圖有點丑


所謂回歸,就是計算上圖中的1+1+1+1+1,也是我們要的結果

#8


if (i <= 0) 
                 return 0; 
             else if(i > 0 && i <= 2) 
                 return 1; 
             else return Foo -1) + Foo(i - 2); 

紅色部分很重要:1、這里計算出真正的數據(數值),而上邊遞推都是函數表達式,不是具體數值;2、函數從此退出調用自己,避免了無限調用自己,陷入死循環

#9


引用 8 樓 From_TaiWan 的回復:
if (i <= 0) 
                 return 0; 
             else if(i > 0 && i <= 2) 
                 return 1; 
             else return Foo -1) + Foo(i - 2); 

紅色部分很重要:1、這里計算出真正的數據(數值),而上邊遞推都是函數表達式,不是具體數值;2、函數從此退出調用自己,避免了無限調用自己,陷入死循環


謝謝你的解答  本來看你的圖 有點了解了 我為了測試它的具體流程 我在輸出設置了個斷點 看見i是如何變化的, 更糊塗了 
5,4,3,2,3,1,3,4,2,4,5,3,2,3,1,3,5


先前四個步驟  很好理解 5,4,3,2后面變成3,1,3.。。。。。。不知怎么計算得來的??

#10


偽遞歸的本質就是循環。我之前分享過尾遞歸的帖子的。

#11


http://bbs.csdn.net/topics/390317532

#12


引用 7 樓 From_TaiWan 的回復:
Foo(i)當I是1或2時,函數都返回1,此時,遞推完成;以后就回歸了,見下圖,圖有點丑


所謂回歸,就是計算上圖中的1+1+1+1+1,也是我們要的結果


又研究了了哈   我想知道它的執行順序  首先執行的時候比如,賦值是 ,即Foo(5)開始 執行 返回Foo(4),執行Foo(4)

而不是Foo(4)+Foo(3), 那第二個函數什么時候開始執行呢 只有把左邊的值得到了,即得到Foo(4) 的值   才開始執行右邊的函數  即當返回,  return     數字+Foo(3)的時候  才開始執行右邊的函數       不知道分析的正確不正確  請大家指教 

#13


引用 9 樓 maocheng82 的回復:
Quote: 引用 8 樓 From_TaiWan 的回復:

if (i <= 0) 
                 return 0; 
             else if(i > 0 && i <= 2) 
                 return 1; 
             else return Foo -1) + Foo(i - 2); 

紅色部分很重要:1、這里計算出真正的數據(數值),而上邊遞推都是函數表達式,不是具體數值;2、函數從此退出調用自己,避免了無限調用自己,陷入死循環


謝謝你的解答  本來看你的圖 有點了解了 我為了測試它的具體流程 我在輸出設置了個斷點 看見i是如何變化的, 更糊塗了 
5,4,3,2,3,1,3,4,2,4,5,3,2,3,1,3,5


先前四個步驟  很好理解 5,4,3,2后面變成3,1,3.。。。。。。不知怎么計算得來的??
順序見下圖箭頭

好象先序遍歷二叉樹

不知道你怎么得到5,4,3,2,3,1,3,4,2,4,5,3,2,3,1,3,5的,應該是:5,4,3,2,1,2,3,2,1

#14


5,4,3,2,3,1,3,4,2,4,5,3,2,3,1,3,5

這是遞歸子函數時計算順序問題,比如f(x)+f(y),是先計算f(x)還是先計算f(y),其實就是樹的前序、中序和后序遍歷問題。跟編譯器有關,跟線程有關。

這個不就是著名的斐波那契數列嘛, 把遞歸改為迭代,就是最大的優化。

事先一次for循環,計算出fx(1)到fx(1000)的值:fx(1)=fx(2)=1; fx(n)=fx(n-1)+fx(n-2)。

需要哪個值n=k,就直接取fx(k)即可。

#15


為了便於觀察,修改成如下
        public static int Foo(int i, string msg="") 
        {
            Console.WriteLine(msg);
            if (i <= 0) 
                return 0; 
            else if(i > 0 && i <= 2) 
                return 1;
            else return Foo(i - 1, string.Format("f({0} - 1)", i)) + Foo(i - 2, string.Format("f({0} - 2)", i)); 
        } 
執行次序一目了然

#16


引用 15 樓 xuzuning 的回復:
為了便於觀察,修改成如下
        public static int Foo(int i, string msg="") 
        {
            Console.WriteLine(msg);
            if (i <= 0) 
                return 0; 
            else if(i > 0 && i <= 2) 
                return 1;
            else return Foo(i - 1, string.Format("f({0} - 1)", i)) + Foo(i - 2, string.Format("f({0} - 2)", i)); 
        } 
執行次序一目了然


是的  正如上面14樓樓主所說 沒有一個固定的順序   跟編譯器有關,跟線程有關。

事先一次for循環,計算出fx(1)到fx(1000)的值:fx(1)=fx(2)=1; fx(n)=fx(n-1)+fx(n-2)。

為什么這么說呢  把I改為7  即執行foo(7) 得到的卻是 



#17


就是個算法問題,怎么跟編譯器,線程扯上關系了?
測試代碼:

static List<int> l = new List<int>();
static int f(int i)
{
    l.Add(i);

    if (i <= 0)
    {
        return 0;
    }
    else if (i <= 2)
    {
        return 1;
    }
    else
    {
        return f(i - 1) + f(i - 2);

    }
}
static void Main(string[] args)
{
    Console.WriteLine(f(5));
    Console.WriteLine("-------------");
    
    foreach(int i in l)
    {
        Console.WriteLine(i.ToString());

    }
    Console.Read();

}



輸出:

#18


你要明白遞歸首先要明白什么是遞歸

#19


你做一下退格處理就更清楚了

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com