[关闭]
@aliasliyu4 2018-04-03T19:14:02.000000Z 字数 945 阅读 1273

讲讲递归和尾递归

递归

理解递归,就是要先理解递归,递归的特性有两个。

比如求一个n!的阶乘是很容易写成递归的。

  1. func fact(x int) int {
  2. if x == 1 {
  3. return 1 // 函数出口
  4. } else {
  5. return x * fact(x-1) // 递归本身
  6. }
  7. }

假设我们求fact(3)的值,我可以如下图一般展开,显而易见的是函数会在x==1处返回,然后从调用栈的最深处返回开始的调用位置,并且返回阶乘的结果。
CpYLAH.jpg

尾递归

尾递归函数的返回值返回的是函数本身, 尾递归的性质

下面是一段二分search的尾递归形式

  1. var i int = 1
  2. // 使用递归去实现这个过程
  3. // 确切的说这是一个尾递归(不保存调用者的状态,直接丢弃)
  4. func binarySearchRecursive(start, end int, in []int, target int) int {
  5. fmt.Println("------------------------------------------------------------------------")
  6. fmt.Printf("if start %d == end %d\n", start, end)
  7. fmt.Printf("frame %v: start: %d, end: %d, in: %v, target: %d\n", i, start, end, in, target)
  8. fmt.Println("call binarySearchRecursive")
  9. fmt.Println("------------------------------------------------------------------------")
  10. i++
  11. if start == end {
  12. return start
  13. }
  14. if start != end {
  15. mid := (start + end) / 2
  16. if target > in[mid] {
  17. start = mid + 1
  18. } else {
  19. end = mid
  20. }
  21. }
  22. return binarySearchRecursive(start, end, in, target)
  23. }

CptCDS.jpg
红色方向表示函数栈的方向,可以把他理解成串行之行,上一次执行的输出是一个执行的输入,所以很显然这种写法是不存在调用栈。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注