问题描述:
考虑下面的01串序列:
0,00,01,10,000,001,010,011,100,101,110,0000,0001,....,1101,1110,00000....
首先是长度为1的 串,然后是长度为2的串,以此类推。如果看成二进制,相同长度的后一个串等于前一个串加1.上述序列不存在全为1的串。
我们的任务是编写一个解码程序。
首先输入一个编码头
AB#TAN
则根据上述的规则生成对应的编码
A:0 B:00 #: 01 T: 10 A: 000 N: 001
这里标红的地方需要注意,此时的编码 0 对应A 001 也对应A
在编码结束后,输入要解码的 编码文本
0100100101101100000111100101
解码过程:
010表示编码长度为2 01 00 10 11代表小节结束 011表示编码长度为3 000 001 111代表小节结束 001 表示编码长度为1 0 1结束
# B T A N A
先上代码跟结果,再分析
代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int readchar(){
for(;;){
int ch = getchar();
if(ch != '\n' && ch != '\r') return ch;
}
}
int readint(int c){
int v = 0;
while(c--) v = v*2 + readchar() - '0';
return v;
}
int code[8][1<<8];
int readcodes(){
memset(code, 0, sizeof(code));
code[1][0] = readchar();
int len, i;
for(len = 2; len <= 7; len++){
for(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;
}
void printcodes(){
int len, i;
for(len = 1; len <= 7; len++)
for(i = 0; i < (1<<len)-1; i++){
if(code[len][i] == 0)return;
printf("code[%d][%d] = %c\n", len, i, code[len][i]);
}
}
int main()
{
while(readcodes()){
printcodes();//调试使用,可以注释掉
for(;;){
int len = readint(3);
if(len == 0) break;
for(;;){
int v = readint(len);
if(v == (1 << len)-1)break;
putchar(code[len][v]);
}
}
putchar('\n');
}
return 0;
}
结果:
分析:
我们把编码看成二进制数,这样我们用(len,value)这个二元组来表示一个编码,其中len是编码长度,value是编码对应的十进制值。用codes[len][value]保存这个编码所对应的字符。由于每次读取编码头时把codes数组清空了,所以只要遇到字符为0的情况,就表示编码头已经结束。