3.7栈与递归(下)----递归与非递归转换

3.7栈与递归(下)----递归与非递归转换

1、递归算法到非递归算法的转换

递归算法具有两个特性:
①递归算法是一种分而治之、把复杂问题分解为简单问题的求解问题方法, 对求解某些复杂问题,递归算法的分析方法是有效的。
②递归算法的效率较低。 为此,在求解某些问题时,希望用递归算法分析问题,用非递归算法求解具体问题。

(1)消除递归的原因:

  • 其一,有利于提高算法时空性能,因为递归执行时需要系统提供隐式栈实现 递归,效率较低。
  • 其二,无应用递归语句的语言设施环境条件,有些计算机语言不支持递归功 能,如 FORTRAN 语言中无递归机制 。
  • 其三,递归算法是一次执行完,中间过程对用户不可见,这在处理有些问题时不合适,也存在一个把递归算法转化为非递归算法的需求。 理解递归机制是掌握递归程序技能必要前提。消除递归要基于对问题的分析,常用的有两类消除递归方法。
  • 一类是简单递归问题的转换,对于尾递归和单向递归的算法,可用循环结构的算法替代。
  • 另一类是基于栈的方式,即将递归中隐含的栈机制转化为由用户直接控制的明显的栈。利用堆栈保存参数,由于堆栈的后进先出特性吻合递归算法的执行过 程,因而可以用非递归算法替代递归算法。

(2) 简单递归的消除

在简单情况下,可以将递归算法转化为线性操作序列,直接用循环实现

①单向递归

  • 单向递归是指递归函数中虽然有一处以上的递归调用语句,但各次递归调用语句 的参数只和主调用函数有关,相互之间参数无关,并且这些递归调用语句处于算法的最后。

3.7栈与递归(下)----递归与非递归转换_第1张图片
计算斐波那契数列的递归算法如下:

 Fib(int n)      
{        
	if(n= =0||n= =1return n;        /* 递归出口 */        
	else  
		return Fib(n-1)+Fib(n-2);      /* 递归调用 */      
 } 

3.7栈与递归(下)----递归与非递归转换_第2张图片
上图中 15 个点表示 15 次运算,如果合并重合点,按图 3.13 所示粗黑线,用循环实现计算,仅需要 5 次运算。
3.7栈与递归(下)----递归与非递归转换_第3张图片
计算斐波那契数列的非递归算法如下:

int Fib(int n) 
{ 
	int  x, y, z; 
	if(n= =0||n= =1return n;    /*计算 Fib (0)或 Fib(1) */         
	else 
	{  
		x=0, y=1;             /* x= Fib (0)  y= Fib (1) */ 
		for(i=2; i<= n; i++ ) 
		{ 
			z=y;      /*  z= Fib (i-1)  */         
			y=x+y;    /*  y= Fib (i-1)+ Fib (i-2)  求 Fib (i) */         
			x=z;      /*  x= Fib (i-1) */ 
		} 
	return y ; 
	} 
} 

用循环方式计算 Fib(n)时,Fib(i) (i=2…n)是在已计算过 Fib (i-1)与 Fib (i-2)的基础上进行的,无重复计算,时间复杂度为 O(n)。

虽然非递归算法没有递归算法直观,但时空耗费远少于递归算法。

而用递归方式计算 Fib (n)时,必须计算 Fib (n-1)与 Fib (n-2),而某次递归计算得出的结果,如 Fib (3)无法保存,下一次要用到时还需要重新递归计算,因此其时间复杂度为 O(2n)。(n次方)

②尾递归

尾递归是指递归调用语句只有一个,而且是处于算法的最后,尾递归是单向递归的特例。

以阶乘问题的递归算法 Fact(n)为例讨论尾递归算法的运行过程。为讨论方 便,列出阶乘问题的递归算法 Fact(n),并简化掉参数 n 的出错检查语句,改写递归调用语句的位置在最后,算法如下:

long Fact(int n) 
{         
	if(n= =0)  
		return 1;         
	return  n*Fact(n-1); 
} 

分析上述算法可以发现,当递归调用返回时,返回到上一层递归调用的下一 语句,而这个返回位置正好是算法的末尾。

也就是说,以前每次递归调用时保存的返回地址、函数返回值和函数参数等实际上在这里根本就没有被使用。

因此, 对于尾递归形式的递归算法,不必利用系统的运行时栈保存各种信息。尾递归形式的算法实际上可变成循环结构的算法。

循环结构的阶乘问题算法 Fact(n)如下:

long Fact (int n) 
{ 
	int fac=1;     
	for(int i=1;i<=n;i++)   /*依次计算 f(1)… f(n)*/    
		fac=fac* i;        /* f(i)= f(i-1)*i */         
	return fac; 
} 

你可能感兴趣的:(笔记)