【万字总结】探讨递归与迭代的区别与联系及如何求解10000的阶层

递归和迭代

这两个概念也许很多童鞋依旧分不清楚,下面通过求解斐波那契数来看看它们俩的关系吧。

斐波那契数的定义:

f0=0

f1=1

fi=fi?1+fi?2(i>1)

递归:

(factorial 6)
(* 6 (factorial 5))
(* 6 (* 5 (factorial 4)))
(* 6 (* 5 (* 4 (factorial 3))))
(* 6 (* 5 (* 4 (* 3 (factorial 2)))))
(* 6 (* 5 (* 4 (* 3 (2 (factorial 1))))))
(* 6 (* 5 (* 4 (* 3 (* 2 1)))))
(* 6 (* 5 (* 4 (* 3 2))))
(* 6 (* 5 (* 4 6)))
(* 6 (* 5 24))
(* 6 120)
720

迭代:

(factorial 6)
(factorial 1 1 6)
(factorial 1 2 6)
(factorial 2 3 6)
(factorial 6 4 6)
(factorial 24 5 6)
(factorial 120 6 6)
(factorial 720 7 6)
720

递归的核心在于:不断地回到起点。

迭代的核心在于:不断地更新参数。

在下面的代码中:

递归的核心是sum的运算,sum不断的累乘,虽然运算的数值不同,但形式和意义一样。

而迭代的核心是product和counter的不断更新。如上表中,product就是factorial的前2个参数不断的累乘更新成第一个参数;而第二个参数则是counter,其不断的加1来更新自己。

product <- counter * product
counter < - counter + 1
#include <iostream>

using namespace std;

int factorialRecursive(int n);
int factorialIteration(int product, int counter, int max_count);

int main()
{
    int n;
    cout<<"Enter an integer:"<<endl;
    cin>>n;
    cout<<factorialRecursive(n)<<endl;
    cout<<factorialIteration(1,1,n)<<endl;

    return 0;
}

int factorialRecursive(int n)
{
    int sum=1;
    if(n==1)
        sum*=1;
    else
        sum=n*factorialRecursive(n-1);
    return sum;
}

int factorialIteration(int product, int counter, int max_count)
{
    int sum=1;
    if(counter>max_count)
        sum*=product;
    else
        factorialIteration((counter*product),(counter+1),max_count);
}

补充问题:

关于上面的factorialIteration函数,今天收到一份邮件,我也通过再次分析学到了很多,这里罗列一下。



第一个问题:

首先来看相对简单的问题,该童鞋在函数内以两种不同方式加上another_sum=2却有着不同的结果。

int factorialIteration(int product, int counter, int max_count)
{
    int sum=1;
    int another_sum=2;
    if(counter>max_count)
    {
        sum*=product;
        another_sum*=product;
    }
    else
        factorialIteration((counter*product),(counter+1),max_count);
}
int factorialIteration(int product, int counter, int max_count)
{
    int sum=1;
    int another_sum=2;
    if(counter>max_count)
    {
        another_sum*=product;
        sum*=product;

    }
    else
        factorialIteration((counter*product),(counter+1),max_count);
}

因为这个函数声明的是int型的返回类型,但没有用return语句,所以C++自动将其运行的最后一行语句作为了返回语句。所以这两个函数类似于:

int factorialIteration(int product, int counter, int max_count)
{
    int sum=1;
    int another_sum=2;
    if(counter>max_count)
    {
        sum*=product;
        return another_sum*=product;
    }
    else
        factorialIteration((counter*product),(counter+1),max_count);
}

int factorialIteration(int product, int counter, int max_count)
{
    int sum=1;
    int another_sum=2;
    if(counter>max_count)
    {
        another_sum*=product;
        return sum*=product;
    }
    else
        factorialIteration((counter*product),(counter+1),max_count);
}

然而我在CodeBlocks中写的代码不用return是可以的,但在Visual Studio中却是会报错的。

有了这个发现,我原来的代码也可以这样来写:

#include <iostream>

using namespace std;

int factorialRecursive(int n);
int factorialIteration(int product, int counter, int max_count);

