递归小论(2)

来源:互联网 发布:打印机的端口名是什么 编辑:程序博客网 时间:2024/06/05 14:18

请扫码加公众号大笑



上次简单介绍了一下什么是递归,这一次来说说递归的难点作用

 

 

不记得上次是否有说过,递归是一个衡量程序员是否成熟的标识。

 

然而我到现在在递归上做得最远的也仅仅是把插入排序二分搜索之类的改成递归写法,其余啥都没有,所以水平有限。

 

因为递归真的是嗨难嗨难。

 

 

递归难点1:在解决问题的时候把大问题改造成一个小问题(开始难)

上次有提到过分治法。分治,分治,分在先,治在后。

然而,分这个过程是很难决定的。

 

二分搜索啊,归并排序啊这些都还算正常的思路,毕竟一半一半的考虑是人类思考一种普遍方式。

 

这种一半一半的分布源于在于往往人们会把分布想象成均匀分布.

 

然而,糟糕的事情在于,问题空间往往并不是均匀分布的,就想在自然界中最普遍的分布并不是均匀分布,而是用起来极其麻烦并且还是连续的正态分布。

 

矩阵的乘法一直是计算机内很难解决的效率问题,因为到现在高效的算法效率才达到N^(lg7)也就是在N^(2. 8)左右(Strassen算法),也就是说比最慢的插入排序还慢。然而,为了减少这0.2次的效率,算法在处理矩阵的把原问题化为了7个子问题。7个,7个子问题,想着7个子问题得耗费多少心血(说实在的,我到现在都没想出创始人是怎么想出7等分这样精分的分解方法)

 

所以,问题空间并不均匀造成分解这一步往往就会遇到困难。

(事实上,在递归入门的时候最经典的两个一个就是汉诺塔,一个就是阶乘。阶乘尚且容易理解,也容易写出来。然而汉诺塔,我觉得能把问题往递归方面想,太难了……)

 

递归难点2:递归的底层是什么(中间难)

不同的分解方式会造成最终计算机停止的地方不同,就如阶乘,计算机会停留在N=0的情况,这是非常确定的。

 

然而,随着分解的方法不断复杂,递归底层变得并不容易那么确定。

 

递归底层可能有两种情况比如N=0,N=-1

递归底层还有可能是left>right

递归底层还有可能是NULL=object

 

如果分解方法简单,最后的底层往往就是一个,然而简单的分解结构就是效率的低下,甚至出现用递归还不如不用的情况(比如阶乘的例子被人嘲笑诟病了很久很久)

 

最麻烦的是,有时候你根本就很难猜到底层是啥……

为什么? 因为有一种技术叫随机化……(获得概率上期望最佳也就是平均效率最后,将要讲的随机化快速排序即是如此)

当把算法随机化以后,所有的事情全靠运气了   为人事,尽天命吧。

 

 

递归难点2:合并算法(最后,还是,难)

当想出一些天马行空无厘头的分解方法以后,计算机也就会帮你一路走到底直接走到并不一定知道的递归的底层,然后也就停下来了。

 

这蠢机器并不知道怎样从底层走回原来最开始的调用……

 

所以这时候就要设计算法把底层合并起来解决(其实并不是简单的底层合并,而是类似1并2, 2并4 , 4并8 这样的滚雪球解决,所以合并算法还要考虑到规模问题……)

 

之前有说过归并排序的合并算法,那个算法说实话还不算复杂,但是作为一个算法来说,代码长度并不短(可能是我写的不好)

 

糟糕的是,归并排序的合并算法是一个比较轻松的合并算法……

 

因为篇幅问题,合并算法的难点直接列出来吧,如果有兴趣可以后台留言,下次我在详细说明

合并算法必须知道底层是怎么样的

合并算法必须得根据回归过程对数据操作改变规模

合并算法在时间问题上必须要最小,如果它慢,整个算法不可能快,它是决定算法快慢的灵魂(也是递归的灵魂)

合并算法还得会处理两个不同规模的数据(比如一个数据有7个元素,另一个数据有100个元素),不同规模数据出现是经常发生的

 

综上而述,递归开头难,中间难,最后还是难。

 

 

但是,调用递归简单呀,比如你有一个aRecursion()函数,怎样递归呢

aRecursion()

{

 

    statement

    aRecursion()

}
0 0