[英]Recursion vs For loops - Factorials, Java
這兩種獲得階乘(循環與遞歸)的方法中哪一種更有效/更快? 如果可以改進,如何改進?
語言:Java
private static long factrecur(int n) {
if (n == 0) {
return 1;
}
else {
return n * factrecur(n-1);
}
}
private static long factloop(int a) {
long total = 1;
for (int b=a;b>=1;b--) {
total *= b;
}
return total;
}
因為沒有方法調用的開銷,for 循環會更高效。 (作為一般規則,循環幾乎總是比遞歸更有效)
解釋為什么必須深入了解調用方法和調用堆棧時會發生什么的細節。
基本上,當你調用一個方法時,它需要一些空間來處理(對於它的局部變量等)它也需要空間來傳遞給它的傳入參數和一個地方來存儲它應該去哪里的返回地址執行完畢。 這個空間是通過將值“推送”到堆棧上來動態提供的。 該堆棧空間一直被占用,直到方法返回,此時它被“彈出”。
因此,在這種情況下考慮遞歸:每次從自身內部調用方法時,都會將更多數據推送到堆棧上,而不會從您所在的方法返回(因此不會釋放調用方法占用的堆棧空間)。 隨着您的遞歸深入,內存量會增加。
相比之下,您編寫的 for 循環僅使用一個堆棧幀推送提供的固定內存量。
有 21 次調用,您的 long 將超支,這是衡量差異的早期階段,這可能會變得相關。
在測量factorial (10*1000*1000)
或大的東西時,您可能需要BigInteger來測量顯着差異。 如果您沒有大量要計算的數字,但經常計算低階乘,則具有預先計算值的哈希圖將比遞歸和循環更快。
遞歸的唯一問題是每次調用函數時,它的地址都放在堆棧的頂部,如果遞歸調用的次數很高,則連接大量調用會導致堆棧溢出異常。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.