int main()
{
    int n;
    cout<<"Enter an integer:"<<endl;
    cin>>n;
    cout<<factorialRecursive(n)<<endl;
    cout<<factorialIteration(1,1,n)<<endl;

    return 0;
}

int factorialRecursive(int n)
{
    int sum=1;
    if(n==1)
        sum*=1;
    else
        sum=n*factorialRecursive(n-1);
    // return sum;   // 去掉这里的return语句
}

int factorialIteration(int product, int counter, int max_count)
{
    int sum=1;
    if(counter>max_count)
        return sum*=product;   // 在这里加上return语句
    else
        factorialIteration((counter*product),(counter+1),max_count);
}


现在来看另一个问题:

#include <iostream>
using namespace std;

int test(int n);
int sum;

int main()
{
    cout<<test(1)<<endl;
    return 0;
}
int test(int n)
{
    sum = 1;
    sum += n;
    if (sum < 5)
        test(n+1);
}

如果设sum为全局变量,那么会在test函数中每一次调用sum=1时都将sum重新赋值为1。整个程序最后输出为5。这个应该没有什么悬念吧?

如果设sum给test内的局部变量,则会在每一次执行int sum=1语句时都会创建一个新的sum对象,它的存放地址和之前的sum并不相同。然后整个程序最后输出意外的是4。

#include <iostream>
using namespace std;

int test(int n);

int main()
{
    cout<<test(1)<<endl;
    return 0;
}
int test(int n)
{
    int sum = 1;
    sum += n;
    if (sum < 5)
        return test(n+1);
    // return sum;   此处有这一行代码命名为程序1,没有这行代码命名为程序2
}

程序1的输出是5,程序2的输出是4。具体函数执行过程如下:

第一步,调用test(1):

int sum=1
sum=2
return test(2)

第二步,调用test(2):

int sum=1
sum=3
return test(3)

第三步,调用test(3):

int sum=1
sum=4
return test(4)

第四步,调用test(4):

int sum=1
sum=5

执行到第四步的时候,由于sum以及不比5小了,所以程序1没有进入if语句而是执行下一句return sum,所以输出为1。

而如果是程序2,也就是没有return sum语句,那么程序在执行完第四步后就会返回到第三步,最终调用(return) sum=4,输出4。



第三个问题:

该童鞋还提到了尾递归,这里我就来说说我的理解,如有问题欢迎大家直接评论或邮件给我。

上面代码中的递归函数factorialRecursive应该没问题的吧。

上面的代码我给其命名为迭代。

int factorialIteration(int product, int counter, int max_count)
{
    int sum=1;
    if(counter>max_count)
        sum*=product;
    else
        factorialIteration((counter*product),(counter+1),max_count);
}

通过在main函数中调用如下代码来执行该函数:

cout<<factorialIteration(1,1,n)<<endl;

当然,也可以另外写一个函数如下:

int factorialIter(int n)
{
    return factorialIteration(1,1,n);
}

并通过在main函数中直接调用该函数来做计算:

cout<<factorialIter(n)<<endl;

函数factorialIteration中的max_count我们称其为“循环不变量”,也就是对于整个运算过程而言这个变量是不变的。为了让大家更加印象深刻,将前面出现过的东西再来复制一遍:

(factorial 6)
(factorial 1 1 6)
(factorial 1 2 6)
(factorial 2 3 6)
(factorial 6 4 6)
(factorial 24 5 6)
(factorial 120 6 6)
(factorial 720 7 6)
720

从第二行开始的factorial的第三个参数”6“就是循环不变量。

尾递归:

在计算机科学中,尾调用是一个作为过程最后一步的子例程调用执行。如果尾调用可能在以后的调用链中再调用这同一个子例程,那么这个子例程就被称为是尾递归,它是递归的一个特殊情况。尾递归非常有用,在实现中也容易处理。尾调用可以不通过在调用堆栈中添加新的栈帧而实现。

传统上,尾部调用消除是可选的。然而,在函数式编程语言中,尾调用消除往往由语言标准作为保障,这种保证允许使用递归,在特定情况下的尾递归,来代替循环。在这种情况下,尽管用它作为一种优化是不正确的(尽管它可能是习惯用法)。在尾递归中,当一个函数调用它自身这种特殊情况下,可能调用消除比传统的尾调用更加合适。

