7.3.3 递归的优缺点及是否必须用递归
递归的优点可以用一句话来总结:代码少,所以代码看起来特别简洁,感觉也挺精妙。
递归的缺点,可以用三条来总结。
(1)虽然代码简洁,代码也精妙,但代码理解起来比较有难度。
(2)如果调用层次太深,调用栈(保存函数调用关系等需要用到的内存)可能会溢出,如果真出现这种情况,那么说明不能用递归调用解决该问题。例如,可以自己演示一下计算50000的阶乘,堆栈会溢出,结果也会溢出,但结果溢出与否不重要,关注的重点是堆栈的溢出,也就是内存装不下这么多层调用了,此时,程序执行并等待几秒钟后,程序要么报告异常,要么无征兆地退出。总之一句话:程序运行不正常。
(3)效率和性能都不算高。这么深层次的函数调用,调用中间要保存的内容也很多,所以效率和性能肯定高不起来。
那么,递归这种调用手段是必须使用的吗?这个问题分两方面来说:
(1)有些问题,可以用递归解决也可以不用递归解决,如上面举的计算5的阶乘的例子,其实,写个循环来解决也是可以的。
(2)有些问题,可能必须用递归解决,至于什么问题必须用递归解决,笔者不能以绝对的口吻来回答,随着读者日后C++使用经验的逐步丰富,自己来寻找答案更合适。比较典型的如汉诺塔问题,是一个典型的递归用法题,但也有人写出了非递归的程序代码,如果有兴趣,可以在网上搜索和研究一下。
总结一下:具体情况具体分析,根据经验,递归不常用,但有些地方不得不用,因为想不到更好的解决办法。
这里穿插一个递归函数直接调用和间接调用的概念。
(1)递归函数直接调用:调用递归函数f的过程中,f函数又要调用f函数(自己调用自己)。这就是上面已经讲过的函数递归调用形式,也就是直接调用,如图7.5所示。
(2)递归函数间接调用:调用递归函数f1过程中要调用f2函数,而在调用f2函数过程中又要调用f1函数,如图7.6所示。
图7.5 递归函数的直接调用
图7.6 递归函数的间接调用