汉诺塔问题的非递归实现
- 格式:docx
- 大小:19.25 KB
- 文档页数:4
汉诺塔原理汉诺塔(Tower of Hanoi)是一个经典的数学问题,它源自印度的一个古老传说。
传说中,在贝拿勒斯(Benares)的圣庙里,一块黄铜板上插着三根宝石针。
初始时,所有的圆盘都放在一根针上,小的在上,大的在下。
这些圆盘按从小到大的次序排列。
有一个僧侣的职责是把这些圆盘从一个针移到另一个针上。
在移动过程中,可以借助第三根针,但有一个条件,就是在小的圆盘上不能放大的圆盘。
当所有的圆盘都从一根针上移到另一根针上时,这个世界就将毁灭。
汉诺塔问题的数学模型是,设有n个圆盘和三根柱子(我们称之为A、B、C),开始时所有的圆盘都叠在柱子A上,按照大小顺序从上到下叠放。
要求把所有的圆盘从柱子A移动到柱子C上,期间可以借助柱子B,但有一个限制条件,任何时刻都不能把一个大的圆盘放在一个小的圆盘上面。
汉诺塔问题的解法是一个典型的递归算法。
整个移动过程可以分解为三个步骤:1. 把n-1个圆盘从柱子A经过柱子C移动到柱子B上;2. 把第n个圆盘从柱子A移动到柱子C上;3. 把n-1个圆盘从柱子B经过柱子A移动到柱子C上。
这个过程可以用递归的方式来描述。
当我们解决n-1个圆盘的问题时,可以再次把它分解为n-2个圆盘的问题,直到最后只剩下一个圆盘的问题,这就是递归的思想。
递归算法虽然简洁,但是在实际应用中需要注意避免出现栈溢出的情况。
除了递归算法外,汉诺塔问题还有非递归的解法。
可以利用栈来模拟递归的过程,将每一步的移动操作保存在栈中,依次执行,直到所有的圆盘都移动到目标柱子上。
汉诺塔问题不仅是一个数学问题,更是一个思维训练的好题目。
它可以锻炼人的逻辑思维能力和动手能力。
在计算机科学中,递归算法是一种非常重要的思想,很多经典的算法问题都可以用递归的方式来解决。
总之,汉诺塔问题是一个古老而经典的数学问题,它不仅有着深奥的数学原理,更能锻炼人的思维能力。
通过研究汉诺塔问题,我们可以更好地理解递归算法的原理,提高自己的编程能力和解决问题的能力。
汉诺塔问题串串烧12009-05-17 15:39汉诺塔问题串串烧1. 相传在古印度的布拉玛婆罗门圣庙的僧侣在进行一种被称为汉诺塔的游戏,其装置是一块铜板,上面有三根杆(编号A、B、C),A杆上自下而上、由大到小按顺序串上64个金盘(如图1)。
游戏的目标是把A杆上的金盘全部移到C 杆上,并仍原有顺序叠好。
条件是每次只能移动一个盘,并且在每次移动都不允许大盘移到小盘之上。
现要求利用递归调用技术给出N个盘从A杆移到C杆的移动过程。
图1 N阶汉诺塔分析:这个移动过程很复杂与烦琐,但规律性却很强。
使用递归调用技术来解决这个移动过程,先得找到一个递归调用模型。
想要得到汉诺塔问题的简单解法,着眼点应该是移动A杆最底部的大盘,而不是其顶部的小盘。
不考虑64个盘而考虑N个盘的一般情况。
要想将A杆上的N个盘移至C杆,我们可以这样设想:1.以C盘为临时杆,从A杆将1至N-1号盘移至B杆。
2.将A杆中剩下的第N号盘移至C杆。
3.以A杆为临时杆,从B杆将1至N-1号盘移至C杆。
我们看到,步骤2只需移动一次就可以完成;步骤1与3的操作则完全相同,唯一区别仅在于各杆的作用有所不同。
这样,原问题被转换为与原问题相同性质的、规模小一些的新问题(图4)。
即:HANOI(N,A,B,C) 可转化为HANOI(N-1,A,C,B)与HANOI(N-1,B,A,B)其中HANOI中的参数分别表示需移动的盘数、起始盘、临时盘与终止盘,这种转换直至转入的盘数为0为止,因为这时已无盘可移了。
这就是需要找的递归调用模型。
图2 N-1阶汉诺塔源程序如下:program ex11_12;vara,b,c:char;n:byte;procedure hanoi(n:byte;a,b,c:char);beginif n>0 thenbeginhanoi(n-1,a,c,b);writeln('Move ',a,' to ',c);hanoi(n-1,b,a,c);end;end;a:='A';b:='B';c:='C';write('N=');readln(n);hanoi(n,a,b,c);end.一般的算法是很难解决这个问题的,而过程HONOI只用了4个语句就解决这个难题。
汉诺塔问题数学解法汉诺塔问题是一个经典的数学难题,也是计算机科学中的常见算法题目。
在这个问题中,我们需要将三个塔座上的圆盘按照一定规则从一座塔移动到另一座塔,只能每次移动一个圆盘,并且在移动过程中始终保持大圆盘在小圆盘下面。
为了解决汉诺塔问题,我们首先需要了解递归的概念。
递归是一种问题解决方法,其中问题被分解为更小的子问题,直到最小的问题可以直接解决。
在汉诺塔问题中,我们可以使用递归来实现移动圆盘的步骤。
设有三个塔座,分别为A、B、C,并且初始时所有的圆盘都在A 塔上,我们的目标是将所有的圆盘移动到C塔上。
为了方便讨论,我们将最小的圆盘称为第1号圆盘,次小的圆盘称为第2号圆盘,以此类推,最大的圆盘称为第n号圆盘。
解决汉诺塔问题的数学解法如下:1. 当只有一个圆盘时,直接将它从A塔移动到C塔,移动结束。
2. 当有两个或以上的圆盘时,可以按照以下步骤进行移动:(1) 先将上面n-1个圆盘从A塔移动到B塔(借助C塔)。
(2) 将第n号圆盘从A塔移动到C塔。
(3) 最后将n-1个圆盘从B塔移动到C塔(借助A塔)。
通过以上步骤,我们可以将n个圆盘从A塔移动到C塔,完成整个汉诺塔问题的解。
这个数学解法的正确性可以通过递归的思想来解释。
当有n个圆盘时,我们需要借助第三个塔座将前n-1个圆盘移动到B塔上,然后将第n号圆盘移动到C塔上,最后再将n-1个圆盘从B塔移动到C塔上。
这个过程可以看作是一个递归过程,我们首先需要将前n-1个圆盘从A 塔移动到B塔上,然后再将第n号圆盘从A塔移动到C塔上,最后再将n-1个圆盘从B塔移动到C塔上。
通过不断缩小问题规模,我们最终可以将整个汉诺塔问题解决。
总结起来,汉诺塔问题是一个经典的数学难题,解决这个问题可以使用递归的数学解法。
通过将问题分解为更小的子问题,我们可以将n 个圆盘从一座塔移动到另一座塔上。
这个数学解法的正确性可以通过递归的思想来解释。
希望通过以上的介绍,您对汉诺塔问题的数学解法有了更深入的理解。
由来法国数学家爱德华·卢卡斯曾编写过一个印度的古老传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针。
印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔。
不论白天黑夜,总有一个僧侣在按照下面的法则移动这些金片:一次只移动一片,不管在哪根针上,小片必须在大片上面。
僧侣们预言,当所有的金片都从梵天穿好的那根针上移到另外一根针上时,世界就将在一声霹雳中消灭,而梵塔、庙宇和众生也都将同归于尽。
[2]不管这个传说的可信度有多大,如果考虑一下把64片金片,由一根针上移到另一根针上,并且始终保持上小下大的顺序。
这需要多少次移动呢?这里需要递归的方法。
假设有n 片,移动次数是f(n).显然f(1)=1,f(2)=3,f(3)=7,且f(k+1)=2*f(k)+1。
此后不难证明f(n)=2^n-1。
n=64时,假如每秒钟一次,共需多长时间呢?一个平年365天有31536000 秒,闰年366天有31622400秒,平均每年31556952秒,计算一下:18446744073709551615秒这表明移完这些金片需要5845.54亿年以上,而地球存在至今不过45亿年,太阳系的预期寿命据说也就是数百亿年。
真的过了5845.54亿年,不说太阳系和银河系,至少地球上的一切生命,连同梵塔、庙宇等,都早已经灰飞烟灭。
印度传说和汉诺塔故事相似的,还有另外一个印度传说:舍罕王打算奖赏国际象棋的发明人──宰相西萨·班·达依尔。
国王问他想要什么,他对国王说:“陛下,请您在这张棋盘的第1个小格里赏给我一粒麦子,在第2个小格里给2粒,第3个小格给4粒,以后每一小格都比前一小格加一倍。
请您把这样摆满棋盘上所有64格的麦粒,都赏给您的仆人吧!”国王觉得这个要求太容易满足了,就命令给他这些麦粒。
当人们把一袋一袋的麦子搬来开始计数时,国王才发现:就是把全印度甚至全世界的麦粒全拿来,也满足不了那位宰相的要求。
concreteHAM:现在有三根相邻的柱子,标号为A,B,C,A柱子上从下到上按金字塔状叠放着n个不同大小的圆盘,现在把所有盘子一个一个移动到柱子B上,并且每次移动同一根柱子上都不能出现大盘子在小盘子上方,请问至少需要多少次移动,设移动次数为H(n)。
首先我们肯定是把上面n-1个盘子移动到柱子C上,然后把最大的一块放在B上,最后把C上的所有盘子移动到B上,由此我们得出表达式:H(1) = 1H(n) = 2*H(n-1)+1 (n>1)那么我们很快就能得到H(n)的一般式:H(n) = 2^n - 1 (n>0)并且这种方法的确是最少次数的,证明非常简单,可以尝试从2个盘子的移动开始证,你可以试试。
进一步加深问题(解法原创*_*):假如现在每种大小的盘子都有两个,并且是相邻的,设盘子个数为2n,问:(1)假如不考虑相同大小盘子的上下要多少次移动,设移动次数为J(n);(2)只要保证到最后B上的相同大小盘子顺序与A上时相同,需要多少次移动,设移动次数为K(n)。
(1)中的移动相当于是把前一个问题中的每个盘子多移动一次,也就是:J(n) = 2*H(n) = 2*(2^n - 1) = 2^(n+1)-2在分析(2)之前,我们来说明一个现象,假如A柱子上有两个大小相同的盘子,上面一个是黑色的,下面一个是白色的,我们把两个盘子移动到B上,需要两次,盘子顺序将变成黑的在下,白的在上,然后再把B上的盘子移动到C 上,需要两次,盘子顺序将与A上时相同,由此我们归纳出当相邻两个盘子都移动偶数次时,盘子顺序将不变,否则上下颠倒。
现在回到最开始的问题,n个盘子移动,上方的n-1个盘子总移动次数为2*H(n-1),所以上方n-1个盘子的移动次数必定为偶数次,最后一个盘子移动次数为1次。
讨论问题(2),综上两点,可以得出,要把A上2n个盘子移动到B上,首先可以得出上方的2n-2个盘子必定移动偶数次,所以顺序不变,移动次数为:J(n-1) = 2^n-2然后再移动倒数第二个盘子,移动次数为2*J(n-1)+1 = 2^(n+1)-3,最后移动最底下一个盘子,所以总的移动次数为:K(n) = 2*(2*J(n-1)+1)+1 = 2*(2^(n+1)-3)+1 = 2^(n+2)-5开天辟地的神勃拉玛(和中国的盘古差不多的神吧)在一个庙里留下了三根金刚石的棒,第一根上面套着64个圆的金片,最大的一个在底下,其余一个比一个小,依次叠上去,庙里的众僧不倦地把它们一个个地从这根棒搬到另一根棒上,规定可利用中间的一根棒作为帮助,但每次只能搬一个,而且大的不能放在小的上面。
第1篇一、实验目的河内塔问题,又称汉诺塔问题,是一个经典的递归问题。
通过本实验,旨在掌握递归算法的基本原理,了解递归算法在解决实际问题中的应用,并学会使用递归方法解决汉诺塔问题。
二、实验原理汉诺塔问题源于印度的一个古老传说。
问题共有三根柱子,分别为A、B、C,A柱子上叠放着n个大小不同的圆盘,从大到小依次排列。
要求将A柱子上的圆盘全部移动到C柱子上,移动过程中,每次只能移动一个圆盘,且大盘子不能放在小盘子上面。
递归算法是一种将问题分解为若干个规模较小的相同问题,然后逐个解决这些子问题的算法。
汉诺塔问题可以通过递归算法解决,其递归过程如下:1. 将前n-1个盘子从A柱子移动到B柱子上;2. 将最大的盘子从A柱子移动到C柱子上;3. 将B柱子上的n-1个盘子移动到C柱子上。
三、实验步骤1. 初始化三个柱子A、B、C,A柱子上叠放n个圆盘;2. 输入圆盘的个数n;3. 调用递归函数,实现汉诺塔问题的解决;4. 输出移动步骤和移动次数。
四、实验结果与分析1. 实验结果以n=3为例,实验结果如下:移动步骤:1. 将盘子1从A柱子移动到B柱子上;2. 将盘子2从A柱子移动到C柱子上;3. 将盘子1从B柱子移动到C柱子上;4. 将盘子3从A柱子移动到B柱子上;5. 将盘子1从C柱子移动到A柱子上;6. 将盘子2从C柱子移动到B柱子上;7. 将盘子1从A柱子移动到B柱子上;8. 将盘子3从B柱子移动到C柱子上。
移动次数:8次2. 实验分析(1)递归算法的基本思想是将问题分解为若干个规模较小的相同问题,从而降低问题的复杂度。
在汉诺塔问题中,通过递归调用,将问题分解为移动n-1个盘子、移动一个盘子、移动n-1个盘子三个子问题,逐步解决问题。
(2)递归算法的时间复杂度为O(2^n),其中n为圆盘的个数。
当n较大时,递归算法的效率较低。
因此,在实际应用中,可以采用非递归算法或其他优化方法来解决汉诺塔问题。
(3)递归算法的空间复杂度为O(n),其中n为圆盘的个数。
汉诺塔递归算法c++语言一、算法概述汉诺塔问题是经典的递归问题,涉及到移动物体的操作和递归解决问题的策略。
通过使用C语言编写汉诺塔递归算法,我们可以更深入地理解递归思维和解决复杂问题的技巧。
二、算法描述汉诺塔问题的基本描述如下:有n个大小不一、重量不同、用不同材质制成的盘子,将它们从A柱移动到C柱,每次只能移动一个盘子,且每次移动的盘子必须放在比它小的柱子上。
汉诺塔递归算法的核心思想是将复杂问题分解为更小的子问题,直到达到基本情况(即无子问题需要解决),然后通过递归调用返回基本情况的结果,从而解决原始问题。
三、C语言实现以下是用C语言实现汉诺塔递归算法的代码:```c#include<stdio.h>voidhanoi(intn,charfrom,chartemp,charto){if(n==1){printf("Movedisk1from%cto%c\n",from,to);}else{//将n-1个盘子从from柱移动到temp柱,将最大的盘子从from柱移动到to柱hanoi(n-1,from,to,to);//递归调用,解决子问题//将最大的盘子从temp柱移动到to柱printf("Movedisk%dfrom%cto%c\n",n,from,to);//将n-1个盘子从to柱移动到temp柱,以便于将最大的盘子移动到to柱hanoi(n-1,temp,from,to);//递归调用,解决子问题){}}intmain(){intn=3;//盘子数量,可以根据需要修改hanoi(n,'A','B','C');//调用函数,将盘子从A柱移动到C柱return0;}```四、总结与思考通过使用C语言实现汉诺塔递归算法,我们可以更深入地理解递归思维和解决复杂问题的技巧。
在实际应用中,递归算法通常适用于那些可以分解为更小子问题的情况,通过逐个解决子问题,最终达到解决原始问题的目的。
路漫漫其修远兮,吾将上下而求索 - 百度文库
1
汉诺塔问题的非递归实现
#include
#include
#include
//第0位置是柱子上的塔盘数目
int zhua[100]={0},zhub[100]={0},zhuc[100]={0};
char charis(char x,int n)
//左右字符出现顺序固定,且根据n值奇偶而不同
{
switch(x)
{
case 'A':
return (n%2==0)?'C':'B';
case 'B':
return (n%2==0)?'A':'C';
case 'C':
return (n%2==0)?'B':'A';
default:
return '0';
}
}
void print(char lch,char rch)
//打印字符
{
if(lch=='A')
{
switch(rch)
{
case 'B':
zhub[0]++;
zhub[zhub[0]]=zhua[zhua[0]];
zhua[zhua[0]]=0;
zhua[0]--;
break;
case 'C':
zhuc[0]++;
zhuc[zhuc[0]]=zhua[zhua[0]];
zhua[zhua[0]]=0;
zhua[0]--;
break;
default:
break;
路漫漫其修远兮,吾将上下而求索 - 百度文库
2
}
}
if(lch=='B')
{
switch(rch)
{
case 'A':
zhua[0]++;
zhua[zhua[0]]=zhub[zhub[0]];
zhub[zhub[0]]=0;
zhub[0]--;
break;
case 'C':
zhuc[0]++;
zhuc[zhuc[0]]=zhub[zhub[0]];
zhub[zhub[0]]=0;
zhub[0]--;
break;
default:
break;
}
}
if(lch=='C')
{
switch(rch)
{
case 'A':
zhua[0]++;
zhua[zhua[0]]=zhuc[zhuc[0]];
zhuc[zhuc[0]]=0;
zhuc[0]--;
break;
case 'B':
zhub[0]++;
zhub[zhub[0]]=zhuc[zhuc[0]];
zhuc[zhuc[0]]=0;
zhuc[0]--;
break;
default:
break;
}
}
printf("\t");
int i;
路漫漫其修远兮,吾将上下而求索 - 百度文库
3
printf("(");
for(i=1;i<=zhua[0];i++)
printf(" %d ",zhua[i]);
printf(")");
printf("(");
for(i=1;i<=zhub[0];i++)
printf(" %d ",zhub[i]);
printf(")");
printf("(");
for(i=1;i<=zhuc[0];i++)
printf(" %d ",zhuc[i]);
printf(")");
printf("\n");
}
void Hannuo(int n)
{
//分配2^n个空间
bool *isrev;
isrev=(bool *)malloc(sizeof(bool)*(int)pow(2,n));
for(int i=1;i
//循环计算是否逆序
for(int ci=2;ci<=n;ci++)
{
for(int zixh=(int)pow(2,ci-1);zixh
isrev[zixh]=isrev[(int)pow(2,ci)-zixh];
//该位置为中间位置,且奇次幂逆序,偶数幂不逆序
isrev[(int)pow(2,ci)]=((ci-1)%2==0)?false:true;
}
char lch='A',rch;
rch=(n%2==0?'B':'C');
printf("%d\t",1);
printf("%c->%c",lch,rch);
print(lch,rch);
for(int k=2;k
if(k%2==0)
rch=charis(lch,n);
else
lch=charis(rch,n);
printf("%d\t",k);
if(isrev[k])
路漫漫其修远兮,吾将上下而求索 - 百度文库
4
{
printf("%c->%c",rch,lch);
print(rch,lch);
}
else
{
printf("%c->%c",lch,rch);
print(lch,rch);
}
}
}
int main()
{
int n;
printf("Input the num:");
scanf("%d",&n);
zhua[0]=n;
for(int i=1;i<=n;i++)
zhua[i]=n-i+1;
Hannuo(n);
return 0;
}