迭代:

迭代是一个重复过程,它的目的是接近既定的目标或结果。每次重复的过程也称为”迭代“,作为迭代的结果都将作为下一次迭代的起点。

迭代在计算中是指的计算机程序中的重复的语句块。它可以表示两个专业术语,同义重复,以及描述一种具有可变状态重复的具体形式。然后令人费解的是,它也可以表示通过显式重复结构的任何重复,而不管其可变性。

在第一个意义上,递归是迭代的一个例子,但通常用”递归“来标记,而不作为”迭代“的例子。

在第二个意义上,(更加狭义地)迭代描述了一种编程风格。这与一个有着更有声明性方法的递归有着鲜明的对比。

第三个意义上,使用while或for循环,以及使用map或fold的函数也被视为迭代。

(以上定义部分摘自英文维基百科)

关于递归和尾递归在函数式编程中的应用也可以看这里:【Scheme归纳】3 比较do, let, loop

下面我也列出了相关的Scheme语言的代码:

(define (factorial n)
    (if (= n 1)
        1
        (* n (factorial (- n 1)))))
(define (factorial n)
    (fact-iter 1 1 n))
(define (fact-iter product counter max-count)
    (if (> counter max-count)
        product
        (fact-iter (* counter product)
                   (+ counter 1)
                   max-counter)))

以上分别是递归和迭代的阶层,下面是Common Lisp语言版的斐波那契数求法:

(defun fib (n)
    (fib-iter 1 0 n))
(defun fib-iter (a b count)
    (if (= count 0)
        b
        (fib-iter (+ a b) a (- count 1))))

借助递归树求解递归式

前面我们已经看到了递归式,也看到了递归树,那么如何借助递归树来求解递归式呢?接下来就来看看吧。

在递归树中,每个结点都表示一个单一问题的代价,子问题对应某次递归函数调用。

通过对树中每层的代价进行求和,就可以得到每层的代价;然后将所有层的代价求和,就可以得要到所有层次的递归调用的总代价。

我们通常用递归树来得出一个较好的猜测结果,然后用代入法来证明猜测是否正确。但是通过递归树来得到结果时,不可避免的要忍受一些”不精确“,得在稍后才能验证猜测是否正确。

因为下面的示例图太难用键盘敲出来了,我就用了手写,希望大家不介意。

如下所示,有一个递归式,我们要借助它的递归树来求解最终的结果。前面所说的忍受“不精确”这里就有2点:

1)我们要关注的更应该是解的上界,因为我们知道舍入对求解递归式没有影响,因此可以将Θ(n2)写成cn2,且为该递归式创建了如下递归树。

2)我们还将n假定为2的幂,这样所有子问题的规模均为正数。

图a所示的是T(n),在图b中则得到了一步扩展的机会。它是如何分裂的呢?递归式的系数为3,因此有3个子结点;n被分为2部分,因此每个结点的耗时为T(n/2)。图c所示的则是更加进一步的扩展,且直到最后的终点。

这棵树有多高(深)呢?

我们发现对于深度为i的结点,相应的规模为n/2i。因此当n/2i=1时,也就意味着等式i=log2n成立,此时子问题的规模为1。因此这个递归树有log2n+1层。那为什么不是log2n层呢?因为深度从0开始,也就是(0,1,2,...,log2n)。

有了深度还需要计算每一层的代价。其中每层的结点数都是上一层的3倍,因此深度为i的结点数为3i。而每一层的规模都是上一层的1/4,所以对于i=0,1,2,...,log4n?1,深度为i的每个结点的代价为c(n/2i)2。

因此对于i=0,1,2,...,log4n?1,深度为i的所有结点的总代价为(3i)?(c(n/2i)2),也就是3ic(n/2i)2。

递归树的最底层深度为log2n,它有3log2n=nlog23个结点,每个结点的代价为T(1),总代价就是nlog23T(1),假定T(1)为常量,即为Θ(nlog23)。

至于这最后的4c为什么可以直接省略掉,如上一节所说的,渐近记号都包含了常量因子。因此猜测T(n)=Θ(n2)。在这个示例中,cn2的系数形成了一个递减几何级数。由于根结点对总代价的贡献为cn2,所以根结点的代价占总代价的一个常量比例,也就是说,根结点的代价支配了整棵树的总代价。

