遞迴和「尾遞迴」的那點事

2021-09-07 04:14:09 字數 1848 閱讀 4336

遞迴,就是在執行的過程中呼叫自己。

1,.構成遞迴需具備的條件:

子問題須與原始問題為同樣的事,且更為簡單;

不能無限制地呼叫本身,須有個出口,化簡為非遞迴狀況處理。

在數學和電腦科學中,遞迴指由一種(或多種)簡單的基本情況定義的一類物件或方法,並規定其他所有情況都能被還原為其基本情況。

2.工作原理

棧又稱堆疊,存放程式的區域性變數(不包括靜態區域性變數,static變數存在靜態區)。在函式被呼叫時,棧用來傳遞引數和返回值。由於棧的後進先出特點,所以棧特別方便用來儲存/恢復呼叫現場。從這個意義上講,我們可以把堆疊看成乙個寄存、交換臨時資料的記憶體區。

當c程式中呼叫了乙個函式時,棧中會分配一塊空間來儲存與這個呼叫相關的資訊,每乙個呼叫都被當作是活躍的。棧上的那塊儲存空間稱為活躍記錄或者棧幀

棧幀由5個區域組成:輸入引數、返回值空間、計算表示式時用到的臨時儲存空間、函式呼叫時儲存的狀態資訊以及輸出引數。

棧是用來儲存函式呼叫資訊的絕好方案,然而棧也有一些缺點:

棧維護了每個函式呼叫的資訊直到函式返回後才釋放,這需要占用相當大的空間,尤其是在程式中使用了許多的遞迴呼叫的情況下。除此之外,因為有大量的資訊需要儲存和恢復,因此生成和銷毀活躍記錄需要消耗一定的時間。我們需要考慮採用迭代的方案。

舉個例子:

//求斐波那契數列的第n項

1int

fibonaccirecursive

(int n)

2

//遞迴實現階乘

intfact

(int n)

優點:無疑就是**簡潔明瞭,容易理解;

缺點:執行效率較低;在遞迴呼叫的過程當中系統為每一層的返回點、區域性量等開闢了棧來儲存,因此遞迴次數過多容易造成棧溢位。

簡而言之,遞迴過的壓棧和出棧,時間和空間都有很大的消耗,

建議:應該盡量避免使用遞迴,除非沒有更好的演算法或者某種特定情況,遞迴更為適合的時候。

如果乙個函式中所有遞迴形式的呼叫都出現在函式的末尾,我們稱這個遞迴函式是尾遞迴的。當遞迴呼叫是整個函式體中最後執行的語句且它的返回值不屬於表示式的一部分時,這個遞迴呼叫就是尾遞迴。尾遞迴函式的特點是在回歸過程中不用做任何操作,這個特性很重要,因為大多數現代的編譯器會利用這種特點自動生成優化的**。

舉個例子:

//這是尾遞迴

intf

(x)//這不是尾遞迴

intf

(x)//這不是尾遞迴

intfactorial

(n)

工作原理

當編譯器檢測到乙個函式呼叫是尾遞迴的時候,它就覆蓋當前的活動記錄而不是在棧中去建立乙個新的。編譯器可以做到這點,因為遞迴呼叫是當前活躍期內最後一條待執行的語句,於是當這個呼叫返回時棧幀中並沒有其他事情可做,因此也就沒有儲存棧幀的必要了。通過覆蓋當前的棧幀而不是在其之上重新新增乙個,這樣所使用的棧空間就大大縮減了,這使得實際的執行效率會變得更高。

//尾遞迴實現階乘

intfacttail

(int n,

int res)

再比如之前寫過的斐波那契數列的尾遞迴形式:

//尾遞迴的方式:first second傳1;

intfib_3

(int first,

int second,

int n)

遞迴和尾遞迴

c語言中編譯預處理的三種形式的命令 巨集定義,檔案包含,條件編譯命令。1 巨集定義主要是 define,undef 如下 define pi 3.1415926 不帶引數的巨集定義 define max a,b a b?a b 帶引數的巨集定義 說明 巨集定義在c語言與c 語言中是相通的。下面舉例說...

尾遞迴和線性遞迴

線性遞迴 fac 0 1 fac n n fac n 1 尾遞迴 fac 0,sum sum fac n,sum fac n 1,sum n 尾遞迴定義 函式最後一步呼叫自身,即最後一行 一定是對於自己的乙個遞迴呼叫。erlang尾遞迴這樣帶來的好處是可以讓編譯器做到將遞迴優化,轉化為跳轉指令而不是...

遞迴和尾遞迴的區別

一 遞迴 1.定義 在電腦科學領域中,遞迴式通過遞迴函式來實現的。程式呼叫自身的程式設計技巧稱為遞迴 recursion 乙個過程或函式在其定義或說明中有直接或間接呼叫自身的一種方法,它通常把乙個大型複雜的問題層層轉化為乙個與原問題相似的規模較小的問題來求解,遞迴策略只需少量的程式就可描述出解題過程...