算法图解系列之递归[03]
2019-11-19 本文已影响0人
Just丶Go
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 可以.>.