计算机算法设计与分析——递归与分治策略(一)

递归:
直接或者间接地调用自身的算法称为递归。用函数自身给出定义的函数成为递归函数。

使用递归技术往往使函数的定义和算法的描述简洁且易于理解。有些数据结构,如二叉树等,由于其本身固有的递归特性,特别适合用递归的形式来描述。另外,还有一些问题,虽然其本身没有明显的递归结构,但用递归技术来求解,可以使得设计出的算法简捷易懂且易于分析。

每个递归函数都必须有非递归定义的初始值,否则,递归函数就无法计算。

递归算法的实例:

阶乘函数:
n!=1 (n=0)
n!=n(n-1)! (n>0)

递归代码:

int faction(int n)
{
if(n==0)
return 1;
else
return n*faction(n-1);
}

Fibonacci数列:
无穷数列1,1,2,3,5,8,13,21,34……,称为Fibonacci数列。

递归代码:

int fibonacci(int n)
{
if(n<=1)
return 1;
else
return fibonacci(n-1)+fibonacci(n-2);
}

Hanoi塔问题

设a,b,c是三个塔座,在塔座a上有一叠共n个圆盘,这些圆盘自下而上,由大到小的叠放在一起,各圆盘从小到大的编号为1,2,……,n。现要求将塔座a上的这一叠圆盘移动到塔座b上,并仍按照同样的顺序叠放,在移动圆盘时应遵守以下的移动规则:
规则(1) 每次只能移动一个圆盘
规则(2) 任何时刻都不允许将较大的圆盘压在较小的圆盘之上
规则(3) 在满足移动规则(1)和(2)的前提下,可将圆盘移动至a,b,c中任何一个塔座上
这个问题有一个简单的解法,假设塔座a,b,c排成一个三角形,构成一个顺时针的循环。在移动圆盘的过程中,若是奇数次移动,则将最小的圆盘移动到顺时针方向的下一个塔座上,若是偶数次移动,则保持最小的圆盘不动,而在其他两个塔座之间,将较小的圆盘移动到另一座塔座上。

运用递归技术解决这个问题,当n=1时,只要将编号为1的圆盘从塔座a直接移动到b就可以了。当n>1时,需要利用塔座c作为辅助塔座,此时要设法将n-1个较小的圆盘依照移动规则从塔座a移动到c,然后将剩下的最大的圆盘从a移动到b,最后再设法将n-1个较小的圆盘依照移动规则从c移动到b。
由此可见,n个圆盘的移动问题可以分解为两次n-1个圆盘的移动问题。这又可以递归的用上述方法来做,所以Hanoi塔的递归算法如下:

void hanoi(int n,int a,int b,int c)
{
if(n>0)
{
hanoi(n-1,a,c,b);
move(a,b);
hanoi(n-1,c,b,a);
}
}

其中,hanoi(n,a,b,c)表示将a上自下而上,由大到小叠放在一起的n个圆盘依照移动规则移动到b上,并且仍然按照同样的顺序叠放。在移动的过程中,以塔座c作为辅助塔座,move(a,b)表示将a上编号为n的圆盘移动到b上。

递归算法总结:

像hanoi这样的递归算法,在执行时需要多次调用自身,实现这种递归调用的关键是为算法建立递归调用的工作栈。通常,在一个算法中调用另一个算法,系统需要在运行被调用算法之前先完成三件事:
(1)将所有实参指针、返回地址等信息传递给被调用算法。
(2)为被调用算法的局部变量分配存储区。
(3)将控制转移到被调用算法的入口。
从被调用算法返回调用算法时,系统也要相应的完成三件事情:
(1)保存被调用算法的计算结果。
(2)释放分配给被调用算法的数据区。
(3)依照被调用算法保存的返回地址将控制转移到调用算法。

递归算法中,当有多个算法被调用时,按照后调用先返回的原则进行。算法之间的信息传递和控制转移必须通过栈来实现,即系统将整个程序运行时所需要的数据空间安排在一个栈区中,每调用一个算法,就为这个算法在栈顶分配一个存储区,每退出一个算法,就释放它在栈顶的存储区。当前正在运行的算法的数据一定在栈顶。递归算法的实现类似于多个算法的嵌套调用,只不过调用算法和被调用算法是同一个算法。

由于递归算法结构清晰,可读性强,且容易被数学归纳法证明算法的正确性,因此它为设计算法、调试程序带来了很大的方便,然而,递归算法的运行效率很低,无论是耗费的计算时间还是占用的存储空间都比非递归算法要多。若在程序中取消递归算法的调用,则其运行时间可以大大的减少。因此,有时希望在递归算法中消除递归调用,使其变成一个非递归算法,例如,采用一个用户定义的栈来模拟系统的递归调用工作栈,从而到达将递归算法改为非递归算法的目的。当然仅仅是机械的模拟还不能达到减少计算时间和减少存储空间的目的,还要根据具体程序的特点对递归调用的工作栈进行简化,尽量的减少工作栈的操作,压缩栈存储空间以达到节省计算时间和存储空间的目的。

你可能感兴趣的:(计算机算法设计与分析——递归与分治策略(一))