欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C#中尾遞歸的使用、優(yōu)化及編譯器優(yōu)化

 更新時間:2015年04月10日 08:57:10   投稿:junjie  
這篇文章主要介紹了C#中尾遞歸的使用、優(yōu)化及編譯器優(yōu)化,本文講解了遞歸運用、尾遞歸優(yōu)化、編譯器優(yōu)化等內容,需要的朋友可以參考下

遞歸運用

一個函數直接或間接的調用自身,這個函數即可叫做遞歸函數。

遞歸主要功能是把問題轉換成較小規(guī)模的子問題,以子問題的解去逐漸逼近最終結果。
遞歸最重要的是邊界條件,這個邊界是整個遞歸的終止條件。

復制代碼 代碼如下:

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!)....每次轉換規(guī)模就變的更小。
2.逼近,轉換到最小規(guī)模時0!,求解1。開始逆向合并逐漸逼近到10,得出解。
這里的x==0就是我們的邊界條件(即終止條件),也有的依賴外部變量為邊界。

如果一個遞歸函數沒有邊界,也就無法停止(無限循環(huán)至內存溢出),當然這樣也沒什么意義。

RecFact調用堆棧:

常見使用場景:

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

尾遞歸優(yōu)化

當邊界不明確的時候,遞歸就很容易出現溢出問題。

在階乘過程中,堆棧需要保存每次(RecFact)調用的返回地址及當時所有的局部變量狀態(tài),期間堆棧空間是無法釋放的(即容易出現溢出)。

為了優(yōu)化堆棧占用問題,從而提出尾遞歸優(yōu)化的辦法。

復制代碼 代碼如下:

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

使用尾遞歸堆棧可以不用保存上次的函數返回地址/各種狀態(tài)值,而方法遺留在堆棧上的數據完全可以釋放掉,這是尾遞歸優(yōu)化的核心思想。

由于尾遞歸期間,堆棧是可以釋放/再利用的,也就解決遞歸過深而引起的溢出問題,這也是尾遞歸的優(yōu)勢所在。

編譯器優(yōu)化

尾遞歸優(yōu)化,看起來是蠻美好的,但在net中卻有點亂糟糟的感覺。

1.Net在C#語言中是JIT編譯成匯編時進行優(yōu)化的。
2.Net在IL上,有個特殊指令tail去實現尾遞歸優(yōu)化的(F#中)。

我們執(zhí)行 TailRecursion(0)(x==1000000) 得出如下結論:

C#/64位/Release是有JIT編譯器進行尾遞歸優(yōu)化的(非C#編譯器優(yōu)化)。

C#/32位或C#/Debug模式中JIT是不進行優(yōu)化的。

F#在優(yōu)化尾遞歸也分2種情況:

1、 簡單的尾遞歸優(yōu)化成while循環(huán),如下:

復制代碼 代碼如下:

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

(方便演示C#呈現)編譯器優(yōu)化成:
復制代碼 代碼如下:

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

2、 復雜的尾遞歸,F#編譯器會生成IL指令Tail進行優(yōu)化,如下:
復制代碼 代碼如下:

let TailRecursion2 a cont = cont (a + 1) 

優(yōu)化成:

如何定義復雜的尾遞歸呢?通常是后繼傳遞模式(CPS)。

F#中在debug模式下,需要在編譯時配置:

總結

在C#語言(過程式/面向對象編程思想)中,優(yōu)先考慮的是循環(huán),而不是遞歸/尾遞歸。 但在函數式編程思想當中,遞歸/尾遞歸使用則是主流用法,就像在C#使用循環(huán)一樣。

相關文章

  • C#中Foreach循環(huán)遍歷的本質與枚舉器詳解

    C#中Foreach循環(huán)遍歷的本質與枚舉器詳解

    這篇文章主要給大家介紹了關于C#中Foreach循環(huán)遍歷本質與枚舉器的相關資料,foreach循環(huán)用于列舉出集合中所有的元素,foreach語句中的表達式由關鍵字in隔開的兩個項組成,本文通過示例代碼介紹的非常詳細,需要的朋友可以參考下
    2021-08-08
  • C# 參數按照ASCII碼從小到大排序(字典序)

    C# 參數按照ASCII碼從小到大排序(字典序)

    這篇文章主要介紹了C# 參數按照ASCII碼從小到大排序(字典序)的方法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2017-04-04
  • C#?將數據庫SqlServer數據綁定到類中的過程詳解

    C#?將數據庫SqlServer數據綁定到類中的過程詳解

    本文講述的是讀取數據庫中數據的常用做法,即將數據庫中的數據綁定到創(chuàng)建的類中,再將類綁定到DataGridView的數據源中的做法,對C#將SqlServer數據綁定到類中感興趣的朋友一起看看吧
    2022-06-06
  • WinForm實現最小化到系統(tǒng)托盤方法實例詳解

    WinForm實現最小化到系統(tǒng)托盤方法實例詳解

    這篇文章主要介紹了WinForm實現最小化到系統(tǒng)托盤方法,實例分析了C#中實現WinForm最小化到系統(tǒng)托盤所需的相關控件與使用技巧,需要的朋友可以參考下
    2015-05-05
  • C#使用NPOI導出Excel類封裝

    C#使用NPOI導出Excel類封裝

    這篇文章主要為大家詳細介紹了C#使用NPOI導出Excel類封裝,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • C#自動給文章關鍵字加鏈接實現代碼

    C#自動給文章關鍵字加鏈接實現代碼

    這篇文章主要介紹了C#自動給文章關鍵字加鏈接實現代碼,有需要的朋友可以參考一下
    2013-12-12
  • C# Winform中DataGridView導出為Excel的實現示例

    C# Winform中DataGridView導出為Excel的實現示例

    本文主要介紹了C# Winform中DataGridView導出為Excel的實現示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-05-05
  • c#打開py文件的方法

    c#打開py文件的方法

    在本篇內容里小編給大家分享的是關于c#打開py文件的方法和步驟,需要的朋友們可以跟著學習下。
    2018-12-12
  • C#開發(fā)Android百度地圖手機應用程序(多地圖展示)

    C#開發(fā)Android百度地圖手機應用程序(多地圖展示)

    這篇文章主要介紹了C#開發(fā)Android百度地圖手機應用程序(多地圖展示)的相關資料,需要的朋友可以參考下
    2016-02-02
  • 積累Visual Studio 常用快捷鍵的動畫演示

    積累Visual Studio 常用快捷鍵的動畫演示

    在代碼開發(fā)過程中,頻繁的使用鍵盤、鼠標操作非常麻煩,影響程序的開發(fā)效率。如何操作能用鍵盤來操作,那就節(jié)省時間了。下面小編把我平時積累的有關visul studio 常用快捷鍵的動畫演示分享給大家,僅供大家參考
    2015-10-10

最新評論