递归和尾递归
最后更新于:2022-04-02 04:10:46
[TOC]
## 递归和尾递归概念
递归
* 递归就是不断地调用函数本身。
尾递归
* 递归函数在调用自身后直接传回其值,而不对其再加运算,函数中所有递归形式的调用都出现在函数的末尾
* 尾递归函数的特点是在**回归过程中不用做任何操作**,这个特性很重要,因为大多数现代的编译器会利用这种特点自动生成优化的代码
### 尾递归为何能优化
普通递归需要先展开,在计算.展开过称可以爆栈
```
function fact(n) {
if (n <= 0) {
return 1;
} else {
return n * fact(n - 1);
}
}
//展开
6 * fact(5)
6 * (5 * fact(4))
6 * (5 * (4 * fact(3))))
// two thousand years later...
6 * (5 * (4 * (3 * (2 * (1 * 1)))))) // <= 最终的展开
//计算
6 * (5 * (4 * (3 * (2 * 1)))))
6 * (5 * (4 * (3 * 2))))
6 * (5 * (4 * 6)))
// two thousand years later...
720 // <= 最终的结果
```
尾递归优化不会爆栈是因为语言的编译器或者解释器所做了“尾递归优化”,而不是尾递归不会进行展开
## 阶乘
### 递归
```
package main
import "fmt"
func Rescuvie(n int) int {
if n == 0 {
return 1
}
return n * Rescuvie(n-1)
}
func main() {
fmt.Println(Rescuvie(5))
}
```
### 尾递归
```
package main
import "fmt"
func RescuvieTail(n int, a int) int {
if n == 1 {
return a
}
return RescuvieTail(n-1, a*n)
}
func main() {
fmt.Println(RescuvieTail(5, 1))
}
```
## 斐波那契数列
### 递归
```
func main() {
fmt.Printf("%+v\n", demo(3))
}
/**
n res cal
1 1 1
2 1 1
3 2 (n-1)*(n-2)
*/
func demo(n int) int {
if n ==1 || n==2 {
return 1
}else {
return demo(n-1)+ demo(n-2)
}
}
```
### 尾递归
```
package main
import "fmt"
func F(n int, a1, a2 int) int {
if n == 0 {
return a1
}
return F(n-1, a2, a1+a2)
}
func main() {
fmt.Println(F(5, 1, 1))
}
```
## 二分查找
```
package main
import "fmt"
// 二分查找递归解法
func BinarySearch(array []int, target int, l, r int) int {
if l > r {
// 出界了,找不到
return -1
}
// 从中间开始找
mid := (l + r) / 2
middleNum := array[mid]
if middleNum == target {
return mid // 找到了
} else if middleNum > target {
// 中间的数比目标还大,从左边找
return BinarySearch(array, target, 1, mid-1)
} else {
// 中间的数比目标还小,从右边找
return BinarySearch(array, target, mid+1, r)
}
}
func main() {
array := []int{1, 5, 9, 15, 81, 89, 123, 189, 333}
target := 500
result := BinarySearch(array, target, 0, len(array)-1)
fmt.Println(target, result)
target = 189
result = BinarySearch(array, target, 0, len(array)-1)
fmt.Println(target, result)
}
```
';