免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 6693 | 回复: 17
打印 上一主题 下一主题

[函数] 求助一个用堆栈来模拟fibr递归函数实现 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-02-02 22:00 |只看该作者 |倒序浏览
利用一个堆栈来模拟递归函数的实现,以fibr函数为例。
要求效率比递归实现高,空间使用率尽量的高,不知道各位大侠有什么好的点子?在下愿闻赐教

论坛徽章:
0
2 [报告]
发表于 2007-02-02 22:18 |只看该作者
我自己顶,希望大家来谈谈自己的想法。

论坛徽章:
0
3 [报告]
发表于 2007-02-03 01:24 |只看该作者
来个具体的吧,对于这个递归函数用堆栈来模拟:f(n) = f(n/2) + f(n/2 +1) + n
堆栈里面的数据结构应该是这样的(设n=7):7,3,1,2,1,1,4,2,1,1,2,1,1。就是一个二叉树,不过不知道怎么写代码可以高效的实现这种入栈。

论坛徽章:
0
4 [报告]
发表于 2007-02-03 01:38 |只看该作者
更正上面的式子,原本的式子是要计算f( more(n/2) ) + f( less(n/2) ) + n,其中more(n/2)表示不大于n/2的最大的整数,less(n/2)表示大于n/2最小的整数,上面的描述有误,不好意思。大家来讨论一下思路。

论坛徽章:
0
5 [报告]
发表于 2007-02-03 22:19 |只看该作者
怎么没有人啊?自己顶

论坛徽章:
0
6 [报告]
发表于 2007-02-03 23:03 |只看该作者
>> 来个具体的吧,对于这个递归函数用堆栈来模拟:f(n) = f(n/2) + f(n/2 +1) + n
>> 更正上面的式子,原本的式子是要计算f( more(n/2) ) + f( less(n/2) ) + n,其中more(n/2)表示不大于n/2的最大的整数,less(n/2)表示大于n/2最小的整数,上面的描述有误,不好意思。

我觉得,根据你下面的描述,上面的递归公式没错啊

论坛徽章:
0
7 [报告]
发表于 2007-02-03 23:14 |只看该作者
如果是上面那个意思的话,由递推公式:f(n) = f(n/2) + f(n/2 +1) + n
可知,f(2) = f(1) + f(2) + 2,无限递归了,所以应该给f(1)和f(2)赋初值
然后可以按下面的方法直接递推计算:
int f[NUM];
f[1] = some_value;
f[2] = some_value;

for (int i = 3; i <= n/2 + 1; ++i)
    f[i] = f[i/2] + f[i/2 + 1] + i;

int fn = f[n/2] + f[n/2 + 1] + n;

空间需要 n/2 + 1 + 1 个数组元素(下标为0的数组元素没用),时间上比递归节约了很多,因为用表保存了中间结果,避免了不少重复计算

另外,我并没有直接把递归转换成栈实现,方法是可行的,但是这种转换方法比较难懂,如果需要自己可以查找资料,讲算法的书上有些有

[[i] 本帖最后由 tyc611 于 2007-2-3 23:17 编辑 [/i]]

论坛徽章:
0
8 [报告]
发表于 2007-02-03 23:34 |只看该作者
忘记了,f(1) = 1。
对于你说的:
原帖由 tyc611 于 2007-2-3 23:14 发表
如果是上面那个意思的话,由递推公式:f(n) = f(n/2) + f(n/2 +1) + n
可知,f(2) = f(1) + f(2) + 2,无限递归了,所以应该给f(1)和f(2)赋初值
然后可以按下面的方法直接递推计算:
int f[NUM];
f[1] = some ...

这个是用迭代的方法。不过我想用堆栈来模拟一下递归的过程。现在关键的问题没有好方法来实现:(7,3,1,2,1,1,4,2,1,1,2,1,1)这种进栈顺序。不知道老大有没有好的方法?

论坛徽章:
0
9 [报告]
发表于 2007-02-03 23:54 |只看该作者
>> 7,3,1,2,1,1,4,2,1,1,2,1,1
这个是怎么得来的?

如果是一个返回点还好转换一点,有两个点转换起来比较麻烦,但是有一种模式可套用,我也说不清楚,建议找资料看吧

可以看看这本书,下面的链接能免费试读,在45页有讲递归转非递归的栈实现方法(需要下载阅读器)
http://www.china-pub.com/computers/common/info.asp?id=11749

[ 本帖最后由 tyc611 于 2007-2-3 23:55 编辑 ]

论坛徽章:
2
2015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:56:11
10 [报告]
发表于 2007-02-04 11:13 |只看该作者
如下是模拟栈的递归实现(如果学过编译原理就不难理解)
fibr函数是C递归代码,main中的是模拟递归代码

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

  3. #define ALEN(v) (sizeof(v)/sizeof((v)[0]))

  4. int fibr(int n){
  5.         printf("%d ", n);
  6.         return n<=1?1:fibr(n/2)+fibr((n+1)/2)+n;
  7. }

  8. int ip;
  9. int ax;
  10. int bp;
  11. int ss[100];
  12. int sp = ALEN(ss);

  13. void push(int n){
  14.         if(--sp<0){
  15.                 sp=ALEN(ss)-1;
  16.                 printf("\nStack Overflow!!\n");
  17.                 exit(-1);
  18.         }
  19.         ss[sp]=n;
  20. }

  21. int pop(void){
  22.         if(sp>=ALEN(ss)){
  23.                 sp=0;
  24.                 printf("\nStack Overflow!!\n");
  25.                 exit(-1);
  26.         }
  27.         return ss[sp++];
  28. }

  29. void call(void){
  30.         push(ip+1);
  31.         ip=0;
  32. }

  33. void ret(void){
  34.         ip = pop();
  35. }

  36. int main(void){
  37.         printf("= %d\n", fibr(7));
  38.         push(7);
  39.         ip=-2;
  40.         call();
  41.         while(ip>=0){
  42.                 switch(ip){
  43.                 case 0:
  44.                         push(bp);
  45.                         bp=sp;
  46.                         printf("%d ", ss[bp+2]);
  47.                         if(ss[bp+2]<=1){
  48.                                 ax=1;
  49.                                 ip=4;
  50.                         }else{
  51.                                 ip=1;
  52.                         }
  53.                         break;
  54.                 case 1:
  55.                         push(ss[bp+2]/2);
  56.                         call();
  57.                         break;
  58.                 case 2:
  59.                         sp+=1;
  60.                         push(ax);
  61.                         push((ss[bp+2]+1)/2);
  62.                         call();
  63.                         break;
  64.                 case 3:
  65.                         sp+=1;
  66.                         ax+=pop()+ss[bp+2];
  67.                         ip=4;
  68.                         break;
  69.                 case 4:
  70.                         bp=pop();
  71.                         ret();
  72.                         break;
  73.                 }
  74.         }
  75.         sp+=1;
  76.         printf("= %d\n", ax);
  77.         return 0;
  78. }
复制代码

评分

参与人数 1可用积分 +3 收起 理由
langue + 3

查看全部评分

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP