博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
学习日志 ━━ 理解递归(使用go语法举例)
阅读量:4115 次
发布时间:2019-05-25

本文共 4188 字,大约阅读时间需要 13 分钟。

理解循环和递归的区别

循环

循环比较好理解,就是一条通道不停开门,不停前行,直到开不了门,就跳出这个通道。

如果是死循环,则相当于此通道永无止尽,

  1. 可能是一个环形通道,
  2. 可能是一条串行无限的通道。

递归

递归则相当于一条通道不停开门,不停前行,直到开不了门,则从 原路返回

所以“递归”从字面上看就非常准确地表达了其含义。

  1. :依次、一层层
  2. :回来,回头执行

实例分析递归的实现过程

一、实例一

1、 递归函数及输出结果

现在我们写一个递归

// 主程序func main() {
digui(3)}//递归函数func digui(n int) {
if n < 1 {
fmt.Println("结束", 99) return } n-- fmt.Println("进", n) // 递归调用 digui(n) n += 1000 fmt.Println("出", n)}// 输出/*进 2进 1进 0结束 99出 1000出 1001出 1002*/

2、 解析执行过程

那么他内部是怎么执行的呢?现在我很傻瓜的把函数一层层嵌入进去解析一下~~+

// 主程序func main() {
digui(3)}//传一个参数n=3的拷贝进入digui()函数func digui(n int) {
//此时n=3,不符合本条件 if n < 1 {
fmt.Println("结束", 99) return } // 执行n--,此时n=2 n-- // 打印第一行:进 2 fmt.Println("进", n) //digui(n) // 这里的递归相当于执行了一个闭包函数 // 传一个参数n=2的拷贝进入函数 func(n int) {
//此时n=2,不符合本条件 if n < 1 {
fmt.Println("结束", 99) return } // 执行n--,此时n=1 n-- // 打印第二行:进 1 fmt.Println("进", n) //digui(n) // 这里的递归相当于执行了一个闭包函数 // 传一个参数n=1的拷贝进入函数 func(n int) {
//此时n=1,不符合本条件 if n < 1 {
fmt.Println("结束", 99) return } // 执行n--,此时n=0 n-- // 打印第三行:进 0 fmt.Println("进", n) //digui(n) // 这里的递归相当于执行了一个闭包函数 // 传一个参数n=0的拷贝进入函数 func(n int) {
// 此时n<1,符合条件 if n < 1 {
// 打印第四行:结束 99 fmt.Println("结束", 99) //结束本函数,后面的都不执行了 return } //因为不执行了,所以后面都注释了 /* n-- fmt.Println("进", n) digui(n) n += 1000 fmt.Println("出", n) */ }(n) // 这一层里的n=0,n+=1000的值为10000 n += 1000 // 第五行打印:出 1000 fmt.Println("出", n) }(n) // 这一层里的n=1,n+=1000的值为10001 n += 1000 // 第六行打印:出 1001 fmt.Println("出", n) }(n) // 这一层里的n=2,n+=1000的值为10002 n += 1000 // 第七行打印:出 1002 fmt.Println("出", n)}

注意:

  1. 本例中函数传参都是值传递,即拷贝,这样外层函数的n=2传入内层函数后执行n--,得到n=1,但该内层的n与外层的n并无关系,因此,在内层函数结束完成后再去执行外层的n+=1000,这里n的值为1002
  2. 解析的例子中可以看出,每层函数结束后都还需要执行一次n+=1000fmt.Println("出",n),这也就是所谓的“回头路”了,其本质仍旧是串联执行,一层函数结束后继续执行下去直到本层结束再继续执行~~并没有真的“走回头路”;
  3. 如果把递归的调用放在函数末尾则叫“尾递归”,实行尾递归时,一层结束后没有任务需要执行就跳到下一层,于是函数就“快速”地一层层结束了,让人感觉没有走回头路,所以尾递归用for循环也能实现。

二、实例二

假设有一题:6层台阶,可以一次走两层或者一次走一层,那么有几种走法?

这里就可以用到递归,本题我们只研究递归的实现过程,不研究算法。

1、 递归函数及输出结果

单看这个递归不好理解,递归是一路走下去,直到没路再原路返回,那这个例子中返回值是两个返回值相加,怎么就能一头越变越小,另一头又越来越大呢?而且返回值是两个函数返回值的和,那这两个函数又会分别分出两个函数去生成返回值,那这样分叉越来越多,岂不是无限循环了?

