范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

C语言解决汉诺塔问题!详细思路源码分享

  每天一个C语言小项目,提升你的编程能力!
  汉诺塔问题源自印度一个古老的传说
  印度教的"创造之神"梵天创造世界时做了 3 根金刚石柱,其中的一根柱子上按照从小到大的顺序摞着 64 个黄金圆盘。梵天命令一个叫婆罗门的门徒将所有的圆盘移动到另一个柱子上,移动过程中必须遵守以下规则:
  (1)每次只能移动柱子最顶端的一个圆盘;
  (2)每个柱子上,小圆盘永远要位于大圆盘之上。
  在汉诺塔问题中,当圆盘个数不大于 3 时,多数人都可以轻松想到移动方案,随着圆盘数量的增多,汉诺塔问题会越来越难。也就是说,圆盘的个数直接决定了汉诺塔问题的难度,解决这样的问题可以尝试用分治算法,将移动多个圆盘的问题分解成多个移动少量圆盘的小问题,这些小问题很容易解决,从而可以找到整个问题的解决方案。
  编译环境:Visual Studio 2019/2022,EasyX插件
  这是经典问题汉诺塔的解题演示动画,代码如下: #include  #include  #include  #define MAX 64				// 圆盘的最大数目 #define NULL 0   // 定义栈 struct STKNODE { 	int a[4]; };  struct STK  { 	STKNODE*	stack[MAX]; 	int			top; };   // 定义全局变量 STK s[3];					// 声明三个栈,分别代表一号二号三号钢针上圆盘的状态 int v = 5;					// 调整速度     // 函数声明 void Initstk(STK* s);							// 初始化栈 void Hannoi(int n, char a, char b, char c);		// 汉诺塔递归 void start();									// 开始画面 void Move(int n, char a, char b);				// 移动过程 int switchab(char a);							// 返回钢针号 void adjust();									// 调整速度暂停    // 主函数 void main() { 	int n, ta[4] = {115, 500, 285, 518};			// 第一个圆盘的位置 	printf("尽量小于16 ");							// 因为大于十六时就会显示有误,但程序可以正常运行 	printf("请输入汉诺塔的层数(1~64):"); 	scanf("%d", &n); 	STKNODE** p; 	p = (STKNODE**)malloc(n * sizeof(STKNODE **));	// 声明一个元素为 n 个的动态 STKNODE 型指针数组 	for (int i2 = 0; i2 < n; i2 ++) 	{ 		p[i2] = (STKNODE *)malloc(sizeof(STKNODE));	// 为每一个指针申请空间 	}  	Initstk(&s[0]); 	Initstk(&s[1]); 	Initstk(&s[2]);									// 将三个栈初始化 	start();										// 呈现开始画面 	setfillcolor(GREEN);							// 圆盘的颜色 	for (int i=0; i < n; i++) 	{ 		ta[0] += 5; 		ta[1] -= 20; 		ta[2] -= 5; 		ta[3] -= 20; 		solidrectangle(ta[0], ta[1], ta[2], ta[3]);			// 画出n个从大到小一次叠放的黄色圆盘 		++s[0].top;									// 进栈 		for (int i1 = 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("				Game Over! "); }    /////////////////////////////////////////////////// // 函数定义  // 汉诺塔的递归 void Hannoi(int n, char a, char b, char c)   { 	if(n == 1) 		Move(1, a, c); 	else 	{ 		Hannoi(n-1, a, c, b); 		Move(n, a, c); 		Hannoi(n-1, b, a, c);     } }  // 栈的初始化 void Initstk(STK *s)  {   	int i; 	s->top = 0; 	for (i = 0; i <= MAX; i++) 		s->stack[++s->top] = NULL; 	s->top = 0; }  // 移动过程 void Move(int n, char a, char b) { 	int i3, i4 = 0, i5 = 0;					 	i3 = b - a;												// 目的钢针与源钢针的位置差值 	i4 = switchab(a);										// 源钢针钢针号 	i5 = switchab(b);										// 目的钢针号 	STKNODE *q1, *q0;										// 两个中间结点用于源栈和目的栈间的值得传递,q1为目的栈,q0为源栈 	q1 = (STKNODE *)malloc(sizeof(STKNODE)); 	q0 = (STKNODE *)malloc(sizeof(STKNODE));  	// 源栈与目的栈值的传递 	q0 = s[i4].stack[s[i4].top]; 	++s[i5].top;											// 进栈 	q1->a[0] = q0->a[0] + i3 * 200; 	q1->a[1] = 500 - s[i5].top * 20; 	q1->a[2] = q0->a[2] + i3 * 200; 	q1->a[3] = 500 - s[i5].top * 20 + 18; 	s[i5].stack[s[i5].top] = q1; 	--s[i4].top;											// 出栈  	// 向上运动 	while (q0->a[1] >= 100) 	{ 		setfillcolor(GREEN); 		solidrectangle(q0->a[0], q0->a[1], q0->a[2], q0->a[3]); 		adjust();											// 调整函数 		Sleep(10 * v);										// 暂停(ms) 		setfillcolor(WHITE); 		solidrectangle(q0->a[0], q0->a[1], q0->a[2], q0->a[3]); 		setlinecolor(RED); 		line((q0->a[0] + q0->a[2]) / 2, q0->a[1], (q0->a[0] + q0->a[2]) / 2, q0->a[3]);	// 重新画上被擦掉原有的红线 		q0->a[1] -= 10; 		q0->a[3] -= 10; 	}  	// 向左或右运动,与 i3 的正负有关 	while (q0->a[2] != q1->a[2]) 	{ 		setfillcolor(GREEN); 		solidrectangle(q0->a[0], q0->a[1], q0->a[2], q0->a[3]); 		adjust(); 		Sleep(10 * v); 		setfillcolor(WHITE); 		solidrectangle(q0->a[0], q0->a[1], q0->a[2], q0->a[3]); 		if (i3 < 0)											// i3<0向左移 		{ 			q0->a[0] -= 20; 			q0->a[2] -= 20; 		}  		else												// i3>0向右移 		{ 			q0->a[0] += 20; 			q0->a[2] += 20; 		} 	}  	// 向下运动 	while (q0->a[3] <= q1->a[3]) 	{ 		setfillcolor(GREEN); 		solidrectangle(q0->a[0], q0->a[1], q0->a[2], q0->a[3]); 		adjust(); 		Sleep(10 * v); 		setfillcolor(WHITE); 		solidrectangle(q0->a[0], q0->a[1], q0->a[2], q0->a[3]); 		setlinecolor(RED); 		if (q0->a[1] > 100)									// 重画被擦掉的红线 		{ 			line((q0->a[0] + q0->a[2]) / 2, q0->a[1], (q0->a[0] + q0->a[2]) / 2, q0->a[3]); 		} 		q0->a[1] += 10; 		q0->a[3] += 10; 	}  	// 在目的钢针上的相应位置绘制出黄色矩形块 	setfillcolor(GREEN); 	solidrectangle(q1->a[0], q1->a[1], q1->a[2], q1->a[3]); }  // 绘制开始界面 void start() {  	// 初始化画面大小 	initgraph(800, 650);  	// 背景设为白色 	setbkcolor(WHITE);  	// 用白色填充整个画面 	cleardevice(); 	 	// 绘制彩虹,形成一道彩虹,摘自 easyx 帮助文档示例程序 	float H, S, L;  	H = 0;			// 色相 	S = 1;			// 饱和度 	L = 0.5f;		// 亮度 	setlinestyle(PS_SOLID, 2);								// 设置线宽为 2 	for(int r = 600; r > 544; r--) 	{ 		H += 5; 		setlinecolor( HSLtoRGB(H, S, L) ); 		circle(750, 900, r); 	}  	// 说明 	settextstyle(50, 0, "华文楷体"); 	settextcolor(RED); 	outtextxy(200, 150, "汉诺塔移动动画"); 	settextstyle(20, 0, "黑体"); 	outtextxy(600, 200, "BY:Ronald"); 	outtextxy(500, 200, "版本V1.1"); 	settextstyle(50, 0, "黑体"); 	settextcolor(GREEN); 	outtextxy(200, 350, "随便按一个键开始吧!");  	// 检测键盘敲击 	getch();  	// 清空开始界面 	cleardevice();  	// 绘制运动画面的的环境 	setlinecolor(RED);  	// 三根红色线段作为钢针 	line(400, 110, 400, 500); 	line(600, 110, 600, 500); 	line(200, 110, 200, 500);  	// 长方体形的底座 	setfillcolor(LIGHTGRAY); 	fillrectangle(80, 501, 720, 510);  	 	// 暂停按钮 	solidrectangle(360, 540, 440, 580); 	settextstyle(30, 0, "黑体"); 	settextcolor(GREEN); 	outtextxy(370, 550, "暂停");                               	settextstyle(20, 0, "宋体"); 	settextcolor(RED); 	outtextxy(300, 580, "鼠标暂停后请按空格继续");  	// 加速按钮 	solidrectangle(160, 540, 240, 580); 	settextstyle(30, 0, "黑体"); 	settextcolor(GREEN); 	outtextxy(170, 550, "加速"); 	settextstyle(20, 0, "宋体"); 	settextcolor(RED); 	outtextxy(170, 580, "请按 d");  	// 减速按钮 	solidrectangle(560, 540, 640, 580); 	settextstyle(30, 0, "黑体"); 	settextcolor(GREEN); 	outtextxy(570, 550, "减速"); 	settextstyle(20, 0, "宋体"); 	settextcolor(RED); 	outtextxy(570, 580, "请按 a");  	// 说明 	settextstyle(50, 0, "宋体"); 	settextcolor(GREEN); 	outtextxy(10, 10, "正在进行中请欣赏:"); }  // 判断目的钢针与源钢针的钢针号返回钢针号 int switchab(char a) { 	switch (a) 	{ 		case "a": 			return 0; 		case "b": 			return 1; 		case "c": 			return 2; 		default: 			return 0; 	} }  // 调整函数,实现加速,减速,暂停 void adjust() { 	char f;												// 接收键盘敲进去的按钮和鼠标点击时赋予的变化值  	// 用 f 接受键盘的键入值 	if(kbhit()) 		f = getch();  	// 检测鼠标消息 	if (MouseHit()==true)									 	{  		// 接收鼠标消息 		MOUSEMSG Mouse; 		Mouse = GetMouseMsg();  		// 响应鼠标消息 		if (Mouse.x >= 360 && Mouse.x <= 440 && Mouse.y >= 540 && Mouse.y <= 580 && Mouse.mkLButton) 		{ 			f = " "; 		} 		if (Mouse.x >= 160 && Mouse.x <= 240 && Mouse.y >= 540 && Mouse.y <= 580 && Mouse.mkLButton) 		{ 			f = "d"; 		} 		if (Mouse.x >= 560 && Mouse.x <= 640 && Mouse.y >= 540 && Mouse.y <= 580 && Mouse.mkLButton) 		{ 			f = "a"; 		} 	}  	// 作用于动画 	switch(f) 	{ 		 		// 暂停 		case " ": 		 			// 用‘继续’覆盖‘暂停’   			settextstyle(30, 0, "黑体"); 			settextcolor(GREEN); 			outtextxy(370, 550, "继续");   			getch(); 		 			// 继续后变回显示‘暂停’ 			settextstyle(30, 0, "黑体"); 			settextcolor(GREEN); 			outtextxy(370, 550, "暂停");   			break; 		 		// 减速 		case "a": 		 			// 当被点击时,‘减速’位置震动一下 			setfillcolor(LIGHTGRAY); 			solidrectangle(560, 540, 640, 580); 			settextstyle(30, 0, "黑体"); 			settextcolor(GREEN); 			outtextxy(575, 545, "减速");  			Sleep(30); 		 			// 减速 			v++;  		 			// 回原位 			setfillcolor(LIGHTGRAY); 			solidrectangle(560, 540, 640, 580); 			settextstyle(30, 0, "黑体"); 			settextcolor(GREEN); 			outtextxy(570, 550, "减速"); 			break; 		 		// 加速 		case "d": 			setfillcolor(LIGHTGRAY); 			solidrectangle(160, 540, 240, 580); 			settextstyle(30, 0, "黑体"); 			settextcolor(GREEN); 			outtextxy(165, 545, "加速"); 			Sleep(30); 			setfillcolor(LIGHTGRAY); 			solidrectangle(160, 540, 240, 580); 			settextstyle(30, 0, "黑体"); 			settextcolor(GREEN); 			outtextxy(170, 550, "加速");  			// 加速 			v--; 		 			// v 最小为1 			if (v <= 0)               			{ 				v = 1; 			} 			break; 		 		default: 			break; 	}  	 	f = "r";									// f 初始化为 r 	FlushMouseMsgBuffer();						// 清空鼠标消息 }
  大家赶紧去动手试试吧!
  此外,我也给大家分享我收集的其他资源,从最零基础开始的教程到C语言C++项目案例, 帮助大家在学习C语言的道路上披荆斩棘!
  编程学习书籍分享:
  编程学习视频分享:
  整理分享(多年学习的源码、项目实战视频、项目笔记,基础入门教程) 最重要的是你可以在群里面交流提问编程问题哦!
  对于C/C++感兴趣可以关注小编在后台私信我: 【编程交流】 一起来学习哦! 可以领取一些C/C++的项目学习视频资料哦!已经设置好了关键词自动回复,自动领取就好了!

