遞歸優(yōu)化-尾遞歸

尾遞歸能否起到優(yōu)化作用跟編譯器有關(guān)系,并不是用了尾遞歸就一定能起到優(yōu)化作用。

定義:函數(shù)里的最后一個動作是返回一個函數(shù)的調(diào)用結(jié)果的情形,即最后一步新調(diào)用的返回值直接被當前函數(shù)的返回結(jié)果。

假設有遞歸函數(shù) func,其最后的return語句有以下兩種寫法:

// 第一種
return  x * func(n-1);

// 第二種(尾調(diào)用)
return func(n-1);

對于第一種情況,要求出func(n)必須求出func(n-1),也就是說在調(diào)用道最后一層之前,之前的調(diào)用必須壓棧存儲。這樣如果棧太深會導致StackOverflow。

若采用第二種尾調(diào)用的方式,由于 return 語句里函數(shù)調(diào)用結(jié)果即為本函數(shù)的調(diào)用結(jié)果,在執(zhí)行func(n-1)時可以(可以不是一定)不用將func(n)的棧楨保存起來,這樣就可以避免以上StackOverflow異常。

尾遞歸能否起到優(yōu)化作用跟編譯器有關(guān)

尾遞歸語法只是具備了優(yōu)化的條件,至于會不會優(yōu)化要看編譯器是不是真的會優(yōu)化,也就是說對于不同語言,甚至同一種語言不同配置結(jié)果都是不一樣的。

以C語言函數(shù)為例:

int tail_func(int n, int res){
    if (n <= 1) return res;
    return tail_func(n - 1, n * res);
}

不開啟編譯優(yōu)化 gcc -o tr func_tail.c 后得到如下匯編代碼

.LFB3:
        pushq   %rbp
.LCFI3:
        movq    %rsp, %rbp
.LCFI4:
        subq    $16, %rsp
.LCFI5:
        movl    %edi, -4(%rbp)
        movl    %esi, -8(%rbp)
        cmpl    $1, -4(%rbp)
        jg      .L4
        movl    -8(%rbp), %eax
        movl    %eax, -12(%rbp)
        jmp     .L3
.L4:
        movl    -8(%rbp), %eax
        movl    %eax, %esi
        imull   -4(%rbp), %esi
        movl    -4(%rbp), %edi
        decl    %edi
        call    tail_func
        movl    %eax, -12(%rbp)
.L3:
        movl    -12(%rbp), %eax
        leave
        ret

開啟編譯優(yōu)化后得到如下匯編代碼

tail_func:
.LFB13:
        cmpl    $1, %edi
        jle     .L8
        .p2align 4,,7
.L9:
        imull   %edi, %esi
        decl    %edi
        cmpl    $1, %edi
        jg      .L9
.L8:
        movl    %esi, %eax
        ret

注意第10行jg .L9,沒有將內(nèi)部函數(shù)當作一個調(diào)用,而是采用跳轉(zhuǎn)的方式,其本質(zhì)就是:內(nèi)部調(diào)用與本身用了同一個棧楨。這就是尾遞歸帶來的性能優(yōu)化

延伸-尾調(diào)用

尾遞歸之所以能帶來性能上的優(yōu)化,本質(zhì)上是因為采用了尾調(diào)用。也就是說只要是尾調(diào)用,都可以實現(xiàn)這種優(yōu)化,原理同上。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容