一:何为递归
我的理解是自己调用自己,但是调用的时候把整体的规模缩小了,最后规模少到一定程度的时候就可以显然的得出答案。
例如:
有一个数组 A[10]={1,2,3,4,5,6,7,8,9,10} ,现在想求这个数组每个元素的和,正常的思想是全都加起来就完事儿了,这里为了诠释递归,所以要用递归的思想来解决:
递归的思想是这样的:数组前10项的和=数组第10项+数组前9项的和
数组前9项的和=数组第9项+数组前8项的和 …
用数学式子表达就是:f(10)=A[9]+f(9)=A[9]+A[8]+f(8)=…
到最后我们可以很清楚的看到,f(0)=0。
所以啊,递归就是将一个大规模的问题分解成小问题,直到问题小到可以直接求解的时候,然后将小问题整和起来就解出大问题啦。
总结一下,递归的要素:
1:问题要变小。
2:小问题要能解出来
上面的这个小例子的代码如下:
#include<stdio.h>
int f(int *A,int n){
if(n==0){
return 0;
}
return A[n-1]+f(A,n-1);
}
int main(void){
int A[10]={1,2,3,4,5,6,7,8,9,10};
printf("%d\n",f(A,10));
return 0;
}
二:何为理所当然
个人觉得,递归的精髓在于理所当然,那什么叫做理所当然呢,我的理解是:只要逻辑是对的,就不用管电脑是怎么操作的,我们只管逻辑。
这里的逻辑包括了:程序的逻辑 和 出口的逻辑,两者缺一不可。
下面用一个快速排序来阐述一下这个理所当然:
快速排序
快速排序的逻辑是:把排序的数组用某种方法切成两边,使得左边的数都比较小,右边的数都比较大,如下图所示:
下面介绍快速排序的精髓:整体有序等于左边有序加上右边有序。
下面用代码阐述理所当然:
一:引出quicksort函数,参数有数组指针、排序起始位和排序终止位。
int main(void){
int A[10]={9,6,79,8,2,5,1,3,5,4};
quicksort(A,0,9); //排序撒,对A的第0个元素到第9个元素进行排序
return 0;
}
二:quicksort的实体
void quicksort(int *A,int left,int right){
int q;
q=divide(A,left,right);//这个是切分数组的方法,返回一个位置,在此位置之前的元素都小,之后的元素都大
quicksort(A,left,q-1);//对左边进行排序!
quicksort(A,q+1,right);//对右边进行排序!
return;
}
此代码中divide有多种方法,但是本文章主要讲递归,就不讲具体的方法了。
神奇~~
在逻辑上,总之,quicksort(A,left,right)就是对数组A从left到right进行排序,所以在调用完quicksort(A,left,q-1)的时候,我们就理所当然的可以认为左边已经排好序了,同理quicksort(A,q+1,right)也是这样,当左边和右边都排好序了的时候,整个数组就有序了。
我们继续仔细想想,上边说的逻辑除了程序的逻辑外,还有出口的逻辑,那么这边出口的逻辑是什么呢,我认为出口的逻辑是问题小到可以轻松解出来的时候,像这个快速排序,问题小到什么时候可以很容易的就排好序呢,答案是:只有一个元素的时候(即left=right时)或者没有元素的时候(即left>right时),因为这时就不用排了撒,我们必须在递归中加入出口逻辑:
void quicksort(int *A,int left,int right){
int q;
if(right>left){ //出口逻辑
q=divide(A,left,right);
quicksort(A,left,q-1); //对左边进行排序!
quicksort(A,q+1,right); //对右边进行排序!
}
return;
}
未完待续~~