1.浅谈递归
接触过算法的人一定听说过递归,因为递归是一种常用的重要算法,其思想被广泛应用于其它算法:如稍微简单的斐波那契数列:
int Fibonacci(int n){
if(n==1||n==2) return 1;
else return Fibonacci(n-1)+Fibonacci(n-2);
}
中等一点的快速排序:
void QuickSort(int[] a,int low,int high){
int i=low;
int j=high;
int temp,t;
temp=a[low];
if(low>=high){
return;
}
while(i<j){
while(temp<=a[j]&&i<j){
j--;
}
while(temp>=a[j]&&i<j){
i++;
}
if(i<j){
t=a[j];
a[j]=a[i];
a[i]=t;
}
}
a[low]=a[i];
a[i]=temp;
QuickSort(a,low,j-1);
QuickSort(a,j+1,high);
}
再高级一点的棋盘覆盖问题和线性时间选择算法(BRPFT)都能用递归去解!!
2.递归的使用条件
谈完了递归的使用方法以及其便捷后,我们可以开始想:遇到一个算法题,我们什么时候去考虑递归或者说如何快速判断能不能、值不值得去用递归呢?
这里会有涉及到两个条件:
(1).能否递推
通俗来说,递归就像打太极,有去咱就得有回,所以前提当然是要能“去“了。其实本质上也是用了”分治“的基本思想,即一个规模为n的问题能否被分为k个规模较小的子问题,且这些子问题相互独立并与原问题相同。重要的就在于能
(2).是否有边界(找到已知不变量)
想想我们为什么要把大问题不断的划分子问题?从哲学高度上说,这很像我们人类从古至今不断追求真理的过程,想即找到永恒的、不变的东西,从变中找不变(当然哲学至今还没找到),因此我们不断把一个大的东西分啊分,直到分到一个我们可以认知到的程度,所以说计算机的抽象思想正是一种哲学高度的体现啊!!!
用阶乘的例子来说吧:
int factorial(int n){
if(n==1||n==0) return 1;
else return n*factorial(n-1);
}
对于阶乘,我们如果以一下问:“同学,8的阶乘是多少!!??”没有记过的同学可能 一下反应不过来。但是假如问:1的阶乘?0的阶乘? 你是不是会会心一笑并不假思索地说,“当然是1啊”。注意,到这一步,我们能不假思索的这一步,便可以称作一个“永恒不变者”或者说“人人知道者”。因此阶乘便成为了这样的一个思想:如果要求8的阶乘,那先求7的阶乘嘛,到时再用8乘以7阶乘就行;欸?7阶乘也不会啊,那就先求7的阶乘吧,到时再用7乘6的阶乘吧;欸!??6阶乘我也不会啊!?那就继续,先求5的阶乘吧。。。。。。然后一直推啊推啊,推到哪了呢?欸!!!好家伙,到1阶乘了啊。。欸我去!这我可终于知道了呀,不就是1嘛!!好了,既然去到这里了,那我是时候得“回去”了。然后脑瓜想想:可把我累坏了呀!现在1的阶乘知道了,那我就知道了2的阶乘咯(2×1=2)!咦,2的阶乘知道,那3的阶乘我也能知道(2×3=6) 4的用3阶乘(6×3=18)。。。。。。欸!!回到了8阶乘了,那结果,是不是自然而然地就出来了呢?我们人这样算可能有点傻,有些脑快的可能直接从8开始乘一直乘到1,毕竟有阶乘公式嘛!但计算机而言,它可不知道啥数学公式,活生生智商不高的傻子,但是,人家记忆力好啊!!只要用上述先把不知道的存起来,直到让它挖到了不变量,再一个个代入(迭代),不能算出来!!!
同样的,像斐波那契数列、快速排序算法、归并排序算法等等等等,它们能用到递归,就是因为能找到边界的不变量,再从不变量把之前的变量一个个化解为不变量(这里有点绕,但能耐心想下是能想出来的)
3,递归的规律套路
这里简单提一嘴,虽然本人也不是说完全精通递归,把所有有关递归题都做了个遍,但也做了不少于三位数了。有个小规律:函数用到递归的,那一定是有if语句的!!(也不知道这句话是不是废话,但小白看了应该会有用)。不信可以翻翻我上面给出的所有有关的递归例子,看看这些函数的前几行是不是就先用了个if来设定边界条件。所以,用到递归函数,一开始,直接就想边界!!
4.最后总结
递归真的妙处多多,不但便于简化算法,更体现了人的一种高智慧抽象思维:大而化小,小而化了嘛!当然,我这里说的也只是个大概,更多相关的细节我后面还会一一补充。最后,纸上谈兵可不行,学计算机的,那必然要敲代码,用马克思思想:理论指导实践。多敲代码,要从矛盾中发现问题,才能不断地发展前行!!!