不知道大家看不看得清,上面的两行文字是“我们要证的是T(n)≤dn2对某个常量d>0成立,使用常量c>0“和”当d≥4c时,最后一步成立。

霍纳规则

在看如何求解1000的阶层之前,我们不妨先看看一个简单点的:霍纳规则。当然,您也可以停顿下来先自己琢磨琢磨。

一、背景

霍纳(Horner)规则是采用最少的乘法运算策略,来求多项式

A(x)=anxn+an?1xn?1+...+a1x+a0

在x0处的值。

该规则为

A(x0)=(...((anx0+an?1)x0+...+a1)x0+a0)

二、分析

如果光看着式子或许会有点烦躁,不妨手动设定几个值到式子中去来手工运算一番,这样一来也会有些亲身的理解。

通过分解我们注意到,从右往左来看,每一个小式子都是如此:

something?x0+ai

三、代码

C语言版

#include <stdio.h>
#include <stdlib.h>

int hornerRule(int list[],int m,int x0);

int main()
{
    int m,x0;
    printf("Enter an integer (length of list): \n");
    scanf("%d",&m);
    int list[m];
    printf("Enter some integers for list: \n");
    int i;
    for(i=m-1;i>=0;i--)
    {
        scanf("%d",&list[i]);
    }
    printf("Enter an integer for x0: \n");
    scanf("%d",&x0);
    printf("%d",hornerRule(list,m,x0));

    return 0;
}

int hornerRule(int list[],int m,int x0)
{
    if(m<=1)
        return list[0];
    else
        return list[0]+(hornerRule(list+1,m-1,x0))*x0;
}

C++语言版

#include <iostream>

using namespace std;

int hornerRule(int list[],int m,int x0);

int main()
{
    int m,x0;
    cout<<"Enter an integer (length of list):"<<endl;
    cin>>m;
    int list[m];
    cout<<"Enter some integers for list:"<<endl;
    for(int i=m-1;i>=0;i--)
    {
        cin>>list[i];
    }
    cout<<"Enter an integer for x0:"<<endl;
    cin>>x0;

    cout<<hornerRule(list,m,x0);

    return 0;
}

int hornerRule(int list[],int m,int x0)
{
    if(m<=1)
        return list[0];
    else
        return list[0]+(hornerRule(list+1,m-1,x0))*x0;
}

四、测试

五、进阶

(PS:博主有一段时间没有碰Scheme有点忘了,所以下面的代码可能有些……粗糙)

关于Scheme可以看这里:

专栏:SICP练习

专栏:Scheme归纳

(define (Horner list m x0)
  (define (Horner-iter ls n)
    (if (<= n 1)
    (car ls)
    (+ (car ls) (* (Horner-iter (cdr ls) (- n 1)) x0))))
  (Horner-iter list m))

(define list ‘(1 2 1 0 3 1))
;Value: list

(Horner list 6 10)
;Value: 130121

如何求解10000的阶层

看到过一个蛮有意思的题,是问“100!”的尾数有多少个零。

尾数有多少个零,实际上指的是从这个数的最后一个不为0的数的下一个(也就是0)开始计数,一直到最后一个数(这些数自然都是0)有多少个0。

好吧,也就是说13330330000的尾数有4个零……

一个整数若含有因子5,则必然在求解100!时产生一个0,也就是说我们从5开始for循环,每次循环都给加上5,然后计数器加1。同时如果该整数还能被25整除,计数器还应该再加上1。(关于这段话的详细解释请看下文)

因此代码如下:

#include<stdio.h>

int main()
{
    int a,count =0;
    for(a=5;a<=100;a+=5)
    {
        ++count;
        if(!(a%25))
            ++count;
    }
    printf("100!的尾数有%d个零。\n",count);
    return 0;
}

题目后面进一步问了如何求出任意N!的尾数有多少个零。

#include<stdio.h>

