| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 5521 人关注过本帖, 8 人收藏
标题:一步一步教你如何调试 递归程序,
只看楼主 加入收藏
BlueGuy
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:29
帖 子:4476
专家分:4055
注 册:2009-4-18
结帖率:94.72%
收藏(8)
已结贴  问题点数:100 回复次数:22 
一步一步教你如何调试 递归程序,
这篇帖子主要是介绍 递归 与 动态规划 之间是如何转换的,
什么是递归估计不用多说,那么什么是 动态规划呢?
我理解的动态规划就是:
能够避免 直接 递归实现 中出现的重复运算的技术就是动态规划。

这里有三个关键词:"直接"、"递归实现"、"重复运算"

也许最简单的, 也是众所周知的动态规划题目是 Fibonacci数列,
如果你不知道,说明你的老师也不知道,而且我为你感到难过。

但是,遗憾的是,本文将 选取另一个也是众所周知的动态规划题目:
二项式系数 C(m, n)

它的递推公式如下:

C(m, n) = C(m-1, n-1) + C(m-1, n), C(m, 0) = 1, C(m, m) = 1;

你或许会很惊讶,这是什么?我根本不熟悉嘛!
好吧,我想杨辉三角你应该不陌生,是个c语言的书籍都会有这道题,
那么,你还记不记得杨辉三角 与 二项式系数有那么一点点的关系呢?
记不得,翻书吧!

首先,我(不是我们)给出 C(m, n)的 直接递归实现。

#include <stdio.h>

int C(int M, int N);

int main(void)
{
    printf("%d\n", C(5, 2));

    getchar();

    return 0;
}

int C(int M, int N)
{
   
    if (N == 0 || M == N)
    {
        return 1;
    }

    return C(M-1, N-1) + C(M-1, N);
}

输出:10

那么, 这个实现直接吗?
当然直接,公式就是这样定义的啊。不是吗?

然后, 可以肯定的是这个实现有 重复运算,
肯定有,要不然不会拿这道题作为例程解析。
怎么样知道这个实现有 重复运算呢?

很简单,把递归调用路径打印出来看一眼就行了,仅仅是一眼。
在此之前,得确信你会 复制/粘帖 控制台中的内容,如果你还不会,
那么,请你百度一下吧。

我给函数多加一个参数用来记录 递归调用深度 (这项技术已经被我多次使用,不知你的技术敏感度怎么样,有没有留意过)?
然后,重新实现一下代码。

#include <stdio.h>

int C(int M, int N, int depth);

int main(void)
{
    printf("\nc(5, 2) = %d", C(5, 2, 0));

    getchar();

    return 0;
}
int C(int M, int N, int depth)
{
    int i, ret;

    for (i = 0; i < depth; i++)
    {
        printf(" ");
    }

    printf("C(%d, %d)\n", M, N);

    if (N == 0 || M == N)
    {
        return 1;
    }

    return C(M-1, N-1, depth+1) + C(M-1, N, depth+1);
}

输出:

C(5, 2)
 C(4, 1)
  C(3, 0)
  C(3, 1)
   C(2, 0)
   C(2, 1)
    C(1, 0)
    C(1, 1)
 C(4, 2)
  C(3, 1)
   C(2, 0)
   C(2, 1)
    C(1, 0)
    C(1, 1)
  C(3, 2)
   C(2, 1)
    C(1, 0)
    C(1, 1)
   C(2, 2)

c(5, 2) = 10

很明显的可以看出,C(1, 1)被多次运算过,当然不只是C(1, 1)了, 还有C(2, 1)呢?还有,...?

然后,怎么样避免这个实现中的重复运算呢?
还记得先前有个帖子 "打家看看这个递归的 为什么结果要存起来 不能直接返回T 求N的阶乘的递归都不要存结果" 吗?

好吧,接下来咱采用相同的技术:把结果保存起来。

#include <stdio.h>

#define M 5
#define N 2

int C(int m, int n, int depth);

int knownC[M+1][N+1] = {0};

int main(void)
{
    printf("\nc(%d, %d) = %d\n", M, N, C(M, N, 0));
    getchar();
    return 0;
}

