递归转非递归几个实例

递归是程序设计中很重要的技巧,简单易于实现;但递归程序效率较之非递归低得多,递归函数要直接或间接的调用自身,系统栈要频繁操作,时间空间消耗很大。在要求高效的很多场合需要将递归程序改写成非递归程序,由于疏于梳理这方面的知识点,感觉对于有些递归结构有些力不从心,于是有意识的学习了一下,感觉好了很多。

关于递归程序转非递归程序,基本通用方法是用自定义栈结构模拟递归过程,这种方法就是万金油,几乎所有递归都适用,之所以说几乎,主要考虑是暂没有见过用栈解决不了的,但碍于怕自己视野狭窄所以说几乎。如果从系统角度看递归,栈机制模拟能解决所有问题。其次,对于具体问题,可以有其他方法,直接迭代、动态规划什么的,像斐波那契数列就可以用直接迭代写成非递归的;动态规划也是直接迭代的一种,但需要转换思想,提取问题的最优子结构,像数塔问题、归并排序等都属于这类。关于这类,就不说了,这得视具体题目而定,发现问题的结构,寻找状态转移方程。

一般的还是得用栈模拟,这里主要谈谈栈模拟。以下所有代码重在说明算法,没有考虑爆栈、溢出等涉及程序的鲁棒性因素,还请谅解。

一、汉诺塔问题

汉诺塔是根据一个传说形成的一个问题:有三根杆子A,B,C。A杆上有N个(N>1)穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至C杆:
每次只能移动一个圆盘;
大盘不能叠在小盘上面。
提示:可将圆盘临时置于B杆,也可将从A杆移出的圆盘重新移回A杆,但都必须遵循上述两条规则。问:如何移?最少要移动多少次?(问题描述转自维基百科)

具体解法思想为先将A杆上面的n-1个借助C杆移到B杆,然后将A杆最低一根直接移到C,再将n-1根借助A杆从B移到C。上面隐含着递归思想将问题逐渐减小最后递推到原问题。

此时注意栈中元素不是单一的,要保留当前状态,可以用结构体,也可以多维数组,下面给出结构体做法。

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include<IOSTREAM>
using namespace std;
  
const int MAXN= 10000 ;
int m_Move= 0 ;
  
/**********************************************
*汉诺塔递归解法
***********************************************/
void recurHanoi( char from, char use, char to, int n)
{
     if ( 0 ==n)
         return ;
     recurHanoi(from,to,use,n- 1 );
     cout<<N<< "从" <<FROM<< "移到" <<TO<<ENDL; while (top from,use,to,number,id; char myStack[++top]= "now;" now.from= "'A';now.use='B';now.to='C';now.number=n;now.id=n;" m_Move= "0;" top= "0;" int now; Node myStack[MAXN]; cout<<?********非递归算法*********?<<endl; { n) notRecurHanoi( int void } cout<<now.id<<?从?<<now.from<<?移到?<<now.to<<endl; ++m_Move; now) print(Node }; to; use; from; id; number; struct *********************************************** *汉诺塔非递归解法 ********************************************** cout<<?**************************?<<endl; cout<<?总共移动?<<m_Move<<?次?<<endl; recurHanoi(&# 39 ;A&# 39 ;,&# 39 ;B&# 39 ;,&# 39 ;C&# 39 ;,n); cout<<?*********递归算法**********?<<endl; recurHanoi( int recurHanoi(use,from,to,n- 1 );> 0 )
      {
          if ( 1 ==myStack[top].number)
         {
             print(myStack[top]);
             --top;
          }
          else 
          {
              from=myStack[top].from;use=myStack[top].use;to=myStack[top].to;number=myStack[top].number;id=myStack[top].id;
              --top;
  
              now.from=use;now.use=from;now.to=to;now.number=number- 1 ;now.id=id- 1 ;
              myStack[++top]=now;
  
              now.from=from;now.use=use;now.to=to;now.number= 1 ;now.id=id;
              myStack[++top]=now;
  
              now.from=from;now.use=to;now.to=use;now.number=number- 1 ;now.id=id- 1 ;
              myStack[++top]=now;     
          }
      }
      cout<< "总共移动" <<M_MOVE<< "次" <<ENDL; int { } cout<<?**************************?<<endl; while (cin n; main()>>n)
     {
         recurHanoi(n);
         notRecurHanoi(n);
     }
     return 0 ;
}


二、组合数

 

C(n,m)=C(n-1,m)+C(n-1,m-1) n>m

C(n,m)=1 n=m或m=0

此问题的递归形式比较简单,非递归形式得深入理解过程,直接栈模拟,注意进出栈的时机,在此不多说可以看看拙劣的代码:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include<IOSTREAM>
using namespace std;
  
const int MAXN= 100 ;
  
int recurCombineCount( int n, int m)
{
     if ( 0 ==m||n==m) return 1 ;
     else return recurCombineCount(n- 1 ,m)+recurCombineCount(n- 1 ,m- 1 );
}
  
int notRecurCombineCount( int n, int m)
{
     int stack[MAXN][ 3 ];
     int top= 0 ;
     ++top;
     stack[top][ 0 ]=n;stack[top][ 1 ]=m;stack[top][ 2 ]= 0 ;
     do
     {
         if ( 0 ==stack[top][ 2 ]) //计算C(n-1,m)
         {
             ++top;
             stack[top][ 0 ]=stack[top- 1 ][ 0 ]- 1 ;stack[top][ 1 ]=stack[top- 1 ][ 1 ];stack[top][ 2 ]= 0 ;
             if (stack[top][ 0 ]==stack[top][ 1 ]|| 0 ==stack[top][ 1 ])
                 stack[top][ 2 ]= 1 ;
         }
         if (top>= 2 &&stack[top][ 2 ]> 0 ) //计算C(n-1,m-1)
         {
             ++top;
             stack[top][ 0 ]=stack[top- 2 ][ 0 ]- 1 ;stack[top][ 1 ]=stack[top- 2 ][ 1 ]- 1 ;stack[top][ 2 ]= 0 ;
             if (stack[top][ 0 ]==stack[top][ 1 ]|| 0 ==stack[top][ 1 ])
                 stack[top][ 2 ]= 1 ;
         }
         while (top>= 3 &&stack[top- 1 ][ 2 ]> 0 &&stack[top][ 2 ]> 0 ) //计算C(n,m)
         //注意此处这样有错://if(top>=3&&stack[top-1][2]>0&&stack[top][2]>0)
         {
             stack[top- 2 ][ 2 ]=stack[top- 1 ][ 2 ]+stack[top][ 2 ];
             top-= 2 ;
         }
     } while (top> 1 );
     return stack[top][ 2 ];
}
  
int main()
{
     int n,m;
     while (cin>>n>>m)
     {
         cout<< "************递归算法**************" <<ENDL; } pre < 0 ; return cout<<?*********************************?<<endl; cout<<?结果为:?<<notRecurCombineCount(n,m)<<endl; cout<<?***********非递归算法*************?<<endl; cout<<?结果为:?<<recurCombineCount(n,m)<<endl;><BR>
   
<P></P>
<P>         这几天持续更行中!<BR>
</P>
<P>      由于时间有限,疏于测试,如有不足或错误,欢迎斧正!<BR>
</P>
<P><BR>
</P>
<P><BR>
</P>
<P><BR>
</P>          
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值