题目
考虑下面01串序列:
0,00,01,10,000,001,010,011,100,101,110,0000,0001,…,1101,1110,00000,…
首先是长度为1的串,然后是长度为2的串,依次类推。可以将此串看作二进制串。注意:上述序列不存在全为1的串。
编写一个解码程序。
首先输入一个编码头(eg:AB#TANCnrtXc),则上述序列的每个串依次对应编码头的每个字符。(eg:0对应A,00对应B,#对应01,T对应10,依次类推)
编码文本由多个小节组成,每个小节的前3个二进制数代表字符编码的长度(eg:010对应长度为2),然后是各字符编码,以全1结束(eg:编码长度为2,就以11结束)。编码文本以000的小节结束。
我先讲解一下位运算
"<<"左移运算,“>>”右移运算
eg:1<<8 即1✖2的8次幂
eg1>>8 即1➗2的8次幂
一个n位的二进制数,最大数为n个1
eg:8位的二进制数最大数为11111111(8个1)
将上述n位最大的二进制数,转换位十进制用位运算来计算
即(1<<n)-1
eg:111转换位十进制(1<<3)-1{2的3次幂减去1为7}
这道题的整体思路:
先用readcodes()读取编译头,并且存放到code[len][value]数组中,再读取编译文本,将编译文本用readint()方法转换为十进制数,在对应到code[len][value]中的值,并将其输出!其中的代码细节我都写在了注释里,以便大家详细阅读!
#include <iostream>
using namespace std;
int code[8][1<<8];//开一个code用于存放编译头
//code[len][value],len位二进制有多少位,eg:001即三位最大为8位,1<<8为左移的位运算(位运算写在代码块下边的讲解部分)
//readchar()防止输入数据中有换行符
int readchar()
{
for(;;)
{
int ch=getchar();
if(ch!='\n'&&ch!='\r')return ch;//只要不为换行符,就返回ch的ASCII码值
}
}
//将c位的二进制数转换为十进制
int readint(int c)
{
int v=0;
while(c--)
{
v=v*2+readchar()-'0';//eg:110=(1*2+1)*2+0
}
return v;
}
//读取编译头,将编译头中的字符,存放到code[len][value]中
int readcodes()
{
memset(code,0,sizeof(code));//清空数组
code[1][0]=readchar();//因为第一个二进制只有一位0,所以单独拿出来读取
for(int len=2;len<=7;len++)
{
for(int i=0;i<(1<<len)-1;i++)//i小于len位二进制转十进制后的"最大数"
{
int ch=getchar();
if(ch==EOF)return 0;//EOF表示读取结束
if(ch=='\n'||ch=='r')return 1;//遇到换行,接着读取
code[len][i]=ch;//将ch归位
}
}
return 1;
}
int main()
{
while(readcodes())//读取预编译头
{
//printcodes()//可以把注释去掉方便调试
for(;;)
{
int len=readint(3);//读取编译文本的前三位,即小节中的编码长度
if(len==0)break;//当这段二进制小节有0位,直接break
for(;;)
{
int v=readint(len);//往后读取len位二进制数,v存放所对应的十进制数
if(v==(1<<len)-1)break;//当读到有len个1时,证明读取到这小节的末尾,直接break跳出循环
putchar(code[len][v]);//不然输出有len位,十进制为v的char型字符
}
}
putchar('\n');
}
return 0;
}
谢谢大家观看,多多点赞支持!