分支转向是算法的灵魂;函数和过程及其之间的相互调用,是在经过抽象和封装之后,实现分支转向的一种重要机制;而递归这是函数和过程调用的一种特殊形式,即允许函数进行自我调用。
递归的价值在于,许多应用问题都可简洁而准确地描述为递归形式。
递归也是一种基本而典型的算法设计模式。这一模式可以对实际问题中反复出现的结构和形式做高度概括,并从本质层面加以描述与刻画,进而导出高效的算法。从程序结构的角度,递归模式能够统筹纷繁多变的具体情况,避免复杂的分支以及嵌套的循环,从而更为简明的描述和实现算法,减少代码量,提高算法的可读性,保证算法的整体效率。
线性递归
int sum(int A[], int n) { //数组求和算法(线性递归版) if(n < 1) //平凡情况,递归基 return 0; //直接(非递归式)计算 else return sum(A, n -1) + A[n - 1];//递归:前n-1项和,再累积 第 n -1 项 }
减而治之
线性递归的模式,往往对应于所谓减而治之(decrease-and-conquer)的算法策略:递归没深入一层,待求解问题的规模都缩减一个常数,直至最终蜕化为平凡的小(简单)问题。
按照减而治之策略,此处随着递归的深入,调用参数将单调地线性递减。因此无论最初输入的n有多大,递归的总次数都是有限的,故算法的执行迟早会终止,即满足有穷性。当抵达递归基时,算法将执行非递归计算。
void reverse( int* A, int lo, int hi) { //数组倒置(多递归基递归版) if(lo < hi){ swap(A[lo], A[hi]); //交换A[lo]和A[hi] reverse(A, lo + 1, hi -1); //递归倒置A(lo, hi) }// else 隐含了两种递归基 }
递归消除
void reverse( int* A, int lo, int hi){ //数组倒置,直接改造得到的非递归版 while( lo < hi){ swap(A[lo], A[hi]);//交换A[lo]和A[hi] lo ++; hi --;//收索待倒置区间 } }
二分递归
分而治之:将大的问题分解为若干规模更小的问题,再通过递归机制分别求解。这种分解持续进行,直到子问题规模缩减至平凡情况。这也就是所谓的分而治之(divde-and-conquer)。
int sum( int A[], int lo, int hi){//数组求和方法(二分递归版) if(lo == li)//如遇到递归基(区间长度已将为1),则 return A[lo];//直接返回该元素 else{ int min = (lo + hi) >> 1; //以居中单元为界将原区间一分为2 return sum(A, lo, mi) + sum(A, mi + 1, hi); //递归对 各子数组求和,然后合计。 } }