【算法】——递归

一、递归的含义

递归函数的执行分为:"**递推”和“回归”**两个过程,这两个过程中条件控制, 即逐层递推,直至递归终止条件满足,终止递归,然后逐层回归

递归调用同普通函数的调用一样,每当调用发生时,就要分配新的栈帧(形参数据,现场保护,局部变量) 而与普通的函数调用不同的是,由于递推的过程是一个逐层调用的过程,因此存在一个逐层连续的分配栈帧过程,直到遇到递归终止条件时,才开始回归,这是才逐层释放栈帧空间,返回上一层,直至最后返回主函数。

注意:没有无穷递归,因为栈会溢出。在windows系统下栈的空间只有1M.

二、递归过程分析

首先我们来讨论一下求解阶乘的问题。要想求到n的阶乘,则要先求n-1的阶乘,要想求到n-1的阶乘,则要先求n-2的阶乘,以此类推。递归的过程就是一个不断开辟栈帧的过程,随后又是逐步回归。下面我们来具体看一下代码实现。
1、代码实现
1.1循环实现

int fun(int n)
{
    int sum = 1;
    for (int i = 1; i <= n; ++i)
    {
        sum = sum * i;
    }
    return sum;
}

1.2递归实现O(n) S(n)

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

递归实现过程如下
在这里插入图片描述
2、改进代码实现

2.1循环代码改变—》错误的。

int fun1(int n)
{
    int sum = 1;
    for (int i = 1; ; ++i)//错误
    while(1){ }
    {
        sum = sum * i;
    }
    return sum;
}

死循环,但其他程序可以执行。因为每一个进程都有一个时间片,时间片一到就会到就绪态

补充:
在C语言中的死循环表示方式

  • for( ; ; ){}(效率会高一点)
  • while(1){ }

2.2递归实现改进,解决溢出问题

int sum1(int n)
{
    if (n <= 1)
        return 1;
    else
    {
        int x = sum(n - 1) * n;
        if (x > 0)
        {
            return x;
        }
        else
        {
            return -1;
        }
    }
}

三、其他递归问题

1、输入一个整数12345,输出 5 4 3 2 1

1.1循环实现:

void fun(unsigned int n)
{
    while (n)
    {
        cout << n % 10 << "";
        n = n / 10;
    }
}

1.1.1循环改进1:使循环打印出来的值为正序
解决方案:模拟实现栈

void fun1(unsigned int n)
{
    int ar[20] = { 0 };//无符号整形42亿多,为十位,大小大于十位就行
    int top = 0;
    while (n)
    {
        ar[top++] = n % 10;
        n = n / 10;
    }
    for (int i = top ; i >= 0; --i)
    {
        cout << ar[i-1] << "";
    }
    cout << endl;
}

注意!i不能定义成unsinged型,因为如果i定义成unsigned,i–过后,-1变成了一个很大的数,会是无限循环

1.1.2循环改进2:使用容器解决

void fun2(unsigned int n)
{
    vector<int> ivec;
    while (n)
    {
        ivec.push_back(n % 10);
        n = n / 10;
    }
    //输出逆转
    for (vector<int>::reverse_iterator rit = ivec.rbegin(); rit != ivec.rend(); ++rit)
    {
        cout << *rit << "";
    }
    cout << endl;
}

1.2递归实现

void fun1(unsigned int n)
{
    if (n > 0)
    {
        cout << n % 10 << "";
        fun1(n / 10);
    }
}

1.2.1递归实现改进1,将if改为while。错误的!!

void fun11(unsigned int n)
{
    while (n > 0)
    {
        cout << n % 10 << "";
        fun1(n / 10);
    }
}

错误原因:不断的递归调用过程n一直是不变的,不断开辟栈帧,相当于死循环

1.2.2递归实现改进2,后面加一段程序n = n /10;错误的!!

void fun111(unsigned int n)
{
    while (n > 0)
    {
        cout << n % 10 << "";
        n = n / 10;
        fun1(n / 10);
    }
}

错误原因:不断的递归调用过程n一直是不变的,不断开辟栈帧,相当于死循环

1.2.3递归改进3,将程序顺序改变,将正序输出

void fun2(unsigned int n)
{
    if(n > 0)
    {   
        fun2(n / 10);
        cout << n % 10 << "";
    }
}

2、求最大公约数
1、循环算法

int fun(int a, int b)
{
    int i = a < b ? a : b;
    for (i -= 1; i > 0; --i)
    {
        if (a % i == 0 && b % i == 0)
        {
            return i;
        }
    }
}

2、欧几里得算法:辗转相除法
2.1循环实现

int fun(int a, int b)
{
    while (b <= 0)
    {
        int tmp = b;
        b = a % b;
        a = tmp;
   }
    cout << a << endl;
}

2.2递归实现

int fun(int a, int b)
{
    if (b == 0)
        return a;
    return(b, a % b);
}

3、 斐波拉契数列
1、O(2^n) S(h)

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

2、改进:消除计算重复项,并且使O(n),S(n)

int fibs(int n, int a, int b)
{
    if (n <= 2) return a;
    else return fibs(n - 1, a + b, a);
}
int fib(int n)
{
    int a = 1, b = 1;
    return fibs(n, a, b);
}
发布了62 篇原创文章 · 获赞 7 · 访问量 2570

猜你喜欢

转载自blog.csdn.net/qq_43412060/article/details/104620112