C语言实现打印n层汉诺塔的图形解,并使键盘输入一次显示一步解

C语言实现打印n层汉诺塔的图形解,并使键盘输入一次显示一步解,第1张

程序源码(前半部分注释请忽略)

2022/04/22/Project1/Project1/project.c · 将车/c_practice - Gitee.com

之前写过一篇关于汉诺塔问题的博客,但是那个博客只是输出了字母解,而且我现在回头看,不是完全明白自己写的是什么意思

干脆详细写一篇输出汉诺塔图形解的程序

所谓图形解,以2层汉诺塔举例如图

如上,我们程序的思路是

 1,首先建立三个数组用来表示图形中的柱子和盘子

数字代表盘子大小号码,| 代表柱子

2,确定汉诺塔的层数

3,然后初始化数组

并打印初始化数组 

4,利用递归拆解汉诺塔问题

接下来是各种函数的写法(执行递归的函数在最后面)

一,初始化函数 chu_shi_hua()

 看了这个函数,草履虫都直呼简单,值得注意的是我们将一个字符存入整形数组中,存储的是该

字符的ASCII码值,在之后的打印函数中我们打印这个字符应该使用%c与打印数字的%d分开

我这里设置的是最大为10层塔,当然也可以更改,大于50算半天或者栈溢出

二,打印数组的函数 print()

 因为我们需要的图形分为字符符号和数字符号,所以打印这样的数组需要在循环中进行多次判断

以确定需要打印的是字符还是数字

同时我们在打印函数的最后再加一个循环,用来实现每次输入1,则汉诺塔解一步

具体思路是,要求玩家输入一个数字,如果为1则跳出循环,结束打印函数,继续后面的程序

否则,就一直执行打印函数

三,移动函数 move()         ********非常重要仅次于递归

 思路是,在求汉诺塔的递归函数中,每当确定了需要移动的盘子在那个柱子,和移动向那个柱子后,将其传递给移动函数

移动函数,找到该取盘子的柱子上可以取的盘子,放到放盘子的柱子可以放的位置

当数组下标从0 -> 9逐渐增大

取的柱子的数组下标对应的元素为 ‘|’ 时  ,  说明上一个数组下标对应的元素为取得盘子

同理,放的柱子下标为 ‘|’ 时就可以放

由于在执行递归的函数中,到底那个形参对应那个实参很难分清楚,而且规律并不统一

所以本人在尝试了一天直接在递归函数中打印数组之后终于放弃了

为什么不干脆多传一组参数,让这个多出来的一组参数,不因为递归而改变

使这些多出来的形参地址和实参地址直接对应便于打印

因此,我给执行递归的函数多传了一组参数,且保证,多层递归中,这些形参的地址始终与

实参的地址对应

然后,再把执行递归的函数中的多出来的一组参数传给移动函数

这样就可以实现,每次移动之后,直接打印实参数组了,而不需要去研究到底那个形参对应那个实

参,那样太痛苦了

最后,重点中的重点       **************

执行递归的函数

五,解汉诺塔    jie()

我们要把所有盘子移动过去先要把最大的盘子移动过去

要把最大的移动过去,先要把次最大的移动过去

问题逐渐缩小

所以使用一个递归

第一个递归会一直转递到只有一个盘子的时候

然后回溯

而我们注意到,每次最大盘子的摆放位置,一次是C一次是B

所以递归如下

//    //    jie(n - 1, a, c, b);
//        //参数意为把上次2位置上的的值传给下次3位置,把3位置的值传给下一次2位置的值
//        //位置上写什么即为接受上次什么位置的值
//        //第一次递归为将最大的盘转移
//        // 每次 b c 交换

//        // 我们知道
//        // 解汉诺塔主要分三部
//        // 
//        // 1,把最大的盘子之前的盘子全部转移到一个柱子,并空出一个可以放最大盘子的柱子
//        // 
//        // 2,把最大盘子转移到那个空柱子
//        // 
//        // 3,因为之前的最大盘子已经转移
//        // 
//        // 此时的情况是一个柱子放最大盘子,一个柱子放其他盘子,一个空柱子
//        // 
//        // 只要我们认为已经被放了最大盘子的C柱子的为空柱子,就可以认为有两个空柱子,和一个放置其余盘子的柱子
//        // 
//        // 则之前的问题把N个盘子A移动到C柱子,变成了把N-1个盘子B移动到C柱子
//        // 
//        // 最后逐渐简化
//        // 
//        // 如图,即为流程,要把N个盘子放到C柱子需要把N-1个放到b柱子
//        // 要N-1....到B需将n-2...放到C
//        // 
//
a         b           cn
a       ()bn-1        c
a         b         ()cn-2
........
a       b3       c   **     
a       b        c2  **
a       b1       c   **
//
//        /*    printf("%d  ---->   %c\n", n, c);*/
//
//        //每次都会打印最大的盘子到正确柱子的步转移骤
//        //但如果程序就此结束,则程序只打印如何把最大盘子转移到C的步骤
//        // 
//        // 即要把N号盘到C,需N-1号次最大盘移动到B(不考录其他每次只转移最大盘)
//        // 要N-1到B,需n-2到C.....
//        // 不考虑如何空出一个柱子
//        // 只考虑最大盘子的行动
//        // 
//        // 如图为最大盘的移动情况带()意味只有一个盘子括号内数字表示盘号,不带括号代表其余多少盘子
//        // 
//        // a            bn-1              c(n)
//        // an-2         b                 c(n-1)
//        // a            bn-3              c(n-2)
//        //...
//        // a          b3           c(4)     此时要求实现   a            b           c4      即除3号盘外2个到A
//        // 
//        // a2         b            c(3)       此时要求实现   a2            b           c(3)      即除2号盘外1个到B
//        // 
//        // a         b1           c(2)     此时要求实现   a            b           c(1)      即除1号盘外0个到A
//        //

可以看出其余盘子移动的次序是A,B互换

即,每次到了这一步,剩下的工作为,将其余盘所在柱子重新视为A柱子

放了最大盘的柱子视为空柱子

此时的问题相当于之前原问题变小了

所以再次调用递归


//            //jie(n - 1,  b, a, c);
//            //a,b 交换(1位置和2位置交换)  3位置是打印位置
//            //位置上写什么即为接受上次什么位置的值
//            //意为把上次3位置上的的值传给下次1位置,把1位置的值传给下一次2位置的值,把2位置的值传给下一次3位置的值
//            //
//            //
//            //第二次递归的意思是,在最大盘到位后,将其除了次最大盘的其余盘移动到空柱 

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/727363.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-26
下一篇 2022-04-26

发表评论

登录后才能评论

评论列表(0条)

保存