int main()
{
    int n;
    printf("请输入N:\n");
    scanf("%d",&n);
    if(n<0)
        printf("%d的阶层无意义。\n",n);
    else if(n<=4)
        printf("%d的阶层的尾数没有零。\n");
    else
    {
        int a,count =0;
        for(a=5;a<=n;a+=5)
        {
            ++count;
            if(!(a%25))
                ++count;
        }
        printf("100!的尾数有%d个零。\n",count);
    }
    return 0;
}

本文就这样结束了吗?

题目的解答中有这么一段话:先求出100!的值,然后数一下末尾有多少个零。事实上,由于计算机所能表示的整数范围有限,这是不可能的。

首先,什么叫计算机所能表示的整数范围?应该叫int等数据类型的整数范围有限才对,计算机嘛……撑死了只能说不能存储而非不能表示。

另外100的阶层真的求不出来吗?请往下读。

我的博客中有大量关于Lisp,或者说Scheme的博文,使用这个语言,几行代码就能搞定了不是吗?欢迎阅读我的其他博文……

(define (fact n)
  (if (= n 1)
      1
      (* n (fact (- n 1)))))
;Value: fact

1000的阶层也能求,截图为证……

闲得无聊,以下是10000的阶层,大家可以继续算更大的数,哈哈……

………………

我发现这个CSDN博客写上这么多数字之后博客没法提交,有异常……没办法,只能上传了……下载后觉得有意思记得回来点赞哦……

传送门:10000的阶层

有网友私信问我,为什么一个整数若含有因子5,则必然在求解100!时产生一个0。这里所说的一个整数,自然是在求100的阶层时需要计算的从1到100这些整数。我下列出一些等式:

1x2=2
2x3=6
6x4=24
24x5=120

120x6=720
720x7=5040
5040x8=40320
40320x9=362880
362880x10=3628800

3628800x11=39916800
3991680x12=479001600
47900160x13=6227020800
622702080x14=87178291200
8717829120x15=1307674368000
…… ……

看到上式就会发现每次尾部增加0都是因为成了一个因子是5的整数。那么一直乘到100都会是这样吗?当然是。但这样就能证明?显然不能。

我们来看看各个整数的最后一个数:

如果是0的话,也就是说是乘以10或者20、30之类的,那么肯定会加上一个0。而且它也是5的倍数。

