任何递归都可以化成非递归。
如果不用盏,
有的递归可以改成迭代。
我想知道的时候,
如果不借助于盏,
到底什么递归何时可以改成非递归,
何时不能?
36 个解决方案
#1
一个例子:
Ackerman函数就不能改为非递归
A(1,0)=2
A(0,m)=1 m>=0
A(n,0)=n+2, n>=2
A(n,m)=A(A(n-1,m),m-1) n,m>=1
Ackerman函数就不能改为非递归
A(1,0)=2
A(0,m)=1 m>=0
A(n,0)=n+2, n>=2
A(n,m)=A(A(n-1,m),m-1) n,m>=1
#2
我还知道hanoi也不能改成非递归,
我想要此问题的描述、总结,或者说定理,
而不是个别例子。
3x
我想要此问题的描述、总结,或者说定理,
而不是个别例子。
3x
#3
hanoi也不能改成非递归 ??
能给出证明么?
能给出证明么?
#4
2,已知Ackerman函数的定义如下:
n+1 m=0
akm(m,n) = akm(m-1,1) m0,n=0
akm(m-1,akm(m,n-1)) m0,n0
(1)写出递归算法
(2)写出非递归算法
递归算法:
int akm(int m, int n)
{
if (m == 0) akm = n+1 ;
else if( n == 0)
akm = akm(m-1 , 1);
else
6.4 递归的模拟
{
g=akm(m , n-1);
akm=akm(m-1 , g) ;
}
}//akm
非递归算法:
int akm1(int m , int n)
{/*S[MAX]为附设栈,top为栈顶指针*/
top = 0 ; S[top].mval = m ; S[top-1].nval=n ;
do {
while (S[top].mval){
while(S[top].nval){
top++ ; S[top].mval=S[top-1].mval;
6.4 递归的模拟
S[top].nval=S[top-1].nval-1 ;
}
S[top].mval-- ; S[top].nval=1 ;
}
if (top>0)
{ top -- ;
S[top].mval -- ;
S[top].nval=S[top+1].nval+1;
}
}
while (top !=0 || S[top].mval != 0);
akm1=S[top].nval+1 ; top-- ;
}//akm1
n+1 m=0
akm(m,n) = akm(m-1,1) m0,n=0
akm(m-1,akm(m,n-1)) m0,n0
(1)写出递归算法
(2)写出非递归算法
递归算法:
int akm(int m, int n)
{
if (m == 0) akm = n+1 ;
else if( n == 0)
akm = akm(m-1 , 1);
else
6.4 递归的模拟
{
g=akm(m , n-1);
akm=akm(m-1 , g) ;
}
}//akm
非递归算法:
int akm1(int m , int n)
{/*S[MAX]为附设栈,top为栈顶指针*/
top = 0 ; S[top].mval = m ; S[top-1].nval=n ;
do {
while (S[top].mval){
while(S[top].nval){
top++ ; S[top].mval=S[top-1].mval;
6.4 递归的模拟
S[top].nval=S[top-1].nval-1 ;
}
S[top].mval-- ; S[top].nval=1 ;
}
if (top>0)
{ top -- ;
S[top].mval -- ;
S[top].nval=S[top+1].nval+1;
}
}
while (top !=0 || S[top].mval != 0);
akm1=S[top].nval+1 ; top-- ;
}//akm1
#5
我认为学过数据结构的朋友都知道递归是用栈来实现的,
那么,递归转化为非递归的程序都可以用栈来描述(当然如果用循环就可以解决的就不必了)
so:所有的递归在理论上都可以转化成非递归的。 只不过在转化过程中的难易程度有不同。还有实现所消耗的空间和时间特别大~
那么,递归转化为非递归的程序都可以用栈来描述(当然如果用循环就可以解决的就不必了)
so:所有的递归在理论上都可以转化成非递归的。 只不过在转化过程中的难易程度有不同。还有实现所消耗的空间和时间特别大~
#6
楼上的我可能没说清楚。
我再举个例子吧,比如说求阶乘,
f(n)=n*f(n-1),
这个是递归,
但是这个很容易可以改成递推。
x=1;
for(int i=2;i<=n;i++)
x*=i;
然后就求出结果了,
这就是我要的非递归,
而不是手动使用栈。
但是对于汉诺塔程序,
是不能改成递推的,
你不信可以试试。
我的意思就是说不要使用栈,
直接改成循环。
所以我的问题是,
什么情况下肯定可以把递归改成循环?
我再举个例子吧,比如说求阶乘,
f(n)=n*f(n-1),
这个是递归,
但是这个很容易可以改成递推。
x=1;
for(int i=2;i<=n;i++)
x*=i;
然后就求出结果了,
这就是我要的非递归,
而不是手动使用栈。
但是对于汉诺塔程序,
是不能改成递推的,
你不信可以试试。
我的意思就是说不要使用栈,
直接改成循环。
所以我的问题是,
什么情况下肯定可以把递归改成循环?
#7
for() 和数组 联合在一起,也可以实现栈的哦。。。呵呵!
#8
感觉lz把问题的面!搞的太窄了
#9
栈保存了全部数据,
循环只保存当前数据,
是吧?
循环只保存当前数据,
是吧?
#10
尾递归可以改成迭代,其他的递归都不行。所谓尾递归是指递归调用的语句在递归函数的最后一句,
#11
其实主要就是看这个算法需要的最小空间复杂度是多少.
如果空间复杂度可以降低到O(1),那么就没必要用递归了.
不然,用不用递归本质上没有区别
如果空间复杂度可以降低到O(1),那么就没必要用递归了.
不然,用不用递归本质上没有区别
#12
hanoi是可以用非递归的
#13
guohuang(菜瓜头) ( ) 信誉:100 2006-7-19 10:10:24 得分: 0
尾递归可以改成迭代,其他的递归都不行。所谓尾递归是指递归调用的语句在递归函数的最后一句,
尾递归可以改成迭代,其他的递归都不行。所谓尾递归是指递归调用的语句在递归函数的最后一句,
#14
都可以非递归
对于计算机来说,递归就是一个循环而已
对于计算机来说,递归就是一个循环而已
#15
guohuang(菜瓜头) ( ) 信誉:100 2006-7-19 10:10:24 得分: 0
尾递归可以改成迭代,其他的递归都不行。所谓尾递归是指递归调用的语句在递归函数的最后一句,
==================
前几天做题也看到这个,只是当时没弄明白什么叫尾递归
尾递归可以改成迭代,其他的递归都不行。所谓尾递归是指递归调用的语句在递归函数的最后一句,
==================
前几天做题也看到这个,只是当时没弄明白什么叫尾递归
#16
即使没有栈,
第归也可以改成非第归,
只是需要额外的内存(比如数组)来保存原来准备保存在栈里的相关信息而已.
当然使用栈是简明易懂的方式.
如果不允许使用额外内存空间,
则没有一个简单的办法可以进行判断.
不过,一般而言,
没有额外信息需要临时保存的第归(实际上栈并没有被使用),
都可以改成无栈并且不使用额外空间的非第归,
如果有额外的信息需要临时保存,并且信息量和第归深度成正相关的时候,
就不能改成无栈并且不使用额外空间的非第归。
第归本身就是一种使用栈保存临时信息的方式。
第归也可以改成非第归,
只是需要额外的内存(比如数组)来保存原来准备保存在栈里的相关信息而已.
当然使用栈是简明易懂的方式.
如果不允许使用额外内存空间,
则没有一个简单的办法可以进行判断.
不过,一般而言,
没有额外信息需要临时保存的第归(实际上栈并没有被使用),
都可以改成无栈并且不使用额外空间的非第归,
如果有额外的信息需要临时保存,并且信息量和第归深度成正相关的时候,
就不能改成无栈并且不使用额外空间的非第归。
第归本身就是一种使用栈保存临时信息的方式。
#17
没有办法可改,汉诺塔就是一个例子,不用递归根本解决不了的。
#18
只有尾递归可以直接消除递归!
其他的都需要间接的,如修改算法,栈保存参数和返回值全部或部分信息。
其他的都需要间接的,如修改算法,栈保存参数和返回值全部或部分信息。
#19
什么情况下肯定可以把递归改成循环?
只有尾递归可以直接消除递归!就是循环就可以了
其他的都需要间接的,如修改算法,栈保存参数和返回值全部或部分信息。
比如:
F(0)=F(1)=1;
F(n) = n*F(n-1);
这个可以直接用循环实现
但是如果改为:
F(0)=F(1)=1;
F(n) = F(n-1)*n;
就不能直接消除递归,而需要修改算法,交换F(n-1) 与 n的位置。
如果用语法树来分析就明显了
{a}b
可用语法(1)
S->Ab
A->aA
上面的可以直接消除递归
下面文法(2)
S->Ab
A->Aa
这个就必须先消除左递归才行。
也就是LL(1)文法为什么先要消除左递归,再进行分析的原故。
只有尾递归可以直接消除递归!就是循环就可以了
其他的都需要间接的,如修改算法,栈保存参数和返回值全部或部分信息。
比如:
F(0)=F(1)=1;
F(n) = n*F(n-1);
这个可以直接用循环实现
但是如果改为:
F(0)=F(1)=1;
F(n) = F(n-1)*n;
就不能直接消除递归,而需要修改算法,交换F(n-1) 与 n的位置。
如果用语法树来分析就明显了
{a}b
可用语法(1)
S->Ab
A->aA
上面的可以直接消除递归
下面文法(2)
S->Ab
A->Aa
这个就必须先消除左递归才行。
也就是LL(1)文法为什么先要消除左递归,再进行分析的原故。
#20
所有尾递归和一些特殊的非尾递归(如树的中序遍历)可以改
#21
这是hanoi非递归算法.
include <iostream>
#include <stdlib.h>
#ifdef _WIN32
using namespace std;
#endif
static void hanoi(int height)
{
int fromPole, toPole, Disk;
int *BitStr = new int[height],
*Hold = new int[height];
char Place[] = {'A', 'C', 'B'};
int i, j, temp;
for (i=0; i < height; i++)
{
BitStr[i] = 0;
Hold[i] = 1;
}
temp = 3 - (height % 2);
int TotalMoves = (1 << height) - 1;
for (i=1; i <= TotalMoves; i++)
{
for (j=0 ; BitStr[j] != 0; j++)
{
BitStr[j] = 0;
}
BitStr[j] = 1;
Disk = j+1;
if (Disk == 1)
{
fromPole = Hold[0];
toPole = 6 - fromPole - temp;
temp = fromPole;
}
else
{
fromPole = Hold[Disk-1];
toPole = 6 - Hold[0] - Hold[Disk-1];
}
cout << "Move disk " << Disk << " from " << Place[fromPole-1]
<< " to " << Place[toPole-1] << endl;
Hold[Disk-1] = toPole;
}
}
int main(int argc, char *argv[])
{
cout << "Towers of Hanoi: " << endl
<< "moving a tower of n disks from pole A to pole B by using pole C" << endl;
cout << "Input the height of the original tower: ";
int height;
cin >> height;
hanoi(height);
system("PAUSE");
return EXIT_SUCCESS;
}
问题描述:有三个柱子A, B, C. A柱子上叠放有n个盘子,每个盘子都比它下面的盘子要小一点,可以从上到下用1, 2, ..., n编号。要求借助柱子C,把柱子A上的所有的盘子移动到柱子B上。移动条件为:1、一次只能移一个盘子;2、移动过程中大盘子不能放在小盘子上,只能小盘子放在大盘子上。
算法要点有二:
1、确定哪一个盘子要移动。有n个盘子的Hanoi塔需要移动2^n -1次,设m为n位的二进制数,则m的取值范围为0~2^n -1。让m每次递增1,可以发现,m中最低一位的刚刚由0变为1的位置的位置编号,和即将要移动的盘子编号有确定关系。
2、这个盘子往哪个柱子上移。
a.第一次需要移动1号盘,n为奇数时,1号盘首先移动到柱子B,为偶数时首先移动到柱子C。
b.接下来如果移动的盘子不是1号盘。你有两个柱子可以选择。先找到1号盘所在的柱子,因为移动的盘子不能叠放到1号盘上,所以该盘可以移动的位置就是没有1号盘的那个柱子。
c.如果移动的盘子是1号盘。也有两个柱子可以选择。找到1号盘原先是从哪个柱子上移来的,因为移动的顺序(顺时针或逆时针)一旦确定,就不会更改,所以排除from的那个柱子后,移动方向也就唯一了。
include <iostream>
#include <stdlib.h>
#ifdef _WIN32
using namespace std;
#endif
static void hanoi(int height)
{
int fromPole, toPole, Disk;
int *BitStr = new int[height],
*Hold = new int[height];
char Place[] = {'A', 'C', 'B'};
int i, j, temp;
for (i=0; i < height; i++)
{
BitStr[i] = 0;
Hold[i] = 1;
}
temp = 3 - (height % 2);
int TotalMoves = (1 << height) - 1;
for (i=1; i <= TotalMoves; i++)
{
for (j=0 ; BitStr[j] != 0; j++)
{
BitStr[j] = 0;
}
BitStr[j] = 1;
Disk = j+1;
if (Disk == 1)
{
fromPole = Hold[0];
toPole = 6 - fromPole - temp;
temp = fromPole;
}
else
{
fromPole = Hold[Disk-1];
toPole = 6 - Hold[0] - Hold[Disk-1];
}
cout << "Move disk " << Disk << " from " << Place[fromPole-1]
<< " to " << Place[toPole-1] << endl;
Hold[Disk-1] = toPole;
}
}
int main(int argc, char *argv[])
{
cout << "Towers of Hanoi: " << endl
<< "moving a tower of n disks from pole A to pole B by using pole C" << endl;
cout << "Input the height of the original tower: ";
int height;
cin >> height;
hanoi(height);
system("PAUSE");
return EXIT_SUCCESS;
}
问题描述:有三个柱子A, B, C. A柱子上叠放有n个盘子,每个盘子都比它下面的盘子要小一点,可以从上到下用1, 2, ..., n编号。要求借助柱子C,把柱子A上的所有的盘子移动到柱子B上。移动条件为:1、一次只能移一个盘子;2、移动过程中大盘子不能放在小盘子上,只能小盘子放在大盘子上。
算法要点有二:
1、确定哪一个盘子要移动。有n个盘子的Hanoi塔需要移动2^n -1次,设m为n位的二进制数,则m的取值范围为0~2^n -1。让m每次递增1,可以发现,m中最低一位的刚刚由0变为1的位置的位置编号,和即将要移动的盘子编号有确定关系。
2、这个盘子往哪个柱子上移。
a.第一次需要移动1号盘,n为奇数时,1号盘首先移动到柱子B,为偶数时首先移动到柱子C。
b.接下来如果移动的盘子不是1号盘。你有两个柱子可以选择。先找到1号盘所在的柱子,因为移动的盘子不能叠放到1号盘上,所以该盘可以移动的位置就是没有1号盘的那个柱子。
c.如果移动的盘子是1号盘。也有两个柱子可以选择。找到1号盘原先是从哪个柱子上移来的,因为移动的顺序(顺时针或逆时针)一旦确定,就不会更改,所以排除from的那个柱子后,移动方向也就唯一了。
#22
首先那要看你怎么理解递归.用栈对递归过程进行原始模拟,并没有从本质上改变递归算法的计算过程,但是如果以递归调用为形式的算法称为递归算法,其他的不是,那么模拟后的算法就不是递归算法,这也就可以说任何递归算法都是可以用非递归形式来实现.
#23
另一种理解,用堆栈实现递归只是模拟了递归的计算过程,并没有消除递归,真正的非递归是指运算所需空间与问题的输入规模无关。当然尾递归可以用迭代来实现非递归,还有把递归转化为尾递归,再转化为迭代,例如用Cooper变换就可以把一大类的递归转化为尾递归。可是并不是所有的递归都可以用迭代实现,例如Ackmann函数就无法用迭代计算.其实正如当年海星所说,转换只是一种模拟,实际上是用人脑完成了电脑的某些过程.
#24
mark
#25
尾递归?
F(0)=F(1)=1;
F(n) = n*F(n-1);
和
F(0)=F(1)=1;
F(n) = F(n-1)*n
有区别吗?
没有区别,我认为。
F(0)=F(1)=1;
F(n) = n*F(n-1);
和
F(0)=F(1)=1;
F(n) = F(n-1)*n
有区别吗?
没有区别,我认为。
#26
都可以改的,只是复杂程度能不能忍受而已
#27
mark
#28
都可以改的,只是复杂程度能不能忍受而已
----------正确!!
#29
yshuise() ( ) 信誉:100 2006-8-8 7:43:41 得分: 0
尾递归?
F(0)=F(1)=1;
F(n) = n*F(n-1);
和
F(0)=F(1)=1;
F(n) = F(n-1)*n
有区别吗?
没有区别,我认为。
-----------------------------------------
对于较高层次来说,这当然没有区别,但是编译器就能识别这两者有本质的区别。语法数也截然不同
尾递归?
F(0)=F(1)=1;
F(n) = n*F(n-1);
和
F(0)=F(1)=1;
F(n) = F(n-1)*n
有区别吗?
没有区别,我认为。
-----------------------------------------
对于较高层次来说,这当然没有区别,但是编译器就能识别这两者有本质的区别。语法数也截然不同
#30
对于较高层次来说,这当然没有区别,但是编译器就能识别这两者有本质的区别。语法数也截然不同
===
是这样。
===
是这样。
#31
尾递归可以改为非递归
#32
最基本的程序结构,顺序,判断,循环,全部递归都可以被这三种结构表示。
#33
应该都可以改成非递归的。
#34
可以用数学的方法,来把 Hanoi问题,归结为,一个数学符号式子,然后用循环就可以解决。
#35
凡是递归都可以改成循环
#36
理论上所有的递归都可以改成非递归,如果改不了只能说明没想到.而且非递归要比递归省时间和空间,不过更费脑.
#1
一个例子:
Ackerman函数就不能改为非递归
A(1,0)=2
A(0,m)=1 m>=0
A(n,0)=n+2, n>=2
A(n,m)=A(A(n-1,m),m-1) n,m>=1
Ackerman函数就不能改为非递归
A(1,0)=2
A(0,m)=1 m>=0
A(n,0)=n+2, n>=2
A(n,m)=A(A(n-1,m),m-1) n,m>=1
#2
我还知道hanoi也不能改成非递归,
我想要此问题的描述、总结,或者说定理,
而不是个别例子。
3x
我想要此问题的描述、总结,或者说定理,
而不是个别例子。
3x
#3
hanoi也不能改成非递归 ??
能给出证明么?
能给出证明么?
#4
2,已知Ackerman函数的定义如下:
n+1 m=0
akm(m,n) = akm(m-1,1) m0,n=0
akm(m-1,akm(m,n-1)) m0,n0
(1)写出递归算法
(2)写出非递归算法
递归算法:
int akm(int m, int n)
{
if (m == 0) akm = n+1 ;
else if( n == 0)
akm = akm(m-1 , 1);
else
6.4 递归的模拟
{
g=akm(m , n-1);
akm=akm(m-1 , g) ;
}
}//akm
非递归算法:
int akm1(int m , int n)
{/*S[MAX]为附设栈,top为栈顶指针*/
top = 0 ; S[top].mval = m ; S[top-1].nval=n ;
do {
while (S[top].mval){
while(S[top].nval){
top++ ; S[top].mval=S[top-1].mval;
6.4 递归的模拟
S[top].nval=S[top-1].nval-1 ;
}
S[top].mval-- ; S[top].nval=1 ;
}
if (top>0)
{ top -- ;
S[top].mval -- ;
S[top].nval=S[top+1].nval+1;
}
}
while (top !=0 || S[top].mval != 0);
akm1=S[top].nval+1 ; top-- ;
}//akm1
n+1 m=0
akm(m,n) = akm(m-1,1) m0,n=0
akm(m-1,akm(m,n-1)) m0,n0
(1)写出递归算法
(2)写出非递归算法
递归算法:
int akm(int m, int n)
{
if (m == 0) akm = n+1 ;
else if( n == 0)
akm = akm(m-1 , 1);
else
6.4 递归的模拟
{
g=akm(m , n-1);
akm=akm(m-1 , g) ;
}
}//akm
非递归算法:
int akm1(int m , int n)
{/*S[MAX]为附设栈,top为栈顶指针*/
top = 0 ; S[top].mval = m ; S[top-1].nval=n ;
do {
while (S[top].mval){
while(S[top].nval){
top++ ; S[top].mval=S[top-1].mval;
6.4 递归的模拟
S[top].nval=S[top-1].nval-1 ;
}
S[top].mval-- ; S[top].nval=1 ;
}
if (top>0)
{ top -- ;
S[top].mval -- ;
S[top].nval=S[top+1].nval+1;
}
}
while (top !=0 || S[top].mval != 0);
akm1=S[top].nval+1 ; top-- ;
}//akm1
#5
我认为学过数据结构的朋友都知道递归是用栈来实现的,
那么,递归转化为非递归的程序都可以用栈来描述(当然如果用循环就可以解决的就不必了)
so:所有的递归在理论上都可以转化成非递归的。 只不过在转化过程中的难易程度有不同。还有实现所消耗的空间和时间特别大~
那么,递归转化为非递归的程序都可以用栈来描述(当然如果用循环就可以解决的就不必了)
so:所有的递归在理论上都可以转化成非递归的。 只不过在转化过程中的难易程度有不同。还有实现所消耗的空间和时间特别大~
#6
楼上的我可能没说清楚。
我再举个例子吧,比如说求阶乘,
f(n)=n*f(n-1),
这个是递归,
但是这个很容易可以改成递推。
x=1;
for(int i=2;i<=n;i++)
x*=i;
然后就求出结果了,
这就是我要的非递归,
而不是手动使用栈。
但是对于汉诺塔程序,
是不能改成递推的,
你不信可以试试。
我的意思就是说不要使用栈,
直接改成循环。
所以我的问题是,
什么情况下肯定可以把递归改成循环?
我再举个例子吧,比如说求阶乘,
f(n)=n*f(n-1),
这个是递归,
但是这个很容易可以改成递推。
x=1;
for(int i=2;i<=n;i++)
x*=i;
然后就求出结果了,
这就是我要的非递归,
而不是手动使用栈。
但是对于汉诺塔程序,
是不能改成递推的,
你不信可以试试。
我的意思就是说不要使用栈,
直接改成循环。
所以我的问题是,
什么情况下肯定可以把递归改成循环?
#7
for() 和数组 联合在一起,也可以实现栈的哦。。。呵呵!
#8
感觉lz把问题的面!搞的太窄了
#9
栈保存了全部数据,
循环只保存当前数据,
是吧?
循环只保存当前数据,
是吧?
#10
尾递归可以改成迭代,其他的递归都不行。所谓尾递归是指递归调用的语句在递归函数的最后一句,
#11
其实主要就是看这个算法需要的最小空间复杂度是多少.
如果空间复杂度可以降低到O(1),那么就没必要用递归了.
不然,用不用递归本质上没有区别
如果空间复杂度可以降低到O(1),那么就没必要用递归了.
不然,用不用递归本质上没有区别
#12
hanoi是可以用非递归的
#13
guohuang(菜瓜头) ( ) 信誉:100 2006-7-19 10:10:24 得分: 0
尾递归可以改成迭代,其他的递归都不行。所谓尾递归是指递归调用的语句在递归函数的最后一句,
尾递归可以改成迭代,其他的递归都不行。所谓尾递归是指递归调用的语句在递归函数的最后一句,
#14
都可以非递归
对于计算机来说,递归就是一个循环而已
对于计算机来说,递归就是一个循环而已
#15
guohuang(菜瓜头) ( ) 信誉:100 2006-7-19 10:10:24 得分: 0
尾递归可以改成迭代,其他的递归都不行。所谓尾递归是指递归调用的语句在递归函数的最后一句,
==================
前几天做题也看到这个,只是当时没弄明白什么叫尾递归
尾递归可以改成迭代,其他的递归都不行。所谓尾递归是指递归调用的语句在递归函数的最后一句,
==================
前几天做题也看到这个,只是当时没弄明白什么叫尾递归
#16
即使没有栈,
第归也可以改成非第归,
只是需要额外的内存(比如数组)来保存原来准备保存在栈里的相关信息而已.
当然使用栈是简明易懂的方式.
如果不允许使用额外内存空间,
则没有一个简单的办法可以进行判断.
不过,一般而言,
没有额外信息需要临时保存的第归(实际上栈并没有被使用),
都可以改成无栈并且不使用额外空间的非第归,
如果有额外的信息需要临时保存,并且信息量和第归深度成正相关的时候,
就不能改成无栈并且不使用额外空间的非第归。
第归本身就是一种使用栈保存临时信息的方式。
第归也可以改成非第归,
只是需要额外的内存(比如数组)来保存原来准备保存在栈里的相关信息而已.
当然使用栈是简明易懂的方式.
如果不允许使用额外内存空间,
则没有一个简单的办法可以进行判断.
不过,一般而言,
没有额外信息需要临时保存的第归(实际上栈并没有被使用),
都可以改成无栈并且不使用额外空间的非第归,
如果有额外的信息需要临时保存,并且信息量和第归深度成正相关的时候,
就不能改成无栈并且不使用额外空间的非第归。
第归本身就是一种使用栈保存临时信息的方式。
#17
没有办法可改,汉诺塔就是一个例子,不用递归根本解决不了的。
#18
只有尾递归可以直接消除递归!
其他的都需要间接的,如修改算法,栈保存参数和返回值全部或部分信息。
其他的都需要间接的,如修改算法,栈保存参数和返回值全部或部分信息。
#19
什么情况下肯定可以把递归改成循环?
只有尾递归可以直接消除递归!就是循环就可以了
其他的都需要间接的,如修改算法,栈保存参数和返回值全部或部分信息。
比如:
F(0)=F(1)=1;
F(n) = n*F(n-1);
这个可以直接用循环实现
但是如果改为:
F(0)=F(1)=1;
F(n) = F(n-1)*n;
就不能直接消除递归,而需要修改算法,交换F(n-1) 与 n的位置。
如果用语法树来分析就明显了
{a}b
可用语法(1)
S->Ab
A->aA
上面的可以直接消除递归
下面文法(2)
S->Ab
A->Aa
这个就必须先消除左递归才行。
也就是LL(1)文法为什么先要消除左递归,再进行分析的原故。
只有尾递归可以直接消除递归!就是循环就可以了
其他的都需要间接的,如修改算法,栈保存参数和返回值全部或部分信息。
比如:
F(0)=F(1)=1;
F(n) = n*F(n-1);
这个可以直接用循环实现
但是如果改为:
F(0)=F(1)=1;
F(n) = F(n-1)*n;
就不能直接消除递归,而需要修改算法,交换F(n-1) 与 n的位置。
如果用语法树来分析就明显了
{a}b
可用语法(1)
S->Ab
A->aA
上面的可以直接消除递归
下面文法(2)
S->Ab
A->Aa
这个就必须先消除左递归才行。
也就是LL(1)文法为什么先要消除左递归,再进行分析的原故。
#20
所有尾递归和一些特殊的非尾递归(如树的中序遍历)可以改
#21
这是hanoi非递归算法.
include <iostream>
#include <stdlib.h>
#ifdef _WIN32
using namespace std;
#endif
static void hanoi(int height)
{
int fromPole, toPole, Disk;
int *BitStr = new int[height],
*Hold = new int[height];
char Place[] = {'A', 'C', 'B'};
int i, j, temp;
for (i=0; i < height; i++)
{
BitStr[i] = 0;
Hold[i] = 1;
}
temp = 3 - (height % 2);
int TotalMoves = (1 << height) - 1;
for (i=1; i <= TotalMoves; i++)
{
for (j=0 ; BitStr[j] != 0; j++)
{
BitStr[j] = 0;
}
BitStr[j] = 1;
Disk = j+1;
if (Disk == 1)
{
fromPole = Hold[0];
toPole = 6 - fromPole - temp;
temp = fromPole;
}
else
{
fromPole = Hold[Disk-1];
toPole = 6 - Hold[0] - Hold[Disk-1];
}
cout << "Move disk " << Disk << " from " << Place[fromPole-1]
<< " to " << Place[toPole-1] << endl;
Hold[Disk-1] = toPole;
}
}
int main(int argc, char *argv[])
{
cout << "Towers of Hanoi: " << endl
<< "moving a tower of n disks from pole A to pole B by using pole C" << endl;
cout << "Input the height of the original tower: ";
int height;
cin >> height;
hanoi(height);
system("PAUSE");
return EXIT_SUCCESS;
}
问题描述:有三个柱子A, B, C. A柱子上叠放有n个盘子,每个盘子都比它下面的盘子要小一点,可以从上到下用1, 2, ..., n编号。要求借助柱子C,把柱子A上的所有的盘子移动到柱子B上。移动条件为:1、一次只能移一个盘子;2、移动过程中大盘子不能放在小盘子上,只能小盘子放在大盘子上。
算法要点有二:
1、确定哪一个盘子要移动。有n个盘子的Hanoi塔需要移动2^n -1次,设m为n位的二进制数,则m的取值范围为0~2^n -1。让m每次递增1,可以发现,m中最低一位的刚刚由0变为1的位置的位置编号,和即将要移动的盘子编号有确定关系。
2、这个盘子往哪个柱子上移。
a.第一次需要移动1号盘,n为奇数时,1号盘首先移动到柱子B,为偶数时首先移动到柱子C。
b.接下来如果移动的盘子不是1号盘。你有两个柱子可以选择。先找到1号盘所在的柱子,因为移动的盘子不能叠放到1号盘上,所以该盘可以移动的位置就是没有1号盘的那个柱子。
c.如果移动的盘子是1号盘。也有两个柱子可以选择。找到1号盘原先是从哪个柱子上移来的,因为移动的顺序(顺时针或逆时针)一旦确定,就不会更改,所以排除from的那个柱子后,移动方向也就唯一了。
include <iostream>
#include <stdlib.h>
#ifdef _WIN32
using namespace std;
#endif
static void hanoi(int height)
{
int fromPole, toPole, Disk;
int *BitStr = new int[height],
*Hold = new int[height];
char Place[] = {'A', 'C', 'B'};
int i, j, temp;
for (i=0; i < height; i++)
{
BitStr[i] = 0;
Hold[i] = 1;
}
temp = 3 - (height % 2);
int TotalMoves = (1 << height) - 1;
for (i=1; i <= TotalMoves; i++)
{
for (j=0 ; BitStr[j] != 0; j++)
{
BitStr[j] = 0;
}
BitStr[j] = 1;
Disk = j+1;
if (Disk == 1)
{
fromPole = Hold[0];
toPole = 6 - fromPole - temp;
temp = fromPole;
}
else
{
fromPole = Hold[Disk-1];
toPole = 6 - Hold[0] - Hold[Disk-1];
}
cout << "Move disk " << Disk << " from " << Place[fromPole-1]
<< " to " << Place[toPole-1] << endl;
Hold[Disk-1] = toPole;
}
}
int main(int argc, char *argv[])
{
cout << "Towers of Hanoi: " << endl
<< "moving a tower of n disks from pole A to pole B by using pole C" << endl;
cout << "Input the height of the original tower: ";
int height;
cin >> height;
hanoi(height);
system("PAUSE");
return EXIT_SUCCESS;
}
问题描述:有三个柱子A, B, C. A柱子上叠放有n个盘子,每个盘子都比它下面的盘子要小一点,可以从上到下用1, 2, ..., n编号。要求借助柱子C,把柱子A上的所有的盘子移动到柱子B上。移动条件为:1、一次只能移一个盘子;2、移动过程中大盘子不能放在小盘子上,只能小盘子放在大盘子上。
算法要点有二:
1、确定哪一个盘子要移动。有n个盘子的Hanoi塔需要移动2^n -1次,设m为n位的二进制数,则m的取值范围为0~2^n -1。让m每次递增1,可以发现,m中最低一位的刚刚由0变为1的位置的位置编号,和即将要移动的盘子编号有确定关系。
2、这个盘子往哪个柱子上移。
a.第一次需要移动1号盘,n为奇数时,1号盘首先移动到柱子B,为偶数时首先移动到柱子C。
b.接下来如果移动的盘子不是1号盘。你有两个柱子可以选择。先找到1号盘所在的柱子,因为移动的盘子不能叠放到1号盘上,所以该盘可以移动的位置就是没有1号盘的那个柱子。
c.如果移动的盘子是1号盘。也有两个柱子可以选择。找到1号盘原先是从哪个柱子上移来的,因为移动的顺序(顺时针或逆时针)一旦确定,就不会更改,所以排除from的那个柱子后,移动方向也就唯一了。
#22
首先那要看你怎么理解递归.用栈对递归过程进行原始模拟,并没有从本质上改变递归算法的计算过程,但是如果以递归调用为形式的算法称为递归算法,其他的不是,那么模拟后的算法就不是递归算法,这也就可以说任何递归算法都是可以用非递归形式来实现.
#23
另一种理解,用堆栈实现递归只是模拟了递归的计算过程,并没有消除递归,真正的非递归是指运算所需空间与问题的输入规模无关。当然尾递归可以用迭代来实现非递归,还有把递归转化为尾递归,再转化为迭代,例如用Cooper变换就可以把一大类的递归转化为尾递归。可是并不是所有的递归都可以用迭代实现,例如Ackmann函数就无法用迭代计算.其实正如当年海星所说,转换只是一种模拟,实际上是用人脑完成了电脑的某些过程.
#24
mark
#25
尾递归?
F(0)=F(1)=1;
F(n) = n*F(n-1);
和
F(0)=F(1)=1;
F(n) = F(n-1)*n
有区别吗?
没有区别,我认为。
F(0)=F(1)=1;
F(n) = n*F(n-1);
和
F(0)=F(1)=1;
F(n) = F(n-1)*n
有区别吗?
没有区别,我认为。
#26
都可以改的,只是复杂程度能不能忍受而已
#27
mark
#28
都可以改的,只是复杂程度能不能忍受而已
----------正确!!
#29
yshuise() ( ) 信誉:100 2006-8-8 7:43:41 得分: 0
尾递归?
F(0)=F(1)=1;
F(n) = n*F(n-1);
和
F(0)=F(1)=1;
F(n) = F(n-1)*n
有区别吗?
没有区别,我认为。
-----------------------------------------
对于较高层次来说,这当然没有区别,但是编译器就能识别这两者有本质的区别。语法数也截然不同
尾递归?
F(0)=F(1)=1;
F(n) = n*F(n-1);
和
F(0)=F(1)=1;
F(n) = F(n-1)*n
有区别吗?
没有区别,我认为。
-----------------------------------------
对于较高层次来说,这当然没有区别,但是编译器就能识别这两者有本质的区别。语法数也截然不同
#30
对于较高层次来说,这当然没有区别,但是编译器就能识别这两者有本质的区别。语法数也截然不同
===
是这样。
===
是这样。
#31
尾递归可以改为非递归
#32
最基本的程序结构,顺序,判断,循环,全部递归都可以被这三种结构表示。
#33
应该都可以改成非递归的。
#34
可以用数学的方法,来把 Hanoi问题,归结为,一个数学符号式子,然后用循环就可以解决。
#35
凡是递归都可以改成循环
#36
理论上所有的递归都可以改成非递归,如果改不了只能说明没想到.而且非递归要比递归省时间和空间,不过更费脑.