c语言递归函数怎么理解,C语言中的递归函数,我觉得好难懂,这正常吗?你们觉得难吗?

我也这么觉得哈哈,我当初学习 C 语言时,觉得最难的就是“递归”了,比指针还难理解(C 语言中的指针,很多人都认为难以理解)。

c语言递归函数怎么理解,C语言中的递归函数,我觉得好难懂,这正常吗?你们觉得难吗?

那什么是“递归”呢?

我有一天翻词典时,看到词典这么解释一个词:

惊人的:用来形容惊人的形容词。

这要么是恶搞,要么就是玩笑。然而在数学上确实有很多概念是用自己定义的,举个例子:n 的阶乘等于 n 乘以 n-1 的阶乘,并且 0 的阶乘等于 1。咋一看,似乎它并没有说清楚什么是阶乘,但是这样的描述,却足以让人知道怎样计算阶乘。例如计算 4 的阶乘:

4! = 4 x 3!
= 4 x 3 x 2!
= 4 x 3 x 2 x 1!
= 4 x 3 x 2 x 1 x 0!
= 4 x 3 x 2 x 1 x 1
= 24

并不用细究阶乘到底是什么,只需要按照定义去计算即可,当然,这种定义方式必须要有一个“基础条件”,比如阶乘的“基础条件”就是 0! = 1。如果没有“基础条件”,阶乘只会无限往下推,没有尽头。

c语言递归函数怎么理解,C语言中的递归函数,我觉得好难懂,这正常吗?你们觉得难吗?

C 语言中,什么是递归函数?

说了半天阶乘,就是为“递归”做铺垫的,如果一个概念需要用到自身,我们就称它的定义是递归的。那显然,递归函数一定是调用了自身的函数,这么说有点虚,来看看实例吧,下面用 C 语言计算 n 的阶乘。我们已经知道,递归最重要的就是“基础条件”了,我们先把阶乘的基础条件写好:

c语言递归函数怎么理解,C语言中的递归函数,我觉得好难懂,这正常吗?你们觉得难吗?

上面的代码实现了 0 的阶乘等于 1,那如果 n 大于 0 呢?按照阶乘的定义,应该是 n x fatorial(n-1),用代码实现就是:

c语言递归函数怎么理解,C语言中的递归函数,我觉得好难懂,这正常吗?你们觉得难吗?

这就用 C 语言实现了计算 n 的阶乘。factorial 函数调用了自己,所以 factorial 是递归函数。事实上,不仅仅是直接调用自己,间接调用自己也属于递归函数。比如,A 调用了函数 B,函数 B 又调用了 A,那 A 也是递归函数。

c语言递归函数怎么理解,C语言中的递归函数,我觉得好难懂,这正常吗?你们觉得难吗?

那,递归函数是怎么执行的呢?

为了方便解释,我们在 factorial 函数的else 部分加几个局部变量:

c语言递归函数怎么理解,C语言中的递归函数,我觉得好难懂,这正常吗?你们觉得难吗?

这里以 factorial(3) 为例,用实线箭头表示调用,用虚线箭头表示返回,右边的框表示在调用和返回过程中各函数调用的局部变量的变化情况。

c语言递归函数怎么理解,C语言中的递归函数,我觉得好难懂,这正常吗?你们觉得难吗?

我们看图右边表示存储空间的框的变化过程,随着函数调用的层层深入,存储空间的一端逐渐增长,然后随着函数的层层退出,存储空间的这一端又逐渐缩短,这是一种具有特定性质的数据结构。

它的特性就是只能在某一端增长或缩短,并且每次访问参数和局部变量时只能访问这一末端的单元,而不能访问内部的单元,比如当factorial(2)的存储空间位于末端时,只能访问它的参数和局部变量,而不能访问factorial(3)和main()的参数和局部变量。

具有这种性质的数据结构称为堆栈或栈(Stack)。每个函数调用的参数和局部变量的存储空间(图里的一个小方框)称为一个栈帧(Stack Frame)。系统为每个程序的运行预留了栈空间,函数调用时就在这个栈空间里分配栈帧,函数返回时就释放栈帧。

c语言递归函数怎么理解,C语言中的递归函数,我觉得好难懂,这正常吗?你们觉得难吗?

