经典打印汉诺塔移动路径、十进制转二进制打印输出——C语言编程基础(递归理解)

1)汉诺塔轨迹输出
有三根杆子A,B,C。A杆上有 N 个 (N>1) 穿孔圆盘,盘的尺寸由下到上依次变小。
要求按下列规则将所有圆盘移至 C 杆:
每次只能移动一个圆盘;
大盘不能叠在小盘上面。
利用递归的方式,打印出移动轨迹
解决:hio函数对应输出移动的步数,move用于打印出每一次的轨迹

  • 本题拓展:当输入一个固定的数值,输出该数值对应的步骤移动路径,该如何输出?
  • 解决:增加一个全局变量,用来在递归的时候计算步数,输入的数值m作为参数传入函数,那么对应的输出也要修改,主要是修改move函数。拓展题代码放在下面:
  • 需要注意的就是,对于m做一个基本的判断 是否是步数范围只能 否则程序报错。
  • 而其中具体步数的增加是在两个部分,一个是退出循环时,另一个就是if之外。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
# include<stdbool.h>
#include<stdlib.h>
# include<math.h>

int step;
void move(int n,int m, char start, char mid, char end) {
	/*step表示输出具体的哪一步 m是用于判断当前步数是否是m+1 */
	if (n == 1) {
	//	printf("%c->%c\n", start, end);   
		step++;
		if (step == m) {
			printf("第%d的移动轨迹是:%c->%c\n",m, start, end);
		}
		return;//出口
	}
	//正常分成三步,第一步(n-1)1-->3
	move(n - 1,m, start, end, mid);
	step++;
	if (step == m) {
		printf("第%d的移动轨迹是:%c->%c\n", m, start, end);

	}
	//第三步 中间移到 目标

	move(n - 1,m, mid, start, end);
}
int hio(int n, int m) {
	if (m > (1LL << n) - 1) {
		printf("程序错误!!!步数超出范围!!");
		exit(1);
	}
	printf("%d个盘子的汉诺塔问题,", n);
	move(n, m, 'A', 'B', 'C');

	return (1LL << n) - 1;   //步数不需要每一步都实现,直接通过公式计算出当下的步数即可

}
int main() {
	int num, num1,m;
	scanf("%d%d", &num,&m);
	printf("%d",hio(num,m));//返回步数
	return 0;
}

2) 十进制转换成二进制
给定任意一个非负十进制整数,请利用递归的方式,求解它的二进制表示方式
基本的思路是:把该整数除以2得到余数,然后倒着输出余数。
思考一下:如何实现倒着打印余数呢?
解决:translate_对应解决十进制转换成二进制。倒着打印对应的是回溯后的代码运行逻辑,程序注释中有详细解释。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
# include<stdbool.h>
# include<math.h>

void move(int n, char start, char mid, char end) {
	//打印每一步的过程,也就是在移动的时候都需要输出
	//当剩最后一个就是移动完成
	if (n == 1) {
	//不需要再n--到这一步了 直接输出然后向上回溯即可 
		printf("%c->%c\n", start, end);   
		return;//出口
	}
	//正常分成三步,第一步(n-1)个从第1-->第3
	move(n - 1, start, end, mid);
	//第二步 没有移动成功的大盘移到第三
	//move(n - 1, start, mid, end);  为什么这一步不用迭代呢 因为 我迭代的目的就是输出移动方向,
	//中间这一步是可以直接输出的 不用再迭代下去,所以直接输出就行
	//我的理解是上面 n-1个移动作为第一步 但是具体的一步 对应的是一个move
	//有出口 并且完成步骤分层理解清楚,需要的数据拿到就可以
	printf("%c->%c\n", start, end);

	//第三步 中间移到 目标

	move(n - 1, mid, start, end);
}

void translate_(int num) {
	if (num == 1) {
		printf("%d", num % 2);
		return ;
	}
	translate_(num >> 1);
	printf("%d", num % 2);   //递归想要每一次递归的结果 反向输出 就需要把输出放在递归函数后面即可
	//至于为什么,解释一下
	/*首先函数的会先执行 46行之前的函数 也就是先判断是否要退出,再更新num值,拿着 新的num值不断向下,直到
	* num满足退出的条件 也就是在最后一次进入到函数中 判断num是等于1,输出此时的1 再通过return
	* 开始向上回溯 ,而 回溯之后执行的是上一层的num 也就是 1退回到 2 num=2的这一层 循环  输出
	* 2%2的结果 从而实现回溯的输出
	* 那么相同的 如果是在translate_前面输出就是在向下走的过程中 先输出%2的值,在向下递归,也就是正向输出模数。
	
	*/

}
int hio(int n) {
	
	move(n, 'A','B', 'C');

	return (1LL << n) - 1;   //步数不需要每一步都实现,直接通过公式计算出当下的步数即可

}
int main() {
	int num, num1;
	scanf("%d", &num);
	printf("%d",hio(num));//返回步数
	scanf("%d", &num1);
	translate_(num1);



	return 0;
}

回溯:在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值