算法图解系列

算法图解系列之递归[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 可以.>.
上一篇下一篇

猜你喜欢

热点阅读