这是书上一条例题,那个觉得有意思就也写一下心得
题目
讲解与心得
首先从输入入手
输入每次输入有三部分,分别是:编码头code(一串字符串且含空格),编码文件小节长度len(只含有1、0),以及编码文件内容(只含有1、0)。所以一共需要三个循环,每个循环对应一部分。
第一部分
读入code[ len ][value],用一个函数readcode装起来,放在 while 循环的条件里面。当读到EOF的时候返回0结束循环。函数内部第一个细节是第一个字符用 readchar (自定义函数)读入,防止读到回车键。剩下的用两层循环getchar读入即可。
第二部分
用 readint (自定义函数)读入三位二进制,len。如果len为 0 则跳出循环。然后到下一层。reading 的读入可以类比十进制,我们总是把用来的数 * 10 再加上刚读入的低位加上来获得新值;2进制同理,只是换成了乘以 2。
第三部分
用 reading(len) 读入len位的二进制转十进制 v,如果为2^len - 1 则跳出循环,否则直接打印 code[len][v]。因为 len 位全 1 的 2 进制 +1 刚好等于 2 ^(len+1) 。
笔者的失误
一开始写 readcode 最后的返回值写成了0,所以wa了....
显然是因为我没有考虑如果把 code 读满了的情况。
代码
#include <stdio.h>
#include <string.h>
int code[8][1<<8];
int readint(int l); //读入一个l位的二进制并返回十进制
int readchar(); //跳过回车读入
int readcodes(); //读入编码头
int main() {
#ifdef TEST
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
#endif // TEST
while (readcodes()) {
for (;;) {
int len = readint(3);
if (len == 0) break;
for (;;) {
int v = readint(len);
if (v == (1 << len) - 1) break;
putchar(code[len][v]);
}
}
printf("\n");
}
return 0;
}
int readint(int len){
int v = 0;
while (len--) v = v * 2 + readchar() - '0';
return v;
}
int readchar(){
for (;;) {
int ch = getchar();
if (ch != '\n' && ch != '\r') return ch;
}
}
int readcodes(){
for (int i = 0; i < 8; i++)
memset(code[i], 0, sizeof(code[i]));
code[1][0] = readchar();
for (int len = 2; len < 8; len++) for (int i = 0; i < (1 << len) - 1; i++) {
int ch = getchar();
if (ch == EOF) return 0;
if (ch == '\n' || ch == '\r') return 1;
code[len][i] = ch;
}
return 1;
}