一.题目及答案
如图,题目及答案如下:
该程序完整代码如下(需要可自由复制):
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> int main() { int x, y, t; scanf("%d", &x); y = 0; while (x) { t = x%2; y =2*y+t; x/=2; } printf("%d\n", y); return 0; }
二.对该程序的分析及详解
以下是对该程序的分析:
先来看题目:
输入一个十进制正整数,将它对应的二进制数的各位逆序,形成新的十进制数输出。
如:13-- > 1101-- > 1011-- > 11
如:10-- > 1010-- > 0101-- > 5
也即,我们的目标是先将十进制整数转换成二进制,再将二进制位逆序,再将逆序后的二进制数转换成十进制。
下面详解一下该题目的思路:
我们可以采用循环的形式,先将该数字上的二进制数一个一个剥下来,再倒序着一位一位安上去,流程大概如图:
将数字剥下来我们比较好理解,无非是剥几进制就给数字一直%几就行,比如该题剥二进制,那我们就可以先用一个变量t来记录下每一位剥下的数字,即:
t=x%2;
接下来问题是怎样将剥下来的数字安进新数字的中未被占用的首位了,显然我们现在是无法知道新输入的数的二进制最高位的权重的,虽然可以在最开始使用循环计算该数字的最高位,但这样有些太麻烦,因此我们不能一开始就将剥下来的末尾数字放在首位,只能采取先放在末位,再逐级向首位移动的方法,代码实现如下:
y=2*y+t;
这行代码妙在不需要知道最高权重,直接从末位向前递补,除了第一次,剩下的每次随着每补进来一位数,前面的所有位数的权重都会+1,下面给大家画图演示一下:
理解了这步,整个题目的思路也就分析完了。
接下来我们由此再拓展一些该思路的其他应用思路。
发现有很多朋友对"y=y*2+t"这条语句有些感到疑惑,所以我把这期间和一些朋友交流的过程贴在这里,希望可以帮助到更多新来的朋友:
这个是我手画的循环图示:
这个是方法来源:十进制转换N进制的基数乘除法
如果还是很难理解,那不妨先想像一个十进制数"123456"是如何通过%10取下一位,然后通过"y=y*10+t"这个公式一步一步转换到"654321"的:
可能我在这里讲的还不是非常清楚,还有疑问的朋友欢迎私信我一起交流!
三.对该题的举一反三
接下来我们会分别将前面题目的”剥数字“思想延申应用至两种题目中:
1.将十进制数对应的n进制数各位逆序,形成新的十进制输出。
2.将十进制数转换成相应的n进制数输出
1.将十进制数对应的n进制数各位逆序,形成新的十进制输出
如题:
输入一个十进制正整数,将它对应的8进制数的各位逆序,形成新的十进制数输出。
如:13-- > 15-- > 51-- > 41
如:10-- > 12-- > 21-- > 17
通过前面2进制的例子,这道题我们很好就理解了,无非刚才是剥二进制数,现在改成剥八进制数,再给前面所有的数乘以8进制的权重,即*8即可。代码如下:
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> int main() { int x, y, t; scanf("%d", &x); y = 0; while (x) { t = x%8; y =8*y+t; x/=8; } printf("%d\n", y); return 0; }
在vs2022中尝试运行一下:
再看下一题:
这道题同理,可以理解为把十进制的每位剥下来逆序安上再输出即可:
完整代码如下:
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> int main() { int x, y, t; scanf("%d", &x); y = 0; while (x) { t = x%10; y =10*y+t; x/=10; } printf("%d\n", y); return 0; }
在vs2022测试运行结果:
综上所述,要转二进制逆序就%2,/2,乘2的权重;
转八进制逆序就%8,/8,乘8的权重;
转十进制就%10,/10,乘10的权重;
转十六进制逆序就%16,/16,乘16的权重。
2.将十进制数转换成相应的n进制数输出
我们常常碰到题目让我们将10进制数转换成2进制或8进制等n进制,这样的题目我们完全可以照搬上面的思路再稍加修改就可以。
在转换的时候,我们先按目标进制把每一位%下来(比如要转换成二进制就是%2),但在安放的时候统一给每一位乘以10的权重,就可以打印出一个看起来像二进制的十进制数了。
但是要注意,我们刚才转换过来的数是逆序安放上去的,所以如果直接%上10的权重会得到逆序的二进制数,vs2022环境演示如下:
不过没关系,这时候我们只需要在此基础上再逆序一遍得到的数字就可以了,即多加一个while循环:(该演示非最终版本)
完整代码如下:(非最终版本)
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> int main() { int x = 0; int y = 0; int t = 0; scanf("%d", &x); while (x) { t = x % 2; y = y * 2 + t; x /= 2; } while (y) { t = y % 2; x = x * 10 + t; y /= 2; } printf("%d", x); return 0; }
注意!如果就这样单纯的逆序两遍的话该程序就会存在一个bug,那就是如果该十进制数转换成目标进制后恰好是以0结尾的,那么末位的0就会丢失,如:
在此感谢一下我的好兄弟(这是他的博客主页),帮助我解决了这个bug。其实想明白后这里的问题很简单,给大家画个图讲解一下:
现在问题的原因就一目了然了,因为第二次转置时十进制中原本的末位0变成了前导0,因此用y当第二次循环的结束标志时,程序会因为无法继续计算前导0而提前终止循环,导致末尾0丢失。
搞清楚了原因,解决办法也非常简单,我们只需要记下第一个while循环时循环的次数,然后在第二个while循环时保证和第一次循环循环同样的次数即可。
解决方法如下:我们在程序中设立计数变量count,然后第一个whlie循环每循环一次,就使count++,直到循环终止,然后将count作为第二个while循环运行的条件,每循环一次,count--,直到count减为0,循环终止。
完整代码如下:
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> int main() { int x = 0; int y = 0; int t = 0; scanf("%d", &x); int count = 0;//创建计数变量count while (x) { t = x % 2; y = y * 2 + t; x /= 2; count++;//while每循环一次,count+1 } while (count)//count为0时程序终止 { t = y % 2; x = x * 10 + t; y /= 2; count--;//while每循环一次,count-1 } printf("%d", x); return 0; }
综上,当我们掌握了进制转换的思路后,就可以自己写一个小程序来将输入的十进制数按照需要转换成任何n进制数啦,如:
该小程序完整代码如下:
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> int main() { int x = 0; int y = 0; int t = 0; printf("输入要转换的十进制数:>"); scanf("%d", &x); int z = x; int n = 0; int count = 0; printf("输入想要转换的进制:>"); scanf("%d", &n); while (x) { t = x % n; y = y * n + t; x /= n; count++; } while (count) { t = y % n; x = x * 10 + t; y /= n; count--; } printf("将%d转换成%d进制后的数字为:%d\n", z, n, x); return 0; }
水平有限,欢迎各位大佬评论或私信我一起交流,学习,进步,谢谢大家!