简单递归【2】

Hanoi塔来啦~~

题干:

补充题干不清楚的地方:n只碟子是自下而上由小到大堆叠的!

为了方便理解我们这里有一个小游戏,大家有兴趣的话可以玩玩

链接:https://pan.baidu.com/s/1IGSI4BGvyAZ3y5hzys2IZQ 
提取码:zhjk

然后我们进入正题

考虑简单的情况:

一个盘子:X->1->Z

两个盘子:X->1->Y、X->2->Z、Y->1->Z

这两个过程很简单

那么三个盘子呢?

有兴趣的可以试着手推一下,不过我们要开始讲基本算法了。

前面已经提到过,递归的想法其实写成代码很简单,但如果硬要动脑筋去搅脑瓜子就很麻烦。

基本算法:

我们直接找出n等于各种值的时候的相似性,递归其实也是因为很多步骤的重复,才可以用到自身调用自身。

可以得出每最后几步都是先将n-1移到备用柱子(Y杆),然后将第n个移到目的柱子,最后把n-1个盘子移到目的柱子n的上面。

其实这样想很简单,实现代码也简单。

but!

深入懂得其中的道理就是另一回事了。比如我就疑惑了很久,”只能将小的盘子叠在大的盘子上面“,这句话如何实现??

ok!

我们来看,为什么要将n-1移动到备用柱子呢?其实就是因为n更大,应该先移动,然后让较小的n-1移动到它上面。这里就实现了将小的叠在大的上面,所以每一次的移动都相当于n取不同值。这里我们就找到了递归的关键要素之一——重复调用部分,也是由前式推出下一步的关系式。

那么,递归出口是什么呢?

其实上面简单案例就已经说了,当n等于1时,直接将盘子移动到目的柱子。

分析到这里,就可以写代码了!

#include<stdio.h>
//把n个盘子从X移到Z 
void hanoi(int n,char X,char Y,char Z);//函数声明
void move(int n,char X,char Z);
int main(){
	int n;
	scanf("%d",&n);
	hanoi(n,'X','Y','Z');
	return 0; 
} 
void hanoi(int n,char X,char Y,char Z){
	if(n==1){//n=1时
		move(n,X,Z);//直接移动到目的柱子
	}
	else{
		hanoi(n-1,X,Z,Y);//将n-1个盘子移动到备用柱子
		move(n,X,Z);//将第n个移动到目的柱子
		hanoi(n-1,Y,X,Z); //将n-1个盘子从备用柱子移动到目的柱子
	}
}
void move(int n,char X,char Z){//这是移动盘子的函数
	printf("%d:%c-->%c",n,X,Z);
	printf("\n"); 
}
//是不是觉得代码的实现蛮简单的,可就是想不到,hhhh

这里呢贴一个n=3时的运行分析

 

 

可以自己画图理解一下那个堆栈过程和栈内存释放的过程! 

其实我的感觉是,只要懂了就挺简单的,所以我的分析好像也不是很详细。

暂时不能理解也没关系,善用搜索,各种资源总有能讲清楚的。

加油!

希望这些文字能对你有用。

后续我可能会更几道递归的题。

现在还没到时间晚安!嘻嘻

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
// helloworld.cpp : Defines the entry point for the console application. // //by 陈墨仙 2019-07-18 //完全不用归解汉诺塔 #include "stdafx.h" #include <windows.h> int h[34];//为了便于理解,0号元素不用,33个盘子 int a[4][34]; int b[4]; int jihao; int dijici; void printH() { //system("cls"); for(int i = 1;i<=34;i++) { printf("%d:%d\t",i,a[3][i]); } } bool jiancha(int * h)//检测是否在下面的都是编号小的 { int d[4]; d[1]=0; d[2]=0; d[3]=0; for(int j = 1;j<4;j++) { for(int i = 1;i<34;i++) { if(a[j][i]==0 || a[j][i]>a[j][i-1]) { } else { printf("error a[%d][%d] = %d a[%d][%d]=%d",j,i-1,a[j][i-1],j,i,a[j][i]); scanf("%d"); return false; } } } return true; } bool shunxu(int zhuzi) { for(int i = 1; i< b[zhuzi];i++) { if(a[zhuzi][i]==34-i) { } else { return false; } } return true; } bool chenggong(int n,int zhuzi)//n号盘是否都移到3 { int d = 0; int t = 34; for(int i = 33;i>33-n;i--) { if(a[zhuzi][34-i]!=i-n+1) { return false; } } return true; } int jc3()//检测3号柱的盘子有几个 { int d = 0; int t = 34; for(int i = 33;i>0;i--) { if(h[i]==3) { d=d+1; t = i; } } return d; } int jc1()//检测1号柱的盘子有几个 { int d = 0; int t = 34; for(int i = 33;i>0;i--) { if(h[i]==1) { d=d+1; t = i; } } return d; } void initH() { for(int i = 0;i<34;i++) { h[i]=1; a[1][i]=i; a[2][i]=0; a[3][i]=0; } b[1]=34; b[2]=1; b[3]=1; } int jc2()//检测2号柱从33往下盘子有几个 { int d = 0; int t = 34; for(int i = 33;i>0;i--) { if(h[i]==2) { d=d+1; t = i; } } return d; } int getTop(int zhuzi) { int d = 0; int t = 0; for(int i = 1;i<34;i++) { if(h[i]==zhuzi && i>t) { t = i; } } return t; } bool jiou(int s) { if(s % 2 == 0) { return true; } else { return false; } } void change(int i,int yuan,int mubiao) { if(h[i] == yuan) { h[i] = mubiao; a[mubiao][b[mubiao]]=i; b[mubiao]=b[mubiao]+1; a[yuan][b[yuan]]=0; b[yuan]=b[yuan]-1; printf("h[%d]:%d->%d",i,yuan,mubiao); } else { printf("Error h[%d] = %d",i,h[i]); scanf("%d"); } jiancha(h); } int FastLog2(int x) { float fx; unsigned long ix, exp; fx = (float)x; ix = *(unsigned long*)&fx; exp = (ix >> 23) & 0xFF; return exp - 127; } int chu2(int n ,int cishu) { for(int j = 1; j<= cishu;j++) { n=n/2; } return n; } void jihaopan(int n) { int i = 1; int yuan = n; while(1) { if(n%2==1) { jihao = i; dijici = chu2(yuan,i)+1; break; } n=n/2; i=i+1; } //printf("几号盘%d,第几次%d",jihao,dijici); } int main(int argc, char* argv[]) { printf("汉诺塔!\n"); int times = 0; initH(); int ji = 1; for(int i = 1;i<5559060534555523;i++) { jihaopan(i); if(jiou(jihao)==false) { int tmp; tmp = dijici%3; if(tmp==1) { change(getTop(1),1,3); } else if(tmp==2) { change(getTop(3),3,2); } else { change(getTop(2),2,1); } } else { int tmp; tmp = dijici%3; if(tmp==1) { change(getTop(1),1,2); } else if(tmp==2) { change(getTop(2),2,3); } else { change(getTop(3),3,1); } } if(chenggong(33,3)) { printf("sssss"); break; } } return 0; }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值