变长编码【GESP四级-2023.9】

题目描述

小明刚刚学习了三种整数编码方式:原码、反码、补码,并了解到计算机存储整数通常使用补码。但他总是觉得,生活中很少用到 231−1231−1 这么大的数,生活中常用的 0∼1000∼100 这种数也同样需要用 44 个字节的补码表示,太浪费了些。 热爱学习的小明通过搜索,发现了一种正整数的变长编码方式。这种编码方式的规则如下:

  1. 对于给定的正整数,首先将其表达为二进制形式。例如,(0){10}=(0){2}(0){10}​=(0){2}​,(926){10}=(1110011110){2}(926){10}​=(1110011110){2}​。

  2. 将二进制数从低位到高位切分成每组 77 bit,不足 77bit 的在高位用 00 填补。例如,(0){2}(0){2}​ 变为00000000000000 的一组,(1110011110){2}(1110011110){2}​ 变为 00111100011110 和 00001110000111 的两组。

  3. 由代表低位的组开始,为其加入最高位。如果这组是最后一组,则在最高位填上 00,否则在最高位填上 11。于是,00 的变长编码为 0000000000000000 一个字节, 926926 的变长编码为 1001111010011110 和 0000011100000111 两个字节。

这种编码方式可以用更少的字节表达比较小的数,也可以用很多的字节表达非常大的数。例如,987654321012345678987654321012345678 的二进制为 (0001101 1011010 0110110 1001011 1110100 0100110 1001000 0010110 1001110){2}(0001101 1011010 0110110 1001011 1110100 0100110 1001000 0010110 1001110){2}​,于是它的变长编码为(十六进制表示) CE 96 C8 A6 F4 CB B6 DA 0D,共 99 个字节。

你能通过编写程序,找到一个正整数的变长编码吗?

输入格式

输入第一行,包含一个正整数 𝑁N。约定 0≤𝑁≤10180≤N≤1018。

输出格式

输出一行,输出 𝑁N 对应的变长编码的每个字节,每个字节均以 22 位十六进制表示(其中, A-F 使用大写字母表示),两个字节间以空格分隔。

代码

#include <iostream>
using namespace std;
void output_digit(int d) {
	if (d >= 10)
		cout << (char)('A' + d - 10);
	else
		cout << (char)('0' + d);
}
void output_code(int s) {
	output_digit(s >> 4);
	output_digit(s & 0x0f);
}
int main() {
	long long n = 0;
	cin >> n;
	int split[10];
	int l = 0;
	while (n > 0) {
		split[l] = (int)(n & 0x7f);
		n >>= 7;
		l++;
	}
	for (int i = 0; i < l - 1; i++)
		split[i] |= 0x80;
	output_code(split[0]);
	for (int i = 1; i < l; i++) {
		cout << " ";
		output_code(split[i]);
	}
	cout << endl;
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值