如果是1的话,无论乘以谁显然都不可能得到10。(这里的谁是指的的上面那些式子中的乘号左边的数的最后一个不为0的数。

如果是2的话,乘以5会得到10。

如果是4、6、8的话乘以5也会得到10。

如果是3、7、9的话就和1一样不会得到10。(得不到10也就无法增加一个0)

那么为什么是5而不是2、4、6、8呢?因为对于任何一个大于1的数的阶层而言,它的最后一个不为0的数必然是偶数。这又是为什么呢?因为最起码一开始就成了2,结果变成了偶数,而偶数乘以偶数为偶数,偶数乘奇数还是偶数…… 而2、4、6、8都必须和5相乘才可以得到10,以至于增加一个0。

那么5呢?5乘以任意一个偶数不都可以增加一个0吗,比如所10、20、30、40等等。

那么这个问题就得到了较为具体的解答。该网友还问了,为什么一个整数有25的因子,就需要计数再加1呢,很显然25是两个5的乘积呀。那么又为什么不考虑5的三次方也就是125呢?因为我们只乘到了100呀,100的阶层嘛。

如果不信我们就来验算一下呗……

#include<stdio.h>

int main()
{
    int a,count =0;
    for(a=5;a<=200;a+=5)
    {
        ++count;
        if(!(a%25))
        {
            ++count;
            if(!(a%125))
                ++count;
        }

    }
    printf("200!的尾数有%d个零。\n",count);
    return 0;
}

还有截图为证哦……

后来还看到一个题目,和这个也类似,需要求的是100的阶层的结果的数字中从左到右第一个四位的质数。

代码来源于网络以及别人的解答,感觉这里还是蛮巧妙地。

// C# Code
    public static class Program
    {
        public static void Main(string[] args)
        {
            string fac100 = Factorial(100).ToString("F0");
            Console.WriteLine("The factorial of 100 is : {0}", fac100);

            for (int i = 0; i <= fac100.Length - 4; i++)
            {
                string substr = fac100.Substring(i, 4);
                if (CheckPrime(Convert.ToInt32(substr)))
                {
                    Console.WriteLine("The expected result found and it is : " + substr);
                    return;
                }
            }
            Console.WriteLine("No result as expected!!");
        }

        public static double Factorial(int n)
        {
            double result = 1;
            for (int i = 1; i <= n; i++)
                result *= i;
            return result;
        }                   

        public static bool CheckPrime(int n)
        {
            if (n == 1 || n == 2)
                return true;
            int squareRoot = Convert.ToInt32(Math.Sqrt(n));
            for (int i = squareRoot; i > 1; i--)
                if (n % i == 0)
                    return false;
            return true;
        }
    }
// C++ Code
#include <iostream>
#include <math.h>
using namespace std;

double Factorial(int n)
{
    double result = 1;
    for (int i = 1; i <= n; i++)
        result *= i;
    return result;
}

bool CheckPrime(long n)
{
    if (n == 1 || n == 2)
        return true;
    long squareRoot = (long)sqrt(n);
    for (long i = squareRoot; i > 1; i--)
        if (n % i == 0)
        return false;
    return true;
}

int main(int argc, char *argv[])
{
    char buf[1024] = { ‘\0‘ };
    sprintf_s(buf, "%.f", Factorial(100));
    cout << "The factorial of 100 is : " << buf << endl;

    char substr[5] = { ‘\0‘ };
    for (int i = 0; i <= strlen(buf) - 4; i++)
    {
        memcpy(substr, buf + i, 4);
        if (CheckPrime(atol(substr)))
        {
            cout << "The expected result found and it is : " << substr << endl;
            return 0;
        }
    }
    cout << "No result as expected!!";
    return 0;
}
// C Code
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdbool.h>

double Factorial(int n)
{
    double result = 1;
    int i;
    for (i = 1; i <= n; i++)
        result *= i;
    return result;
}

bool CheckPrime(long n)
{
    if (n == 1 || n == 2)
        return true;
    long squareRoot = (long)sqrt(n);
    long i;
    for (i = squareRoot; i > 1; i--)
        if (n % i == 0)
        return false;
    return true;
}

int main(int argc, char *argv[])
{
    char buf[1024] = { ‘\0‘ };
    sprintf(buf, "%.f", Factorial(100));
    printf("The factorial of 100 is : %s\n",buf);

    char substr[5] = { ‘\0‘ };
    int i;
    for (i = 0; i <= strlen(buf) - 4; i++)
    {
        memcpy(substr, buf + i, 4);
        if (CheckPrime(atol(substr)))
        {
            printf("The expected result found and it is : %s\n",substr);
            return 0;
        }
    }
    printf("No result as expected!!\n");
    return 0;
}


欢迎大家点击左上角的“关注”或右上角的“收藏”方便以后阅读。


号外

求投票或转发支持呀……希望我不要死得太惨了……

请点击这里:投票

投票从10号开始一直持续到20号,拜托各位了!

——————当然你也可以直接点击图片啦

时间: 2024-10-18 04:59:17

【万字总结】探讨递归与迭代的区别与联系及如何求解10000的阶层的相关文章

深究递归和迭代的区别 联系 优缺点及实例对比

深究递归和迭代的区别.联系.优缺点及实例对比 1.概念区分 递归的基本概念:程序调用自身的编程技巧称为递归,是函数自己调用自己. 一个函数在其定义中直接或间接调用自身的一种方法,它通常把一个大型的复杂的问题转化为一个与原问题相似的规模较小的问题来解决,可以极大的减少代码量.递归的能力在于用有限的语句来定义对象的无限集合. 使用递归要注意的有两点: 1)递归就是在过程或函数里面调用自身; 2)在使用递归时,必须有一个明确的递归结束条件,称为递归出口. 递归分为两个阶段: 1)递推:把复杂的问题的求

Java中递归和迭代的区别

关于递归和迭代的博客一篇: http://blog.csdn.net/believejava/article/details/8423888 递归占用的资源较多,而且容易发生内存溢出,不易管理,推荐使用迭代 包的好处是:将有相似功能java文件放在同一个包下,易于使用管理 防止命名冲突 为protected类型的变量提供保护,使其对包外不暴露,只能在包内使用. .有一个问题是为啥主函数所在的java文件不能写包名,只能import包,否则老是报错.. 还有就是我现在为啥都不需要在配置classp

