问题 C: 进制转换之C++题解


文章目录


题目链接:http://codeup.hustoj.com/problem.php?cid=100000579&pid=2

题目描述

将一个长度最多为30位数字的十进制非负整数转换为二进制数输出。

分析

30位数字的十进制非负整数用C++已有的基本数据类型无法表示

提示:long long 的量级是 1 0 19 ; 10^{19}; 1019unsigned long long 是 1 0 20 10^{20} 1020,远远不够 1 0 30 10^{30} 1030

于是很自然的想到用高精度除法来做这道题。这里发一张《算法笔记》中高精度除法的知识点讲解图片
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
高精度数如何定义?上述图片并没有给出,实际上在该书的前几页中已经讲过,这里就不在赘述。

学完高精度除法后,这道题就很好写了,用"高精度除法"+"除基取余"的思路来写。代码如下

提示这里只给出了高精度除法的知识点,如果对高精度不熟悉,可以使用《算法笔记》这本资料学习完整的知识点。这种模板类的知识点一定要多写几遍,孰能生巧,初学一边肯定是记不牢固的。

#include<cstdio>
#include <cstring>

// 定义大整数结构体
struct bign {
	int d[40];
	int len;
	bign() {
		memset(d, 0, sizeof(d)); // memset在头文件string.h(cstring)中
		len = 0;
	} // 构造函数,初始化成员变量
};

// 将字符串转换为大整数
bign strToBign(char str[]) { // 字符串转换为bign
	bign a;
	a.len = strlen(str); // bign的长度就是字符串的长度
	/*倒序存储,原因是,在进行运算的时候都是从整数的低位到高位进行枚举,顺序存储和这种思维
	 相合,但把整数按字符串%s读入时,实际上是逆位存储的。
	 即当整数为211时,str[0] = '2',str[1] = '1', str[2] = '1';
	 因此再读入之后需要在另存为至d[]数组的时候反转一下
	*/
	for (int i = 0; i < a.len; i++) {
		a.d[i] = str[a.len - 1 - i] - '0';
	}  // 倒序存储

	return a;
} 

// 高精度除法;被除数a,除数b,余数r
bign divide(bign a, int b, int& r) {
	bign c;
	c.len = a.len; // 被除数的每一位和商的每一位是一一对应的,因此先令长度相等。
	for (int i = a.len - 1; i >= 0; i--) { // 从高位开始
		r = r * 10 + a.d[i]; // 和上一位遗留的余数组合
		if (r < b) c.d[i] = 0; // 不够除,该位为0
		else { // 够除
			c.d[i] = r / b; // 商
			r = r % b; // 获得本轮的余数
		}
	}
	while (c.len - 1 >= 1 && c.d[c.len - 1] == 0) c.len--; // 去除高位的0(大小不变),同时至少保留一位最低位
	return c;
}

int main(){
	char str1[40]; // 存放高精度数的字符数组
	while(scanf("%s", str1) != EOF) { // 多点测试写法
		bign a = strToBign(str1); // 转换为高精度数
		char ans[150]; // 存放最终结果
		int cnt = 0;
		do {
			int r = 0; // 获得每次的余数
			a = divide(a, 2, r); // 做除法
			ans[cnt++] = r + '0'; // 形成二进制
		} while (!(a.len == 1 && a.d[0] == 0)); // 只要数不为0,就一直除基取余

		// 打印结果
		for (int i = cnt - 1; i >= 0; i--) {
			printf("%c", ans[i]);
		}
		printf("\n");
	}

    return 0;
}

参考资料:《算法笔记》

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值