您的位置:首页 > 编程语言 > C语言/C++

解惑:迭代与递归

2013-12-06 11:43 330 查看
(一)迭代法

迭代法也称辗转法,是一种不断用变量的旧值递推新值的过程。迭代算法利用计算机运算速度快、适合做重复性操作的特点,让计算机对一组指令(或一定步骤)进行重复执行,在每次执行这组指令(或这些步骤)时,都从变量的原值推出它的一个新值,是用计算机解决问题的一种基本方法。

迭代常用循环实现。

例1:分析下面的程序的功能

[cpp] view
plaincopyprint?

int main(void)  

{  

          int x;  

          cin>>x;  

          while(x>0)  

          {  

                   cout<<x%10;  

                   x=x/10;  

       }  

          cout<<endl;  

}  

通过走查不难发现,输出的是x的倒序数。例如输入的x值为358,输出853。

在循环中,每一次迭代,x的数值都变小,直至为0结束循环,而在迭代中,每次都取出当前的最后一位数输出,于是x中的各位数,越靠后的越先输出,最终输出的是x的倒序数。

思考:如果将例子中的10换成2、8或16呢?

输出的结果自然是x对应的2、8或16进制数的倒序数。

联想到十进制数转换为其他进制数的方法。以转换为2进制数为例,方法为除2取余法,且最后得到的余数应在前面。我们将前面的迭代过程稍做修改,引入数组暂存余数解决此问题。

参考程序如下:

[cpp] view
plaincopyprint?

int main(void)  

{  

          int x, n=0, a[50];  

          cin>>x;  

          while(x>0)  

          {  

                   a
=x%2;  

                   x=x/2;  

                   n++;  

       }  

          for(int i=n-1;i>=0; i--)  

                   cout<<a[i];  

          cout<<endl;  

}  

还有一种迭代法叫近似迭代法,常用于数值计算中,如弦截法求解方程(p106例4.9)。例子中)重复步骤(2)和(3),直到|f(x)|<ξ(ξ为一个很小的正数)为止, 此时认为 f(x)≈0,获得了f(x)=0的近似解x。这个过程就是迭代。

请阅读下面的函数,其中f(x)是任意的方程,且调用时,要保证f(x1)和f(x2)异号。

[cpp] view
plaincopyprint?

double root(double x1, double x2)     

{  

          double x,y,y1;  

          y1=f(x1);  

          do  

          {  

                   x=xpoint(x1,x2);   

                   y=f(x);                       

                   if(y*y1>0)  

                   {        y1=y;  

                            x1=x;  

                   }  

                   else  

                            x2=x;  

          }while(fabs(y)>=0.00001);  

          return x;  

}  

总结:利用迭代算法解决问题,需要做好以下三个方面的工作[1]:

1、确定迭代变量。在可以用迭代算法解决的问题中,至少存在一个直接或间接地不断由旧值递推出新值的变量,这个变量就是迭代变量。

2、建立迭代关系式。所谓迭代关系式,指如何从变量的前一个值推出其下一个值的公式(或关系)。迭代关系式的建立是解决迭代问题的关键,通常可以使用递推或倒推的方法来完成。

3、对迭代过程进行控制。在什么时候结束迭代过程?这是编写迭代程序必须考虑的问题。不能让迭代过程无休止地重复执行下去。迭代过程的控制通常可分为两种情况:一种是所需的迭代次数是个确定的值,可以计算出来;另一种是所需的迭代次数无法确定。对于前一种情况,可以构建一个固定次数的循环来实现对迭代过程的控制;对于后一种情况,需要进一步分析出用来结束迭代过程的条件。

 

(二)递归法

递归是计算机科学中的一种重要方法。

能采用递归描述的算法通常有这样的特征:为求解规模为N的问题,设法将它分解成规模较小的问题,然后从这些小问题的解方便地构造出大问题的解,并且这些规模较小的问题也能采用同样的分解和综合方法,分解成规模更小的问题,并从这些更小问题的解构造出规模较大问题的解。特别地,当规模N=1时,能直接得解。

例如求n!,由n!=n*(n-1)!,且1!=1,容易写出下面的函数:

[cpp] view
plaincopyprint?

long fact(int n)  

{  

         long f;  

       if (n==1)  

                   f=1;  

       else  

                   f=n*fact(n-1);                   

       return f;                            

}  

递归函数在执行过程中,有一个递推的过程,求fact(n)先求fact(n-1),求fact(n-1)先求fact(n-2),……。在求得fact(1)=1后,再回归回去,求出fact(2)、fact(3)……直到得出fact(n)。递归,由递推和回归两个阶段组成。

递归不仅可以用于计算此类形式的问题。实际上,所有用迭代可以完成的任务用递归也可以完成,所有用递归完成的任务也可以用迭代完成。一般而言,递归更容易表达(人的效率),而迭代的执行效率更高(机器的效率)。递归程序的执行效率低是由于每一次敲击用函数都需要在计算机内保存相关的运行环境,既费时间又占空间,尤其是有些递归需要执行很多“层次”。所以在实践中,常用递归将问题分析清楚了,写出迭代程序来求解。

用递归的思路求解问题,需要找出这种递推和回归的过程来。

对比例1,我们给出相同功能的递归实现。

[cpp] view
plaincopyprint?

int main(void)  

{  

         int x, n;  

         cin>>x;  

     f(x);  

         cout<<endl;  

         return 0;  

}  

void f(int a)  

{  

         if (a==0)  

                   return;  

         else  

       {  

                   cout<<a%10;          //(1)  

                       f(a/10);              //(2)  

       }  

}  

请自行分析,输入x的值为358,输出将是?

试图实现十进制向二进制的转换,要保证对2取余数后,按照倒序取出来,需要将(1)、(2)两句换一下位置。即:

[cpp] view
plaincopyprint?

void f(int a)  

{  

         if (a==0)  

                   return;  

         else  

       {  

                   f(a/2);                //(2)  

                   cout<<a%2;  //(1)  

       }  

}  

为什么?走查一遍就清楚了。

最后总结,递归的基本概念和特点[1]:

程序调用自身的编程技巧称为递归( recursion)。

一个过程或函数在其定义或说明中又直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。用递归思想写出的程序往往十分简洁易懂。

一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。

注意:

(1) 递归就是在过程或函数里调用自身;

(2) 在使用递增归策略时,必须有一个明确的递归结束条件,称为递归出口。

原文地址:http://blog.csdn.net/sxhelijian/article/details/7100443
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息