尾遞歸與尾調用

在很多的高級語言中,都會提到尾遞歸的特性。

當年在大學裏學遞歸時,老師特別強調遞歸次數與進程棧的關係。

遞歸越多,函數入棧越多,由於進程有棧空間有線,會生成棧越界。

下圖是一個入棧的過程。

main call funcA ;

funcA call funcB

當然了,遞歸引發棧越界只是調用棧越界的方式之一,如果代碼寫的調用層級特別多,則也會引發棧越界。

隨着語言的發展(我想其中是語言的編譯器與解釋器的發展),發明一種叫“尾調用”的技術。

來個例子:

function B

{

    do someting;

    return 0;

}

function A

{

   do someting;

    return B;

}

這種A使用return B.把自己的返回與調用B聯合在了一起。這就叫尾調用。

解釋器就發現,當調用B完成之後,A的棧上的數據不會再被使用。那不如先把A從棧上POP出去。再調用B。

如下來個不是尾調用的例子。

function A1

{

   do someting;

   ret = B();

    return ret;

}

A1在調用了B後,還會使用棧上的內容。或是如下例子也不是尾調用。

function A2

{

   do someting;

      return B()+1;

}

尾調用不一定出現在函數尾部,只要是最後一步操作即可。

如function A3

{

      if(xxx == true) then

           return B(); //這裏就是尾調用。

     else

           a++;

     end

}

尾調用的棧是怎麼玩的呢?

尾遞歸正是使用了尾調用的特性。

在寫遞歸函數時,特意使用尾調用的寫法。這樣遞歸時,棧空間不會隨着遞歸次數而增長。這樣就節約了很多的內存。


PS:我寫的文章就很一般了,在網上有很多對尾調用和尾遞歸的介紹。大家可以多參考一下。

http://www.ruanyifeng.com/blog/2015/04/tail-call.html

C語言的編譯器在加上-O2也可以識別並優化尾調用 。

有一例子,請大家自己行參考吧

http://blog.sina.com.cn/s/blog_5374d6e30100t0do.html


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章