递归和迭代的区别

递归的基本概念:程序调用自身的编程技巧称为递归,是函数自己调用自己. 一个函数在其定义中直接或间接调用自身的一种方法,它通常把一个大型的复杂的问题转化为一个与原问题相似的规模较小的问题来解决,可以极大的减少代码量.递归的能力在于用有限的语句来定义对象的无限集合. 使用递归要注意的有两点: 1)递归就是在过程或函数里面调用自身; 2)在使用递归时,必须有一个明确的递归结束条件,称为递归出口. 递归分为两个阶段: 1)递推:把复杂的问题的求解推到比原问题简单一些的问题的求解; 2)回归:当获得最简单

递归和迭代的区别?

递归的基本概念 程序调用自身的编程技巧称为递归,是函数自己调用自己. 一个函数再其定义的直接或间接调用自身的一种方法,他通常把一个大型的复杂问题转化为一个和原来问题相似的规模较小的问题来解决,可以极大的减少代码量. 使用递归要注意的有两点: 1)递归就是在过程或函数里面调用自身; 2)在使用递归时,必须有一个明确的递归结束条件,称为递归出口. 迭代 利用变量的原值推算出一个新值. 如果递归是自己调用自己,迭代就是A不停的调用B 迭代:利用变量的原值推算出变量的一个新值.如果递归是自己调用自己的话

深究递归和迭代的区别、优缺点及实例对比

1.迭代是人,递归是神! 从"编程之美"的角度看,可以借用一句非常经典的话:"迭代是人,递归是神!"来从宏观上对二者进行把握. 从概念上讲,递归就是指程序调用自身的编程思想,即一个函数调用本身:迭代是利用已知的变量值,根据递推公式不断演进得到变量新值得编程思想. 2.递归 递归就是函数自己调用自己. 2.1构成递归需具备的条件: 子问题须与原始问题为同样的事,且更为简单: 2.?不能无限制地调用本身,须有个出口,化简为非递归状况处理. 2.2递归的基本原理 第一:每

【万字博文】分析与设计:插入排序和分治算法、递归和迭代的探讨

插入排序及其解决思路 算法的作用自然不用多说,无论是在校学生,还是已经工作多年,只要想在计算机这条道路走得更远,算法都是必不可少的. 就像编程语言中的"Hello World!"程序一般,学习算法一开始学的便是排序算法.排序问题在日常生活中也是很常见的,说得专业点: 输入是:n个数的一个序列<a1,a2,...,an?1,an> 输出是:这n个数的一个全新的序列<a,1,a,2,...,a,n?1,a,n>,其特征是a,1≤a,2≤...≤a,n?1≤a,n 举

递归与迭代

头文件 #include <stdlib.h> #include <stdio.h> #include <string.h> #pragma once 代码文件 #include "myH.h" //深度理解递归与迭代方法 //递归与迭代方法的区别: //递归使用函数和条件语句(if和else语句) //迭代法使用循环语句(for和while语句) /**************************************************

递归与迭代_1 2016.4.21

迭代乃人工,递归方神通 To interate is human,to recurse,divine 一.定义 (1) 迭代 是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果 每一次对过程的重复称为一次"迭代",而每一次迭代得到的结果会作为下一次迭代的初始值 (2) ① 程序调用自身的编程技巧称为递归( recursion) 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量

递归与迭代_2 2016.4.22

八.递归消除 按照递归的思想可使我们得以从宏观上理解和把握应用问题的实质 深入挖掘和洞悉算法过程的主要矛盾和一般性模式 并最终设计和编写出简洁优美且精确紧凑的算法 然而,递归模式并非十全十美,其众多优点的背后也隐含着某些代价 (1)空间成本 首先,从递归跟踪分析的角度不难看出,递归算法所消耗的空间量主要取决于递归深度 故较之同一算法的迭代版,递归版往往需耗费更多空间,并进而影响实际的运行速度 另外,就操作系统而言,为实现递归调用需要花费大量额外的时间以创建.维护和销毁各递归实例,这些也会令计算的