遞歸的簡單認識(c語言)

遞歸

程序調用自身的編程技巧稱爲遞歸( recursion)。 遞歸作爲一種算法在程序設計語言中普遍應用。一個過程或函數在其定義或說明中有直接或間接調用自身的一種方法,它一般把一個大型複雜的問題層層轉化爲一個與原問題類似的規模較小的問題來求解,遞歸策略只需少許的程序就可描述出解題過程所須要的屢次重複計算,大大地減小了程序的代碼。
簡而言之,遞歸就是利用調用自身的方法完成屢次重複計算的方式。算法

  • 設計思想:

把問題分解成規模更小,但和原問題有着相同解法的問題(大事化小)編程

  • 分類:

遞歸函數又能夠分爲尾遞歸和非尾遞歸函數。
尾遞歸函數是指函數的最後一個動做是調用函數自己的遞歸函數,是遞歸的一種特殊情形。尾遞歸具備兩個主要的特徵:數據結構

  1. 調用自身函數(Self-called);
  2. 計算僅佔用常量棧空間(Stack Space)。
  • 優勢:

代碼簡潔,容易計算驗證。函數

  • 缺點:

相對於循環(迭代),效率低下,存在棧區限制問題(棧溢出)。spa

  • 特色:

後進先出,以後迴歸先進入的函數再執行下一步。設計

  • 使用條件:

一個問題可以分解成規模更小,且與原問題有着相同解的問題;
存在一個能讓遞歸調用退出的簡單出口。遞歸

  • 設計條件:

設置遞歸結束的限制條件(儘量防止棧溢出);設計思路儘量遵循在每次調用後不斷逼近限制條件。內存

內存分區

內存分區分爲五種:棧區、堆區、靜態區、常量區、代碼區。rem

  • 棧區:

存放函數的參數值(形參)、局部變量和函數調用申請等,由編譯器自動分配和釋放,一般在函數執行完後就釋放了,其操做方式相似於數據結構中的棧。棧內存分配運算內置於CPU的指令集,效率很高,可是分配的內存量有限。編譯器

  • 堆區:

就是經過new、malloc、realloc和calloc分配的內存塊,能夠認爲是動態分配的內存塊,編譯器不會負責它們的釋放工做,須要用程序區釋放。分配方式相似於數據結構中的鏈表。「內存泄漏」一般說的就是堆區。

  • 靜態區:

全局變量和靜態變量的存儲位置,初始化的全局變量和靜態變量在一塊區域,未初始化的全局變量和未初始化的靜態變量在相鄰的另外一塊區域。程序結束後,由系統釋放。

  • 常量區:常量存儲在這裏,不容許修改。
  • 代碼區:存放編寫的代碼,不調用。

遞歸引發的棧溢出

  • 緣由:

咱們知道,正確的遞歸就是在達到某個限制條件(較小調用次數)以前不斷調用函數來實現目標,而每次調用函數都會向棧區申請內存且不釋放(函數總體還未結束調用),一旦函數調用過多,棧區容量天然不足,棧溢出也就出現了。

  • 棧溢出常見錯誤:

1. 未設置限制條件,函數不斷調用。
2. 限制條件設置不合理,致使函數調用過多。
3. 設計思路存在問題,函數調用結束再也不逼近限制條件,致使函數過多調用。

迭代

  • 概念

迭代是重複反饋過程的活動,其目的一般是爲了逼近所需目標或結果。每一次對過程的重複稱爲一次「迭代」,而每一次迭代獲得的結果會做爲下一次迭代的初始值。
目前對於c語言來講,迭代能夠簡單認爲是循環結構。

  • 遞歸與迭代
  1. 遞歸是一種重複遞推與迴歸過程的結構,而迭代是一種重複循環與更新狀態的結構,二者爲重複計算服務,實現的方式有所不一樣。

遞歸與跌代的不一樣實現方式

  1. 遞歸效率低下,循環驗證麻煩。
  2. 迭代能夠轉換爲遞歸,但遞歸不必定能轉換爲迭代。
  3. 轉換方法:

將遞歸算法轉換爲非遞歸算法有兩種方法,一種是直接求值(迭代),不須要回溯;另外一種是不能直接求值,須要回溯。前者使用一些變量保存中間結果,稱爲直接轉換法,後者使用棧保存中間結果,稱爲間接轉換法。

  • 直接轉換法

直接轉換法一般用來消除尾遞歸(tail recursion)和單向遞歸,將遞歸結構用迭代結構來替代。(單向遞歸 → 尾遞歸 → 迭代)

  • 間接轉換法

遞歸實際上利用了系統堆棧實現自身調用,咱們經過使用棧保存中間結果模擬遞歸過程,將其轉爲非遞歸形式。

尾遞歸函數遞歸調用返回時正好是函數的結尾,所以遞歸調用時就不須要保留當前棧幀,能夠直接將當前棧幀覆蓋掉。

相關文章
相關標籤/搜索