可以看出,写 C 语言递归函数最重要的就是一定要定义好“基础条件”,不然函数就会永远调用下去,知道系统资源耗尽程序崩溃为止。递归和循环是等价的,用循环能做的事用递归都能做,反之亦然,事实上有的编程语言(如某些LISP)只有递归而没有循环。

计算机硬件能做的所有事情就是数据存取、运算、测试和分支、循环(或递归),在计算机上运行的高级语言写的程序当然也不可能做到更多的事情,虽然高级语言有丰富的语法特性,但也只是为做这些事情提供一些方便。那么,为什么计算机是这样设计的?为什么想到计算机需要具有这几种功能,而不是更多或者更少?这些要归功于早期的计算机科学家,例如Alan Turing,他们在计算机还没有诞生的年代从数学理论上为计算机的设计指明了方向。

c语言递归函数怎么理解,C语言中的递归函数,我觉得好难懂,这正常吗?你们觉得难吗?

欢迎在评论区一起讨论,质疑。文章都是手打原创,每天最浅显的介绍C语言、linux等嵌入式开发,喜欢我的文章就关注一波吧,可以看到最新更新和之前的文章哦。

如何对递归进行理解?

你既然要求用简单的大白话解释递归算法,那么,我就给你解释一下,保证让你明白。

有一个耳熟能详的故事,恰好可以说明递归。

从前有座山,山上有座庙,庙里有个老和尚和一个小和尚,老和尚正在给小和尚讲故事:{从前有座山,山上有座庙,庙里有个老和尚和一个小和尚,老和尚正在给小和尚讲故事:【从前有座山,山上有座庙,庙里有个老和尚和一个小和尚,老和尚正在给小和尚讲故事:[从前有座山,山上有座庙,庙里有个老和尚和一个小和尚,老和尚正在给小和尚讲故事:()......]】}

这个故事不断地调用自身,而递归就是函数调用自身若干次。所不同的是,递归不能像这个故事一样无限次数的调用自身,递归必须有一个终止条件,调用若干次后就终止。

这个解释,够白话了吧。

在学习数据结构与算法的时候,一旦出现递归就很难理解,对于递归有没有什么好的理解方法?

哈哈,这种情况跟当年初学编程的我一样啊。

首先,你既然能问出来这个问题,我假定你已经看了一些递归的程序例子了,而不是只看了定义就来谈这个(要是你真没看,就先去看吧)

然后,在递归里,有一个很重要的东西,就是递归的退出条件,这个东西是所有递归算法理解的基础,递归一定有退出条件,不然就必定导致程序永远执行不完。退出条件就是这个递归的程序跑到什么情况的时候,就不继续调用自己了。这个退出条件可能是递归的次数,也可能是判断某个数是不是够大,或者不再有子结点,等等。通常如果你看到的递归函数里有两个或两个以上的return(比如像 if A return X else return 函数自己),那么不是return函数自己的那行就是退出条件了。

找到退出条件以后,剩下的就简单了,你把退出条件以外的部分拆成一摸一样的函数来理解就可以了。举例子,有个递归函数F(int x),返回段有一句是return F(k),那么你这样改写:

F1(int x),F2(int x),F3(int x)

函数体都一样,抄F(int x)的就行,只是把那个return那里改一下,原来的return F(k)在F1中改成return F2(k),F2中改成return F3(k),总之就是不断引下一个函数来执行就行。

然后你就发现,反正函数体都一样,我干嘛要这么sb把这函数写N遍,直接return自己不就好了!

你能读懂到这里,你就已经能理解了,还不理解就找个例程按我上面说的自己拆开写一下。

递归,其实就是:从前有座山,山顶有座庙,庙里有个老和尚,正在讲故事,讲什么故事?他讲:“从前有座山…

然后这个故事整体达到5000字的时候就不继续了,这个5000字就是退出条件了。

理解心得是:1 不要顺着分析,先找退出条件,这极大有利于你理解这个算法为什么这样写而递归只是其中的过程而已 2 读不明白程序时把那个递归函数拆成三个一样的, 用迭代来连起来,假定在第三个的时候,退出条件达到了,不再递归/迭代,这样的情况下再理解。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 xxx@163.com 举报,一经查实,本站将立刻删除。

发表评论

登录后才能评论