算法之递归,迭代,动态规划,分冶

递归:把一个问题 A 转换一个或多个子问题,我们把它们的集合叫做 B;A 的答案可以由 B 得到;对于一种确定的递归方法,从 B 的答案得到 A 的答案有且只有一种方法。

迭代:与递归的思想一样,只是在实现层面不一样。

动态规划:与递归思想一样,不同的是由 B 的答案得到 A 的答案可能有多种方法(可能),每次选择一种最优的方法去推导出 A 的答案。

分冶:与递归思想不一样,递归强调由 i 到 i+1 (或反过来)的推进,一个问题到一个紧密关联(递进关系)问题的转换;而分冶强调问题的划分,一个问题分解为多个简单的问题。

画图 1 以表示它们的不同。


图1 几种算法思想的不同

1.我们先来剖析递归和迭代的本质不同

下面给出一个斐波那契数列的两种解决方法:

//递归求解方法
int F(int i)
{
    if(i < 1)  return 0;
    
    if(i == 1) return 1;
    
    return F(i-1) + F(i - 2);

}

//迭代求解方法
int F(int i)
{
    f[0] = 0;
    f[1] = 1;
    for(i = 2; i <= N; i++)
    {
        f[i] = f[i-1] + f[i-2];
    }
    return f[i];
}

在递归方法中,F(i) 函数会递归调用 F(i-1) 和 F(i-2),F(i-1)会递归调用 F(i-2) 和 F(i-3)......直到碰到递归出口 F(1) 和 F(0)。

在迭代方法中,先由 F[0] 和 F[1] 求得 F[2],再由 F[2] 和 F[3] 求 F[4].......一直求到 F(i),这个过程没有递归调用函数,但是和递归的思想是一致的,为了求 F(i) 或 F[i] 必需要要先求 i-1 和 i-2 问题的答案。只是实现的方法不一样而已。递归采用了递归调用,而迭代采用了自底向上求解方法,由此次计算结果直接得到下一个问题的答案。

很明显可以看出这两种方法哪一个更优:递归方法由于两个原因效率太低,一是递归深度可能会非常大,而递归调用函数会产生时间耗费(函数栈构建,销毁)和空间耗费(函数栈需要放在栈内存里面);二是存在极大的重复调用,为了求 F(i) 要先调用 F(i-1) 和 F(i-2),而在 F(i-1)里面又会调用  F(i-2),越往下走,重复调用的次数会越来越多,F(1) 会被调用无数遍。

递归和迭代的本质区别在于:

对递归而言,在本问题(称为 i 问题)一轮的求解中,它不知道 i - 1 问题是怎么求解的,它只知道只知道如何由 i - 1 问题的答案得到自己的答案。

对迭代而言,在本问题(称为 i 问题)一轮的求解中,它明确知道 i - 1 的问题是怎么求解的(有多种手段,如可以直接存储 i - 1 问题的答案,或者通过其它方法求解),并且还知道如何由 i - 1 问题的答案得到自己的答案。

我们一般要将递归求解方法转换为迭代求解方法,以获得更高的性能,这就意味着,在迭代求解中,需要处理多一个细节,即,给出 i - 1 问题的求解方法。绝大多数情况下,我们直接存储 i - 1 问题的答案来达到这一点。这也揭示了一点,迭代一般是从底向上的,如斐波那契数列求解的迭代从 0,1,2 开始求解,不断向上求解,每求解一个问题,它的 i - 1 问题的答案已经得出了,所以可以很自然的完成迭代过程。对应的递归的方向往往是确定的,只能是 i 问题到 i - 1 问题的方向,因为只存在要求 i 问题,要递归调用 i - 1 问题的处理过程,而反过来是不存在的。

有一种优化的递归结合了递归与迭代的方法,实际上可以称为自顶向下的迭代或带有记忆功能的递归

const static int unknown = -1;

//结合迭代与递归结合的方法,也称为自顶向下的迭代,或者有记忆功能的递归
int F(int i)
{
    if(f[i] != unknown) //先看 i 问题的答案有没有缓存,如果有则立即返回
    
    {
        return f[i];
    }
    
    if(i == 0) t = f[0] = 0;
    
    if(i == 1) t = f[1] = 1;
    
    if(i > 1)  t = F(i - 1) + F(i - 2); //递归求解
    
    return f[i] = t;    //缓存结果

}

这个方法明显减少了递归调用的次数,因为一旦某个问题的解缓存了,那么就不会再递归调用它的子问题的求解过程。


2.递归与动态规划




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值