递归——汉诺塔

直入主题!!!

递归:将一个大的问题分解成比较小的,有着相同形式的问题去解决。

递归和迭代的区别

递归: 

】  

】】

】】】

】】

迭代:

】】

】】

】】

】】

】】

递归可以理解为朋友之间礼尚往来,有来有回。

迭代可以理解为找了个女朋友,买...买...买...,“你是个好人...”

下面我们通过一个简单的例子来认识下递归:

//求5的阶乘

function factorial(n) {

    if ( n <= 1 ) {

        return 1;

    } else {

        return n * factorial( n - 1 );

    }

}

factorial(5)

上面这个例子用递归实现了求5的阶乘,我们可以从这个例子中看到递归的一些特质:

1、递归就是函数里调用自身。

2、在使用递增归策略时,必须有一个明确的递归结束条件,称为递归出口。

3、递归程序通常显得很简洁,但递归运行效率较低。

4、在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储,占用内存。递归次数过多容易造成栈溢出等。

那么我们在何种条件下可以使用递归呢?

1、必须能够鉴别出一个简单的场景,且该场景的答案是容易肯定的。

2、必须能够确定一个递归的分解方式,能够将问题的复杂实例分解为更小的、具有相同形式的问题。

下面我们用一个经典的案例,来体会一下递归的神奇魅力——汉诺塔

        在被认为是世界中心的贝拿勒斯的神庙里,一个黄铜盘上固定了三个宝座,每一个都又高又粗。上帝造万物时,在其中的一个宝座上放了64只纯金圆盘,最大的盘子放在黄铜盘上,然后依次叠放,直到最小盘放在最顶上,这就是梵天塔。住持日夜不停地把这些盘子从一个宝座上移到另外一个宝座上,但他需要遵守一些固定的永远不变的梵天规则,即住持每次只能移动一个盘子,且必须把这个盘子放在一个宝座上而没有更小的盘子在它的下面。当所有的64只盘子都已从上帝造物时所放置的宝座上移到另外的一个宝座上时,塔和庙宇都将坍塌,随着一声雷鸣,世界末日来到了。

摘自 亨利·德·帕维勒《自然》

这就是汉诺塔的背景故事了,在这个问题上迭代就不能起到应有的效果了,我们只能用递归去解决。

首先确认规则:

1、每次只能移动一个盘。

2、在移动过程中,始终保持大盘在下,小盘在上。                                        

为了便于处理,我们只考虑塔上有三个圆盘时所发生的情况

递归——汉诺塔_第1张图片

根据我们上面所说的使用递归的两个条件进行分析:

1、需要找到一个简单的场景:如果塔盘只有一只圆盘,那这就是它对简单的场景。

2、可以把问题分解成更简单的、形式相同的子问题:

        思考过后我们会发现,可以将其分为三个步骤来解决:

        1)把上边堆积的2个圆盘从A座移动到C座上。

        2)把底部的圆盘从A座移动到B座上。

        3)把2只圆盘从C座移动到B座上。

实施第一步后,圆盘位置如下图所示:


递归——汉诺塔_第2张图片

一旦成功地将最大的圆盘上面的2只从A座移动到C座,第二步就很简单了,只需要把大圆盘从A座移动到B座上,就会出现如下图所示的情况:


递归——汉诺塔_第3张图片

剩下的工作就是把2只圆盘形成的盘塔从C座移动回B座上,这又是一个相同形式的规模更小的问题。这是递归策略中的第三步,从而使问题得到解决:


递归——汉诺塔_第4张图片

就是这样,我们成功把三个圆盘的问题转化为了两个圆盘,所以当圆盘为N的时候,递归策略可以归纳如下:

1、把上面的N-1只圆盘从起始座移动到临时座上。

2、把剩下的唯一的圆盘从起始座移动到目标座上。

3、把N-1只圆盘组成的塔盘从临时座上移动到目标座上。

下面我们就用代码来实现一下这个问题:

var hanoi = function(num,start,finish,temp){

    if(num == 1){

        console.log(`移动 1号盘 从 ${start} 到 ${finish}`)

    }else{

        //把上面的N-1只圆盘从起始座移动到临时座上。此时temp位置对于N-1的圆盘来说就是finish位置

        hanoi(num-1,start,temp,finish);

        console.log(`移动 ${num}号盘 从 ${start} 到 ${finish}`);

        //把N-1只圆盘组成的塔盘从临时座上移动回到目标座上。此时temp位置对于N-1的圆盘来说就是start位置

        hanoi(num-1,temp,finish,start);

    }    

}

hanoi(3,'A','B','C')

运行结果如下:


递归——汉诺塔_第5张图片

        以上就是汉诺塔的解决思路了。这也很明显的体现了递归的魔力!!!我们只要给出合理的分解,其余的都教由计算机去处理,节省了我们宝贵的脑细胞。因为内部的过程我们没办法看见,所以要有递归跳跃的思想,也就是说要信任递归流程,相信它没问题。

        To iterate is human, to recurse divine.—— L. Peter Deutsch,迭代是人,递归是神,我们这些凡人只能慢慢体会,量力而行喽:)。

你可能感兴趣的:(递归——汉诺塔)