func main() {
fmt.Println(f(6))}func f(n int) int {
if n == 1 {
return 1 } if n == 2 {
return 2 } return f(n-2) + f(n-1)}// 输出:13

2、 解析执行过程

带着一脸的疑惑,我们来看一看具体的执行流程。

假定每一层都有ab两个变量分别接收两个函数的返回值,然后再将a+b之和返回给当前函数。
下面的解析过程已经去掉了不符合条件的语句,否则太长了。

func main() {
fmt.Println(f(6))}// n = 6func f(n int) int {
// 输入6-2=4 a := func(n int) int {
// 输入4-2=2 a := func(n int) int {
return 2 }(n - 2) // 返回2 // 输入4-1=3 b := func(n int) int {
// 输入3-2=1 a := func(n int) int {
return 1 }(n - 2) // 返回1 // 输入3-1=2 b := func(n int) int {
return 2 }(n - 1) // 返回2 // 返回1+2=3 return a + b }(n - 1) // 返回3 // 返回2+3=5 return a + b }(n - 2) // 返回5 // 输入6-1=5 b := func(n int) int {
// 输入5-2=3 a := func(n int) int {
// 输入3-2=1 a := func(n int) int {
return 1 }(n - 2) //返回1 // 输入3-1=2 b := func(n int) int {
return 2 }(n - 1) //返回2 //返回1+2=3 return a + b }(n - 2) // 返回3 // 输入5-1=4 b := func(n int) int {
// 输入4-2=2 a := func(n int) int {
return 2 }(n - 2) // 返回2 // 输入4-1=3 b := func(n int) int {
// 输入3-2=1 a := func(n int) int {
return 1 }(n - 2) // 返回1 // 输入3-1=2 b := func(n int) int {
return 2 }(n - 1) // 返回2 // 返回1+2=3 return a + b }(n - 1) // 返回3 // 返回2+3=5 return a + b }(n - 1) // 返回5 // 返回3+5=8 return a + b }(n - 1) // 返回8 // 返回5+8=13 return a + b} // 返回13

看代码的执行过程,我们能看出:

  1. n-2n-1n不断变小,n传递至下一层后,在符合n==1n==2的条件之前,n一直在不断变小;
  2. n遇到条件n==1n==2时,它(n)终于撞南墙returnreturn的意思就是结束本层,进入下一层。
  3. 到达上一层后先执行a+b,两者之和return回上一层,并执行上一层的a+b
  4. 因此n在不断减小,a+b不断变大返回。
  5. 与上个例子一样,将递归函数作为标准,该函数之前的行为依次执行,直至遇到返回条件后,再依次执行递归函数之后的程序。
  6. 从过程中可以总结本题:进入下一层的目的是不断创建分支直至条件满足返回,返回上一层的目的是将分支中的值进行加法计算再供上一层使用。

按照上面的总结,我们怎么让自己一眼看出递归的执行流程呢?

以本例中return f(n-2)+f(n-1)作为标准;

  1. if:两句条件语句n==1n==2在调用递归函数之前,因此先执行;
  2. n-1 n-2n-1n-2作为参数传入f(),因此这两参数是第二位执行,此后函数在不断执行 n-1n-2
  3. if return:直到n满足了条件n==1n==2后返回1或者2
  4. + return:此后不断返回外层,再将f(n-2)+f(n-1)(即a+b)之和返回,直至程序结束。

转载地址:http://vtkpi.baihongyu.com/

你可能感兴趣的文章
C# 发HTTP请求
查看>>
启动 LocalDB 和连接到 LocalDB
查看>>
Palindrome Number --回文整数
查看>>
Reverse Integer--反转整数
查看>>
Container With Most Water --装最多水的容器(重)
查看>>
Longest Common Prefix -最长公共前缀
查看>>
Letter Combinations of a Phone Number
查看>>
Single Number II --出现一次的数(重)
查看>>
Valid Parentheses --括号匹配
查看>>
Remove Element--原地移除重复元素
查看>>
Remove Duplicates from Sorted Array--从有序数组中移除重复元素
查看>>
Count and Say
查看>>
Gas Station
查看>>
Palindrome Partitioning --回文切割 深搜(重重)
查看>>
Valid Palindrome 简单的回文判断
查看>>
Pascal's Triangle -- 生成杨辉三角
查看>>
Pascal's Triangle II 生成杨辉三角中的某行
查看>>
Minimum Depth of Binary Tree -- 二叉树的最小深度 DFS 加剪枝
查看>>
Climbing Stairs 爬楼梯方法 动态规划
查看>>
Merge Two Sorted Lists 合并两个有序链表
查看>>