程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C#中尾遞歸的應用、優化及編譯器優化

C#中尾遞歸的應用、優化及編譯器優化

編輯:C#入門知識

C#中尾遞歸的應用、優化及編譯器優化。本站提示廣大學習愛好者:(C#中尾遞歸的應用、優化及編譯器優化)文章只能為提供參考,不一定能成為您想要的結果。以下是C#中尾遞歸的應用、優化及編譯器優化正文


遞歸應用

一個函數直接或直接的挪用本身,這個函數便可叫做遞歸函數。

遞歸重要功效是把成績轉換成較小范圍的子成績,以子成績的解去逐步切近親近終究成果。
遞歸最主要的是界限前提,這個界限是全部遞歸的終止前提。

static int RecFact(int x)
{
    if (x == 0)
        return 1;
    return x * RecFact(x - 1);
}
RecFact(10);

下面是個經典階乘函數的完成。這裡分2步:

1.轉換,把10的階乘轉化成10*9!,10(9*8!)....每次轉換范圍就變的更小。
2.切近親近,轉換到最小范圍時0!,求解1。開端逆向歸並逐步切近親近到10,得出解。
這裡的x==0就是我們的界限前提(即終止前提),也有的依附內部變量為界限。

假如一個遞歸函數沒有界限,也就沒法停滯(無窮輪回至內存溢出),固然如許也沒甚麼意義。

RecFact挪用客棧:

罕見應用場景:

1.階乘/斐波那契數列/漢諾塔
2.遍歷硬盤文件
3.InnerExceptions異常撲捉(exception.InnerException==null)

尾遞歸優化

當界限不明白的時刻,遞歸就很輕易湧現溢出成績。

在階乘進程中,客棧須要保留每次(RecFact)挪用的前往地址及其時一切的部分變量狀況,時代客棧空間是沒法釋放的(即輕易湧現溢出)。

為了優化客棧占用成績,從而提出尾遞歸優化的方法。

static void TailRecursion(int x)
    {
        Console.WriteLine(x);
        if (x == 10)
            return;
        TailRecursion(x + 1);
    }
    TailRecursion(0);

應用尾遞歸客棧可以不消保留前次的函數前往地址/各類狀況值,而辦法遺留在客棧上的數據完整可以釋放失落,這是尾遞歸優化的焦點思惟。

因為尾遞歸時代,客棧是可以釋放/再應用的,也就處理遞歸過深而惹起的溢出成績,這也是尾遞歸的優勢地點。

編譯器優化

尾遞歸優化,看起來是蠻美妙的,但在net中卻有點亂糟糟的感到。

1.Net在C#說話中是JIT編譯成匯編時停止優化的。
2.Net在IL上,有個特別指令tail去完成尾遞歸優化的(F#中)。

我們履行 TailRecursion(0)(x==1000000) 得出以下結論:

C#/64位/Release是有JIT編譯器停止尾遞歸優化的(非C#編譯器優化)。

C#/32位或C#/Debug形式中JIT是不停止優化的。

F#在優化尾遞歸也分2種情形:

1、 簡略的尾遞歸優化成while輪回,以下:

let rec TailRecursion(x) =
  if (x = 1000) then true
  else TailRecursion(x + 1)

(便利演示C#出現)編譯器優化成:

public static bool TailRecursion(int x)
    {
        while (x != 0x3e8)
        {
            x++;
        }
        return true;
    }

2、 龐雜的尾遞歸,F#編譯器會生成IL指令Tail停止優化,以下:

let TailRecursion2 a cont = cont (a + 1) 

優化成:

若何界說龐雜的尾遞歸呢?平日是後繼傳遞形式(CPS)。

F#中在debug形式下,須要在編譯時設置裝備擺設:

總結

在C#說話(進程式/面向對象編程思惟)中,優先斟酌的是輪回,而不是遞歸/尾遞歸。 但在函數式編程思惟傍邊,遞歸/尾遞歸應用則是主流用法,就像在C#應用輪回一樣。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved