3 遞歸
3.1 遞歸<函數>
// MARK: 3.1 遞歸
/*
階乘
*/
func factorial(_ parameter: Int) -> Int {
// 基線條件
guard parameter > 1 else {
print("Base Case \(parameter)")
return parameter
}
print(parameter)
// 遞歸條件
return parameter * factorial(parameter - 1)
}
print("Final result is : \(factorial(3))")
3.2 基線條件和遞歸條件
// MARK: - 3.2 基線條件和遞歸條件
// FIXME: 1. 遞歸條件是指函數調用自己.
// FIXME: 2. 基線條件則是指函數不再調用自己, 從而避免形成無限循環.
// MARK: - 3.3.1 棧<調用棧>
// FIXME: 棧: 是一種簡單的數據結構.
// FIXME: e.g.
func greet(_ name: String) -> Void {
// 2. 為hello函數分配內存并壓入棧
hello(name)
// 3. hello執行完成, 將hello函數從棧中彈出, 并釋放內存
// 4. 為bye函數分配內存并壓入棧
bye(name)
// 5. bye函數執行完成, 將hello函數從棧中彈出(移除), 并釋放內存
}
private func hello(_ name: String) {
print("Hello \(name)!")
}
private func bye(_ name: String) {
print("bye, \(name)~")
}
// 1. 此時為greet函數分配內存并壓入調用棧, 并加參數'Jim"存儲到內存中
greet("Jim")
// 6. greet函數執行完成, 將其從棧中彈出, 并釋放
3.3 遞歸調用棧
// MARK: - 3.3.2 遞歸調用棧
// TODO: 本小節, 拿3.1中的 factorial 函數說明
// FIXME: 1. 當調用 factorial(3)時, 此時的函數調用棧
/*
內部執行順序如下:
factorial(3)
3 * factorial(2)
3 * (2 * factorial(1))
3 * (2 * 1)
3 * 2
6
// FIXME: 上述過程的長度可以看做是內存的峰值曲線.
解釋: 調用3時, 3內調用2, 3等待2完成; 2內調用1, 2等待1完成; 1內調用0, 1等待0完成. 當調用到0時, 0滿足了基線條件, 此時 factorial(0)執行完成, 從棧中彈出, 并釋放內存; 接著 factorial(1)的執行完成, 從棧中彈出并釋放內存; 接著依次類推到棧底 factorial(3)的執行完成, 從棧中彈出并釋放內存.
*/
// FIXME: PS: 當使用遞歸時, 每一次遞歸都棧都需要分配內存, 如果調用棧過長或無限循環, 將占用大量的內存或內存不夠的情況.
// TODO: 如果遇到上述情景, 你有兩種選擇. 1) 重寫代碼, 轉而使用循環. 2) 使用尾遞歸<這是一個高級遞歸, 內存的使用是恒量的, 但是部分語言不支持尾遞歸優化, C 可以.>.