微课汉诺塔问题教案.docx
《微课汉诺塔问题教案.docx》由会员分享,可在线阅读,更多相关《微课汉诺塔问题教案.docx(35页珍藏版)》请在冰豆网上搜索。
微课汉诺塔问题教案
本微课适用范围如下所示:
课程所属学科:
计算机
适用专业:
计算机应用技术、计算机软件工程、电子信息
适用课程:
C语言程序设计、C++程序设计、JAVA程序设计、数据结构
适用对象:
有一定编程基础的同学
《汉诺塔问题》微课教案
学院(部):
软件学院系(教研室):
网络教研
授课教师:
杨珺职称:
副教授
课程名称
汉诺塔算法解析及其程序实现
课程类别
微课教学
授课对象
具有一定程序设计基础
考核方式
自我理解与自我实现
教
学
基
本
目
的
和
要
求
“微课”是指以视频为主要载体记录教师在课堂教育教学过程中围绕某个知识点或教学环节而开展的精彩教与学活动全过程。
“微课”的核心组成内容是课堂教学视频(课例片段),同时还包含与该教学主题相关的教学设计、素材课件、教学反思、练习测试及学生反馈、教师点评等辅助性教学资源,它们以一定的组织关系和呈现方式共同“营造”了一个半结构化、主题式的资源单元应用“小环境”因此,“微课”既有别于传统单一资源类型的教学课例、教学课件、教学设计、教学反思等教学资源。
利用“微课”这种形式,师生可流畅地在线观摩课例,查看教案、课件等辅助资源;也可灵活方便地将其下载保存到终端设备(如笔记本电脑、手机、MP4等)上实现移动学习、“泛在学习”,非常适合于教师的观摩、评课、反思和研究。
课程的性质和任务
汉诺塔问题是一个数据结构、程序设计与算法分析课程中的一个经典问题。
是函数设计与调用、递归设计与调用和算法分析的一个经典综合问题。
理解、掌握与实现汉诺塔问题对进一步理解、巩固掌握数据结构、程序设计与算法分析课程中的相关知识点,提高学习的逻辑思维能力。
在理解掌握的基础上可与计算机图形设计、游戏设计相结合起来,增加学习趣味性。
也是一次综合实践的课程片段,既要掌握概念,又要动手编程,还要上机调试运行。
对计算机专业和理工类专业来说是对课堂教学的有益补充。
课程的教学目标
本课程的教学目标是:
通过理论和实践教学,使学生较好地掌握理解与巩固函数设计与调用、递归设计与调用和算法分析知识,掌握基本的程序设计过程和技巧,具备初步的图形设计与游戏设计的能力,并能熟练应用C、C++/Java集成环境进行程序的编写、编译与调试,解决一般编程问题的水平。
教学重点和难点
一、函数的设计与应用
重点:
C或C++中的函数设计
二、堆栈的应用
重点:
数据结构中栈的相关概念与应用。
三、顺序结构程序设计
重点:
递归的应用。
参考资料
教材:
《C程序设计》(第三版)谭浩强著清华大学出版社2005
参考书:
《C语言程序设计案例教程》张基温等清华大学出版社
教
学
安
排
引言
汉诺塔源自古印度神话,曾经是一个趣味数学难题,在无计算机的年代基本无法求解,在计算机帮助下可以很好的解决这个问题,但也受到计算机运算速度的影响。
讲授
一、问题出现的历史背景
(1)汉诺塔问题也是世界末日问题之一。
(2)古印度趣味数学问题之一。
二、汉诺塔问题的特点
重复同一种运算,但是计算机量非常巨大。
三、汉诺塔问题求解方法
(1)三根杆子,64个盘子。
(2)依据“大盘在下,小盘在上”的顺序放在同一根杆上。
(2)利用剩余的两根空杆,将盘子移致另一根杆子上。
但是不能违背“大盘在下,小盘在上”原则。
四、算法的结构(3个C程序引入C程序结构)
(1)设计递归函数
用递归的方法求fac(n)=n!
fac(n)=n*fac(n-1)(n>1)(递归公式)
fac(n)=1(n=1)(递归边界条件)
(2)设计recursionformula(递归公式)
if(n>1)
hanoi(n-1,A,C,B);
printf("%c%c\n",A,C);
hanoi(n-1,B,A,C);
(3)设计Endingcondition(边界条件)
if(n==1)
printf("%c%c\n",A,C);
(4)设计递归函数voidhanoi(intn,charA,charB,charC)
{if(n>1){
hanoi(n-1,A,C,B);
printf("%d:
%c->%c\n",++i,A,C);
hanoi(n-1,B,A,C);}
else
printf("%d:
%c->%c\n",++i,A,C);
}
(5)Complexityanalysisofalgorithm(算法复杂度分析)
时间复杂度为:
O(2n)
思考题、
课后作业
阅读:
相关的汉诺塔的资料
课后设计:
编写一个汉诺塔的游戏程序
主要
参考资料
《数据结构》、《C语言程序设计》、《C++程序设计教材》教材
课后自我
总结分析
通过本课程的学习,可以帮助同学进一步理解递归问题和栈的应用。
并且可以提高同学的动手编程能力
备注
程序实现部分
汉诺塔问题的递归实现:
#include
voidhanoi(intn,charA,charB,charC)
{
if(n==1)
{
printf("Movedisk%dfrom%cto%c\n",n,A,C);
}
else
{
hanoi(n-1,A,C,B);
printf("Movedisk%dfrom%cto%c\n",n,A,C);
hanoi(n-1,B,A,C);
}
}
main()
{
intn;
printf("请输入数字n以解决n阶汉诺塔问题:
\n");
scanf("%d",&n);
hanoi(n,'A','B','C');
}
●汉诺塔算法的非递归实现C++源代码
#include
usingnamespacestd;
//圆盘的个数最多为64
constintMAX=64;
//用来表示每根柱子的信息
structst{
ints[MAX];//柱子上的圆盘存储情况
inttop;//栈顶,用来最上面的圆盘
charname;//柱子的名字,可以是A,B,C中的一个
intTop()//取栈顶元素
{
returns[top];
}
intPop()//出栈
{
returns[top--];
}
voidPush(intx)//入栈
{
s[++top]=x;
}
};
longPow(intx,inty);//计算x^y
voidCreat(stta[],intn);//给结构数组设置初值
voidHannuota(stta[],longmax);//移动汉诺塔的主要函数
intmain(void)
{
intn;
cin>>n;//输入圆盘的个数
stta[3];//三根柱子的信息用结构数组存储
Creat(ta,n);//给结构数组设置初值
longmax=Pow(2,n)-1;//动的次数应等于2^n-1
Hannuota(ta,max);//移动汉诺塔的主要函数
system("pause");
return0;
}
voidCreat(stta[],intn)
{
ta[0].name='A';
ta[0].top=n-1;
//把所有的圆盘按从大到小的顺序放在柱子A上
for(inti=0;i ta[0].s[i]=n-i;
//柱子B,C上开始没有没有圆盘
ta[1].top=ta[2].top=0;
for(inti=0;i ta[1].s[i]=ta[2].s[i]=0;
//若n为偶数,按顺时针方向依次摆放ABC
if(n%2==0)
{
ta[1].name='B';
ta[2].name='C';
}
else//若n为奇数,按顺时针方向依次摆放ACB
{
ta[1].name='C';
ta[2].name='B';
}
}
longPow(intx,inty)
{
longsum=1;
for(inti=0;i sum*=x;
returnsum;
}
voidHannuota(stta[],longmax)
{
intk=0;//累计移动的次数
inti=0;
intch;
while(k {
//按顺时针方向把圆盘1从现在的柱子移动到下一根柱子
ch=ta[i%3].Pop();
ta[(i+1)%3].Push(ch);
cout<<++k<<":
"<<
"Movedisk"< "to"< i++;
//把另外两根柱子上可以移动的圆盘移动到新的柱子上
if(k {//把非空柱子上的圆盘移动到空柱子上,当两根柱子都为空时,移动较小的圆盘
if(ta[(i+1)%3].Top()==0||
ta[(i-1)%3].Top()>0&&
ta[(i+1)%3].Top()>ta[(i-1)%3].Top())
{
ch=ta[(i-1)%3].Pop();
ta[(i+1)%3].Push(ch);
cout<<++k<<":
"<<"Movedisk"
< <<"to"< }
else
{
ch=ta[(i+1)%3].Pop();
ta[(i-1)%3].Push(ch);
cout<<++k<<":
"<<"Movedisk"
< <<"to"< }
}
}
}
汉诺塔问题的非递归实现
#include
#include
#include
//第0位置是柱子上的塔盘数目
intzhua[100]={0},zhub[100]={0},zhuc[100]={0};
charcharis(charx,intn)
//左右字符出现顺序固定,且根据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';
}
}
voidprint(charlch,charrch)
//打印字符
{
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;
}
}
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");
inti;
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");
}
voidHannuo(intn)
{
//分配2^n个空间
bool*isrev;
isrev=(bool*)malloc(sizeof(bool)*(int)pow(2,n));
for(inti=1;i isrev[i]=false;
//循环计算是否逆序
for(intci=2;ci<=n;ci++)
{
for(intzixh=(int)pow(2,ci-1);zixh //初始值重复一次,自增值可加4,减少循环次数。
isrev[zixh]=isrev[(int)pow(2,ci)-zixh];
//该位置为中间位置,且奇次幂逆序,偶数幂不逆序
isrev[(int)pow(2,ci)]=((ci-1)%2==0)?
false:
true;
}
charlch='A',rch;
rch=(n%2==0?
'B':
'C');
printf("%d\t",1);
printf("%c->%c",lch,rch);
print(lch,rch);
for(intk=2;k {
if(k%2==0)
rch=charis(lch,n);
else
lch=charis(rch,n);
printf("%d\t",k);
if(isrev[k])
{
printf("%c->%c",rch,lch);
print(rch,lch);
}
else
{
printf("%c->%c",lch,rch);
print(lch,rch);
}
}
}
intmain()
{
intn;
printf("Inputthenum:
");
scanf("%d",&n);
zhua[0]=n;
for(inti=1;i<=n;i++)
zhua[i]=n-i+1;
Hannuo(n);
return0;
}
汉诺塔
汉诺塔问题的递归Java语言实现
importjava.util.Scanner;
publicclassHanoiTest{
publicstaticvoidhanoi(intlevel,Stringa,Stringb,Stringc){
if(level==1)
move(1,a,c);
else
{
hanoi(level-1,a,c,b);
move(level,a,c);
hanoi(level-1,b,a,c);
}
}
staticvoidmove(intlevel,Stringa,Stringb){
System.out.println(level+"层:
"+a+"---->"+b);
}
publicstaticvoidmain(String[]args){
Scannersc=newScanner();//括号中是输入,提交不上去所以就没写
System.out.println("请输入汉诺塔的层数:
");
intn=sc.nextInt();
System.out.println(n+"层汉诺塔的解法是:
");
hanoi(n,"A","B","C");
}
}
汉诺塔动画C++实现程序
这是经典问题汉诺塔的解题演示动画,代码如下:
///////////////////////////////////////////////////
//程序名称:
汉诺塔移动动画
//编译环境:
VisualC++6.0,
//作 者:
//最后修改:
//
#include
#include
#include
#defineMAX64//圆盘的最大数目
#defineNULL0
//定义栈
structSTKNODE
{
inta[4];
};
structSTK
{
STKNODE*stack[MAX];
inttop;
};
//定义全局变量
STKs[3];//声明三个栈,分别代表一号二号三号钢针上圆盘的状态
intv=5;//调整速度
//函数声明
voidInitstk(STK*s);//初始化栈
voidHannoi(intn,chara,charb,charc);//汉诺塔递归
voidstart();//开始画面
voidMove(intn,chara,charb);//移动过程
intswitchab(chara);//返回钢针号
voidadjust();//调整速度暂停
//主函数
voidmain()
{
intn,ta[4]={115,500,285,520};//第一个圆盘的位置
printf("尽量小于16\n");//因为大于十六时就会显示有误,但程序可以正常运行
printf("请输入汉诺塔的层数(1~64):
");
scanf("%d",&n);
STKNODE**p;
p=(STKNODE**)malloc(n*sizeof(STKNODE**));//声明一个元素为n个的动态STKNODE型指针数组
for(inti2=0;i2{
p[i2]=(STKNODE*)malloc(sizeof(STKNODE));//为每一个指针申请空间
}
Initstk(&s[0]);
Initstk(&s[1]);
Initstk(&s[2]);//将三个栈初始化
start();//呈现开始画面
setfillstyle(YELLOW);//圆盘的颜色
for(inti=0;i{
ta[0]+=5;
ta[1]-=20;
ta[2]-=5;
ta[3]-=20;
bar(ta[0],ta[1],ta[2],ta[3]);//画出n个从大到小一次叠放的黄色圆盘
++s[0].top;//进栈
for(inti1=0;i1<4;i1++)
{
p[i]->a[i1]=ta[i1];
s[0].stack[s[0].top]=p[i];//记录每个矩形的位置,top为圆盘的个数
}
}
Hannoi(n,'a','b','c');//汉诺塔递归函数
system("pause");
printf("\t\t\t\tGameOver!
\n");
}
///////////////////////////////////////////////////
//函数定义
//汉诺塔的递归
voidHannoi(intn,ch