LeetCode遞歸 -2(Recursion) 培訓專題 講解文章翻譯 (附連接) (2019-04-09 15:50)

遞歸 - 空間複雜度 

在本文中, 咱們將討論如何分析遞歸算法的空間複雜度.
在計算遞歸算法的空間複雜度時,最須要考慮的兩個部分就是: 遞歸相關空間 (recursion related space)和非遞歸相關空間(non-recursion related space).

遞歸相關空間


遞歸相關空間指的是遞歸直接產生的內存開銷,也就是在遞歸調用過程當中開闢的堆棧內存空間。爲了完成一個典型的函數調用,系統中在開闢內存空間時,會存放一下3個重要的數據信息:
  1. 調用函數的返回地址. 一旦程序調用結束,須要這個地址返回, 即程序調用結束進行下一步的地址; 
  2. 該調用函數所須要的參數; 
  3. 調用函數的內部變量.
儘管堆棧是在遞歸調用時產生的最小消耗. 旦只要調用過程結束,這些空間也會被釋放掉。 
對於遞歸算法,函數的調用將會持續產生調用鏈,直至調用到基本型 (base case) (亦稱做. bottom case).這意味着每一個函數的調用也是逐步累積的.
對於遞歸算法, 若是沒有其餘的內存消耗, 這個算法的空間上限就是該遞歸調用直接產生的內存開銷。
仍是拿練習  printReverse說事,咱們每次調用只是打印了一個字符,因此在遞歸調用以外咱們沒有用掉其餘的內存開銷, .對於每一次的遞歸調用, 假設須要一個固定常量的空間. 那麼根據前面的分析,他會調用 n 次函數鏈,  n 就是輸入的字串長度. 因此該算法的空間複雜度即爲 {\mathcal{O}(n)}O(n).
爲了更好地說明, 對於遞歸調用序列 f(x1) -> f(x2) -> f(x3) 的執行步驟序列以及堆棧的佈局以下圖所示:
 f(x1) 將會被分配必定額外的空間以便調用f(x2). 對於 f(x2)調用f(x3).時候的內存操做也是一樣類型的狀況,直到 f(x3),的調用到達了基本型, 當到達 f(x3).時,不在分配額外空間。
這種調用機制致使有時分配給堆棧的空間有時超出內存限制,會致使一種程序崩潰的狀況,叫作棧溢出( stack overflow),因此當設計採用這種遞歸調用機制的程序時,首要考慮的就是輸入量是否會致使溢出狀況的發生。
 

非遞歸相關空間 


顯而易見, 所謂非遞歸相關空間即與遞歸調用鏈過程當中不直接相關的內存開銷, 好比爲全局變量所分配的空間(通常狀況下都存放在堆heap中).
不管是否是遞歸程序,在執行下一個子程序以前總須要一個全局變量來存放輸入的數據。  一樣對於調用函數的返回值也須要開闢空間來存放.後者的一種狀況就是咱們前面討論過的 記憶化 處理方式. 例如在處理斐波那契額數列的記憶化遞歸算法中, 咱們使用一個map來存儲每次遞歸調用返回的結果值. 所以, 在計算該算法的空間複雜度的時候, 咱們同時也須要考慮記憶化操做所帶來的空間成本.  
相關文章
相關標籤/搜索