共建共享发展成果来源经济日报山西省运城市河东驿站河东东街站,环卫工人在此歇息。驿站向市民免费提供茶水药品充电宝等服务和设施,24小时开放,让市民共享城市高质量发展带来的幸福和温度。闫鑫摄(中经视觉怀孕你忌口了吗?能管住嘴就管住嘴,这个事情不能大意网友1我有个朋友她老公是医生的,朋友提前半年就各种垃圾食品夜宵下午茶都不吃了,一心养生,怀了二胎以后更是极度的自律就为了保胎,结果还是得流掉,保不住。所以,这是嘴的问题吗?网友2我一个抑郁症的妈妈,自我救赎之路请讲一个让你难忘的职场经历文张涔汐作者寒梅傲雪痛苦的缘起都说人这一生要经历两次出生,一次是肉体的出生,一次是意识的觉醒。看着儿子在我的教育下越来越胆小自卑,我越来越不淡定了,我担心男婴眼里取出8条寄生虫,乃与宠物亲密导致,家长须警惕近日,何女士八个月大的儿子出现揉眼的情况,当地医院用药后也没有改善,趁着孩子睡觉,何女士扒开了孩子的右眼皮,看到有白色虫子在蠕动,吓得赶紧带着孩子来到了浙大儿院眼科门诊。主治医师袁身高没有赢在起跑线?做好身高管理还有希望儿童健康是全民健康的重要基石,为响应健康中国国家战略,儿童青少年健康意识亟待提高。2015年,联合国儿童基金会对儿童健康设立了5个长远目标,包括成年身高认知能力经济创造能力生殖能力微小说一个泼妇的下场一天我四岁的儿子慌慌张张从外边跑回来,也不和我说话,急怱怱跑到二楼的洗澡间,把门关上了。我正纳闷呢,后面来了一位婆娘,她立在门口气愤地对我嚷着你家豆豆(我儿子小名)呢?我疑惑地答道励进幕小遨游绘本海洋,绘制多彩童年英语绘本封面设计大赛英语组校本研修主题报道(9)来源栖霞教育之家学校新闻为培养孩子良好的阅读习惯,发展孩子想象力创造力及表达能力,体验英文阅读的快乐,2022年10月,幕府山庄小学开展遨游绘本海洋,绘制多彩童年英语绘本封面设计大王宝钏挖野菜背后咸湿佬陈浩民曾拉着大肚子老婆当众道歉对于大多数明星来说,不红了是宿命在娱乐圈,能够成为常青树的,少之又少明星的光环很耀眼,在人群之中,总是会成为最显眼的那个所以,即使不红了,但在短视频世界里,明星的身份依旧会让过气艺这几位明星,个个对子女爱意满满,却忘了保持应有的分寸男星张亮曾在节目中分享过自己的育儿观,当谈到有关自己与女儿的亲密互动话题时,张亮随即严肃起来,表示就算再亲密,也绝不能亲女儿的嘴。但并不是每一对明星父母都能像张亮一样,能在亲子关系星爵的腹肌,锤哥的大臂,为演好漫威,这些明星的改变让人惊叹优秀的演员,有让自己的一切为角色服务的决心和耐力,改变体型就是其中之一。为演好摔爸,阿米尔汗曾先增重54斤,之后又减掉54斤,毅力超乎常人。为了演好影,邓超曾增重20斤,之后又在两贾莫兰特将率领灰熊突破历史在周五晚上的第四节末段,杰伦格林以单人快攻的方式冲上球场,直奔后退的防守者。穿过交通,他认为自己的上篮令人印象深刻,直到贾莫兰特突然出现,将球钉在玻璃上。几分钟后,莫兰特在禁区内投
影片中的超前技术手段,反映出几种怪诞元素?在酝酿电影2001太空漫游时,库布里克认为,首先需要确定的是外星生命的问题是否一个合法的科学研究课题?我们是宇宙中唯一的吗?对人类是否有着深远的意义?如果能做到这一点,其他问题也会宇宙中的一些非对称性照照镜子,我们会发现身体左侧与右侧几乎相同,这称为对称性。我们不仅可以在自然界看到它,而且更根本的是,对称性似乎写在宇宙的蓝图中。例如,量子力学中的对称性导致了三种基本的自然力电磁通常定制一套元宇宙仿真人IP需要多少钱随着科技的发展与进步,现在互联网上出现了很多元宇宙公司和虚拟形象。这两年在虚拟现实方面也有了很大的发展,元宇宙是什么?元宇宙是一个全新的概念,它是互联网和现实相结合的产物。与现实中到底是什么?网传甘肃发现巨大发光不明飞行物,分析是卫星吗根据北京时间11月14号消息,网传甘肃省武威市天空突然出现巨大发光不明飞行物,在空中划出蝌蚪形奇观,引发全网关注。很多网友都在猜测这到底是什么呢?会不会是所谓的外星飞船或者其他神秘中国又一重大科技基础设施正式进入联调联试阶段央视网消息昨天(11月13日),国家重大科技基础设施子午工程二期圆环阵太阳射电成像望远镜设备完成系统集成,正式进入联调联试阶段。这一设备可以对太阳爆发活动进行观测。13日上午10时抗衰宜早不宜迟广州紫馨更专业年纪快到30了,脸部皮肤开始变得明显松弛,法令纹太明显了,再也不是当初18岁胶原蛋白满满的小妹妹了。一直都很想去打个BNS改善一下,而且现在轮廓固定确实火我的下颌线还是比较清晰的,马丁靴失宠了?今年秋冬流行烟筒靴,不用系带,时髦百搭今年别再一直穿马丁靴了,烟筒靴也很时髦!冬天已经悄然降临,我们真的要换上厚厚的衣服了。除了衣服裤子要加厚,鞋子也要更换为升级为更能保暖的战靴。这时候各种各样的靴子就开始闪亮登场了,几块钱一瓶的维生素B6,能解决皮肤干燥湿疹和痘痘,真的假的?许多人对于维生素B6并不熟悉,其实作为B族维生素大家庭的一员,维生素B6可以有效防治多种疾病,值得一提的是维生素B6的价格并不贵,一般药店几块钱就可以买一瓶,还是100片装的。别看凯特王妃与碧翠丝公主连环撞衫,泄露两人的购物习惯英国王室成员昨参加缅怀在第一次第二次世界大战与其他战事不幸丧生军民的国殇纪念日活动,凯特王妃身穿英国设计师品牌CatherineWalker军风黑大衣,并别上3朵红色罂粟花胸针出席Pawn重返赛场?LCK知情人放出消息,Deft剑指两连冠2022电竞季时间来到11月14日,悬念重重的2022LPLLCK转会期将至,多位英雄联盟顶尖选手与俱乐部的合同即将到期,成为LOL召唤师关注的焦点,包括RNG野王WeiEDG冠军转会消息皇家马德里巴塞罗那尤文图斯曼联巴黎国际米兰利物浦西班牙媒体Relevo报道,皇马体育部门已经开始了锋线补强对象的选择,目前他们仍未找到合适的人选。自从上赛季开始,银河战舰就在寻找中锋。虽然罗德里戈现在已经成为本泽马的替补,但俱乐