int C(int m, int n, int depth)
{
    int i, ret;

    for (i = 0; i < depth; i++)
    {
        printf(" ");
    }

    printf("C(%d, %d)\n", m, n);

    if (knownC[m][n] != 0)
    {
        return knownC[m][n];
    }

    if (n == 0 || m == n)
    {
        ret = 1;
    }
    else
    {
        ret = C(m-1, n-1, depth+1) + C(m-1, n, depth+1);
    }

    return knownC[m][n] = ret;
}

输出:
C(5, 2)
 C(4, 1)
  C(3, 0)
  C(3, 1)
   C(2, 0)
   C(2, 1)
    C(1, 0)
    C(1, 1)
 C(4, 2)
  C(3, 1)
  C(3, 2)
   C(2, 1)
   C(2, 2)

c(5, 2) = 10

这个就是 所谓的 "自顶向下动态规划" 。

现在, 我们回到先前 所说的 "杨辉三角",
利用杨辉三角解 C(m, n) 。

#include <stdio.h>

#define M 5
#define N 2

int main(void)
{
   
    int C[M+2][M+2] = {0, 1};
    int i, j;

    for (i = 1; i < M+2; i++)
    {
        for (j = 1; j <= i; j++)
        {
            C[i][j] = C[i-1][j-1] + C[i-1][j];
        }
    }

    printf("%d\n", C[M+1][N+1]);

    return 0;
}

这个就是 所谓的 "自底向上动态规划" 。


最后,请问你看懂了吗?
看懂了,请再看下 "出一个简单的算法题, 测测论坛的整体水平" 这个帖子,
并用三种方法解答出来,解不出来说明你还没看懂,希望你花点时间把它看懂。

小记:
先前和某人讨论 递归,他说递归多简单呀,然后还给我举了个例子,
就是 阶乘, 自此我对其非常不屑。

好吧, 我说完了,谢谢!

[ 本帖最后由 BlueGuy 于 2011-5-7 17:19 编辑 ]
收到的鲜花
  • Devil_W2011-05-08 19:20 送鲜花  -3朵   附言:很水。
搜索更多相关主题的帖子: 关键词 二项式 
2011-05-07 09:53
flyue
Rank: 10Rank: 10Rank: 10
来 自:江南西道
等 级:贵宾
威 望:19
帖 子:3465
专家分:1563
注 册:2006-6-20
收藏
得分:5 
接分…

天之道,损有余而补不足.人之道则不然,损不足以奉有余.孰能有余以奉天下,唯有道者.
2011-05-07 16:42
heimodao
Rank: 3Rank: 3
等 级:论坛游侠
帖 子:88
专家分:172
注 册:2011-4-8
收藏
得分:5 
留名找时间再看
2011-05-07 16:55
BlueGuy
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:29
帖 子:4476
专家分:4055
注 册:2009-4-18
收藏
得分:0 
以下是引用flyue在2011-5-7 16:42:56的发言:

接分…
前辈过来接分,给这个帖子增加了不少光彩。

我就是真命天子,顺我者生,逆我者死!
2011-05-07 16:59
犹豫情人
Rank: 2
来 自:天津
等 级:论坛游民
帖 子:58
专家分:24
注 册:2010-7-1
收藏
得分:5 
分啊
2011-05-07 18:47
cacker
该用户已被删除
收藏
得分:5 
提示: 作者被禁止或删除 内容自动屏蔽
2011-05-07 18:56
oszc
Rank: 3Rank: 3
等 级:论坛游侠
帖 子:111
专家分:154
注 册:2011-4-15
收藏
得分:5 
学习mark,
分啊分啊分
2011-05-07 19:18
laoyang103
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:内蒙古包头
等 级:贵宾
威 望:19
帖 子:3082
专家分:11056
注 册:2010-5-22
收藏
得分:5 
你咋知道我在找动态规划的资料呢   哈哈

谢谢楼主啦

                                         
===========深入<----------------->浅出============
2011-05-07 20:08
liangjinchao
Rank: 7Rank: 7Rank: 7
等 级:黑侠
帖 子:376
专家分:697
注 册:2010-11-8
收藏
得分:5 
先收藏,再慢慢欣赏!

因为有了因为,所以有了所以,既然已成既然,何必再说何必
2011-05-07 20:35
gongyaping
Rank: 4
来 自:广东肇庆怀集
等 级:业余侠客
帖 子:174
专家分:257
注 册:2010-8-1
收藏
得分:5 
多谢分享。
2011-05-07 21:59
快速回复:一步一步教你如何调试 递归程序,
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.038479 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved