汉诺塔问题的图像化剖析 (吉林大学 孙立鑫)

目录

汉诺塔问题
1.汉诺塔问题的递归算法
2.图像模拟汉诺塔(easyx图像库)

注:编译器为 visual stdio 2022 较为严格 如

char a;

scanf_s("%c",&a,1);

scanf的写法发生变化 取地址后要表明数字,字符串的话写字符数组长度,单个字符写1.


1.汉诺塔问题的递归算法

#include<stdio.h>
void moveone(char, char);
void move(int, char, char, char);
int sum = 0;
int main(void)
{
	char x, y, z;
	scanf_s("%c %c %c", &x,1, &y,1, &z,1);
	char ch;
	ch = getchar();//过滤前导字符
	int n;
	scanf_s("%d", &n);
	move(n, x, y, z);//开始移动
	return 0;

}
void moveone(char v, char u)
{
	sum++;
	printf("%c->%c    %d\n", v, u,sum);
}
void move(int n, char x, char y, char z)
{
	if (n > 0)
	{
		move(n - 1, x, z, y);
		moveone(x, y);
		move(n-1,z, y, x);
    }
}

最终会出现如下移动结果(以4次为例)输入 a b c 4 回车

a->c    1
a->b    2
c->b    3
a->c    4
b->a    5
b->c    6
a->c    7
a->b    8
c->b    9
c->a    10
b->a    11
c->b    12
a->c    13
a->b    14
c->b    15

  这是简单的递归思想,按照以上步骤移动一定是正确的并且是移动次数最少的,那么这便为我们下面的图像化创造了条件。

  2.图像模拟汉诺塔(easyx图像库)

  说到图像化,c++图像库Easyx可以简单实现图形的显示功能,我们用这个图形库来编辑代码。

  我们采用源文件头文件相结合的方式。

  源文件如下:

#include<stdio.h>
#include<graphics.h> //图形库头文件
#include<stdlib.h>  
#include"slx.h"  //我们自己的头文件
char x, y, z;   //三个柱子的名称
int top1 = -1;  //栈1
bk stack1[100];
int n1;
int top2 = -1;  //栈2
bk stack2[100];
int n2;
int top3 = -1;  //栈3
bk stack3[100];
int n3;
bk blocks[100];  //汉诺塔块
int sum = 0;  //计数器
int main(void)
{
	scanf_s("%c %c %c", &x, 1, &y, 1, &z, 1);
	char ch;
	ch = getchar(); //过滤前导字符
	int n;
	scanf_s("%d", &n);
	n1 = n;  //n1 n2 n3为栈的容量
	n2 = n;
	n3 = n;
	int i = 0;  //为块赋值序号和半长
	for (; i < n; i++)
	{
		blocks[i].xu = i + 1;
		blocks[i].chang = 10*(i+1);
	}
	i = n-1;
	for (; i >=0; i--)  //从大到小压到栈1中
	{
		push1(blocks[i]);
	}
	initgraph(1000,1000);  //窗口
	xian();  //显示图像
	system("pause");
	move(n, x, y, z);  //移动
	system("pause");  //必要的指令 让窗口停留
	closegraph();
	return 0;
}

     头文件如下:

#ifndef _SLX_H_
#define _SLX_H_
#include<stdio.h>
#include<graphics.h>
#include<stdlib.h>
typedef struct block
{
	int xu;
	int chang;
}bk;  //在头文件中声明结构体
extern int top1;  //以下为引用外部变量
extern bk stack1[100];
extern int n1;
extern int top2;
extern bk stack2[100];
extern int n2;
extern int top3;
extern bk stack3[100];
extern int n3;
extern int sum;
extern char x;
extern char y;
extern char z;
extern int n;  //以下为进栈出栈函数
void push1(bk i)//进栈
{
	if (top1 >= n1 - 1)//满栈
	{
		;
	}
	else
	{
		top1++;//不满栈 栈顶指针加一再进栈
		stack1[top1] = i;
	}
}
bk pop1(void)
{
	if (top1 < 0)//空栈
	{
		;
	}
	else
	{
		bk i = stack1[top1];//栈不空 取值
		top1--;//栈顶指针减一
		return i;//弹出
	}
}
void push2(bk i)//进栈
{
	if (top2 >= n2 - 1)//满栈
	{
		;
	}
	else
	{
		top2++;//不满栈 栈顶指针加一再进栈
		stack2[top2] = i;
	}
}
bk pop2(void)
{
	if (top2 < 0)//空栈
	{
		;
	}
	else
	{
		bk i = stack2[top2];//栈不空 取值
		top2--;//栈顶指针减一
		return i;//弹出
	}
}
void push3(bk i)//进栈
{
	if (top3 >= n3 - 1)//满栈
	{
		;
	}
	else
	{
		top3++;//不满栈 栈顶指针加一再进栈
		stack3[top3] = i;
	}
}
bk pop3(void)
{
	if (top3 < 0)//空栈
	{
		;
	}
	else
	{
		bk i = stack3[top3];//栈不空 取值
		top3--;//栈顶指针减一
		return i;//弹出
	}
}
/*图像显示函数*/
void xian(void)
{
	setbkcolor(RGB(0, 199, 140));
	cleardevice();
	setlinecolor(RGB(138, 43, 226));
	line(100, 900, 900, 900);
	line(300, 100, 300, 900);
	line(500, 100, 500, 900);
	line(700, 100, 700, 900);
	int i;
	i = 0;
	for (int o=10; i <=top1;i++,o+=20)
	{
		rectangle(300 - stack1[i].chang, 900 - (o + 10), 300 + stack1[i].chang, 900 - (o - 10));
	}
	i = 0;
	for (int p = 10; i <=top2; i++, p += 20)
	{
		rectangle(500 - stack2[i].chang, 900 - (p + 10), 500 + stack2[i].chang, 900 - (p - 10));
	}
	i = 0;
	for (int q = 10; i <=top3; i++, q += 20)
	{
		rectangle(700 - stack3[i].chang, 900 - (q + 10), 700 + stack3[i].chang, 900 - (q - 10));
	}
}
/*移动函数*/
void moveone(char v, char u)
{
	sum++;
	printf("%c->%c    %-10d", v, u, sum);
	if (v == x && u == y)
	{
		push2(pop1());
	}
	if (v == x && u == z)
	{
		push3(pop1());
	}
	if (v == y && u == z)
	{
		push3(pop2());
	}
	if (v == y && u == x)
	{
		push1(pop2());
	}
	if (v == z && u == x)
	{
		push1(pop3());
	}
	if (v == z && u == y)
	{
		push2(pop3());
	}
	xian();
	system("pause");
}
/*递归移动函数*/
void move(int n, char x, char y, char z)
{
	if (n > 0)
	{
		move(n - 1, x, z, y);
		moveone(x, y);
		move(n - 1, z, y, x);
	}
}
#endif

  我们以8个为例 输入 a b c 8 回车

  显示如下

 继续按回车到结束

完结撒花

 

  以上就是汉诺塔问题的图像化。

  总结,汉诺塔的背后是较难理解的递归思想,我们可以借此来锻炼递归的思维,就是拆分问题,逐层解决,最终完成目标。

  希望以上内容对你有所帮助,也祝你的生活轻松愉快。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孙立鑫 吉林大学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值