采用递归和非递归方法求解Hanoi问题

时间:2020-04-10
本文章向大家介绍采用递归和非递归方法求解Hanoi问题,主要包括采用递归和非递归方法求解Hanoi问题使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

目的:领会基本递归算法设计和递归到非递归的转换方法

内容:编写一个程序exp5-1.cpp,采用递归和非递归方法求解Hanoi问题,输出三个盘片的移动过程

写在前面

题目是昨天老师发在学习通上的,目前

解决了:

  1. Hanoi问题理解
  2. Hanoi递归算法及其实现

未解决的:

  1. Hanoi非递归算法及实现
    (PPT上是用栈来实现的,然而笔者对栈不熟...解决完再记上来吧)

以下就从解决了的两个方面展开讨论

Hanoi问题理解

笔者参考的是算法动态图解app上的解释,还挺直观的:

简单来说就是有X,Y,Z三个柱子,目标是将X柱子上的盘片移动到Y柱子上,同时要保持和X柱相同的顺序。X柱子上盘片自下而上、由大到小放置着n个盘片,两个要求:

Ⅰ. 一次只能移一个盘片

Ⅱ.不能把大盘片放在小盘片上

个人的理解:
首先,为了方便分析,将X柱上盘片自上而下依次编号为\(1,2...n\)

  • 当n=1时,即A柱上只有一个盘片,直接从X移动到Z,这是最简单的情况
  • 当n=2 时,
    第一步,把1号移动到Y柱(因为要满足要求Ⅱ,2号盘片必须第一个移动到Z柱上,那么必须把1号先移开,移动到哪里?肯定不能是Z柱,那么就是Y柱了)
    第二步,把2号盘移到Z柱
    第三步,把1号从Y柱移动到Z柱,完成!
  • 当n=3时,
    第一步,可以把1号,2号盘,通过Z柱移到Y柱,这在前面(n=2时)已经证明可行。
    第二步,把3号盘移到Y柱
    第三步,发现问题转化为n=2的情况,即把1号,2号盘,从Y柱移动到Z柱,方法参见n=2,不再赘述

写到这里,我们发现这个问题是可递归的,n个盘片的Hanoi问题可以通过n-1个盘片的Hanoi问题求得,抽象成数学语言就是$$f(n)=g(f(n-1),c_{n-1}),f(1)=m_1$$

要求\(f(n)\),可先求\(f(n-1),f(n-2)...\),层层递归,直到\(f(1)\)


Hanoi递归算法及其实现
递归模型及递归算法
  • 设计递归模型
    可以看出递归模型分为递归体,递归出口两个部分,其实就是高中数学数列,递归函数概念
  • 设计递归算法(以本题为例)
    把盘片数,X柱,Y柱,Z柱分别抽象成自定义函数的四个参数n,X,Y,Z
void Hanoi1(int n,char X,char Y,char Z)

分别用if语句,else语句描述递归出口与递归体

  • 算法代码:

//递归法
void Hanoi1(int n,char X,char Y,char Z){

    
        if(n==1){
        printf("\t将第%d个盘片从%c移动到%c\n",n,X,Z);//递归出口,当只有一个盘片时     }
        else {
        Hanoi1 (n-1,X,Z,Y);//将n-1个盘片,通过z,从x移动到y
        printf ("\t把第%d个盘片从%c移动到%c\n",n,X,Z);//将第n个盘片,从x移动到z
        Hanoi1 (n-1,Y,X,Z);//将n-1个盘片,通过x,从y移动到z
        
        }
}

Hanoi递归算法的实现

理解了算法代码的实现,接下来就就是"搬砖"阶段了

在main()函数里分别初始化三个参数的值,然后调用Hanoi1()就可以了

完整代码:

#include <iostream>
using namespace std;

//递归法
void Hanoi1(int n,char X,char Y,char Z){

    
        if(n==1){
        printf("\t将第%d个盘片从%c移动到%c\n",n,X,Z);//递归出口,当只有一个盘片时
    }
    else {
        Hanoi1 (n-1,X,Z,Y);//将n-1个盘片,通过z,从x移动到y
        printf ("\t把第%d个盘片从%c移动到%c\n",n,X,Z);//将第n个盘片,从x移动到z
        Hanoi1 (n-1,Y,X,Z);//将n-1个盘片,通过x,从y移动到z
        
    }
}
int main() {
    int n=3;
    char X='x',Y='y',Z='z';
    cout <<"递归法过程:"<<endl;
    Hanoi1 (n,X,Y,Z);
    return 0;
}

运行截图:


写在最后

在"搬砖"的过程中,出现了许多错误,变量未初始化(uninitialzing),函数未指名(not declared) ...原因在于没有经历完整的c语言编程过程,只是看教材的代码,效率确实太低了。

原文地址:https://www.cnblogs.com/hzyb2018/p/12672049.html