紫书第四章例4-4信息解码Message Decoding (处理二进制字符的一种典型例题)

浏览: 221 发布日期: 2017-12-27 分类: c
题目:Message Decoding
Some message encoding schemes require that an encoded message be sent in two parts. The first part, called the header, contains the characters of the message. The second part contains a pattern that represents the message. You must write a program that can decode messages under such a scheme.
The heart of the encoding scheme for your program is a sequence of “key” strings of 0’s and 1’s as follows:
0,00,01,10,000,001,010,011,100,101,110,0000,0001,...,1011,1110,00000,...
The first key in the sequence is of length 1, the next 3 are of length 2, the next 7 of length 3, the next 15 of length 4, etc. If two adjacent keys have the same length, the second can be obtained from the first by adding 1 (base 2). Notice that there are no keys in the sequence that consist only of 1’s.
The keys are mapped to the characters in the header in order. That is, the first key (0) is mapped to the first character in the header, the second key (00) to the second character in the header, the kth key is mapped to the kth character in the header. For example, suppose the header is:
AB#TANCnrtXc
Then 0 is mapped to A, 00 to B, 01 to #, 10 to T, 000 to A, ..., 110 to X, and 0000 to c.
 The encoded message contains only 0’s and 1’s and possibly carriage returns, which are to be ignored. The message is divided into segments. The first 3 digits of a segment give the binary representation of the length of the keys in the segment. For example, if the first 3 digits are 010, then the remainder of the segment consists of keys of length 2 (00, 01, or 10). The end of the segment is a string of 1’s which is the same length as the length of the keys in the segment. So a segment of keys of length 2 is terminated by 11. The entire encoded message is terminated by 000 (which would signify a segment in which the keys have length 0). The message is decoded by translating the keys in the segments one-at-a-time into the header characters to which they have been mapped.(看原题https://cn.vjudge.net/contest/197063#problem/D);

大体意思:就是输入一串字符串,然后第一个为0,第二个为00,之后就是01,10,001,010, (0,00,01,10,000,001,010,011,100,101,110,0000,0001,...,1011,1110,00000,...)这个样子,然后之后会在输入一串由0和1数字,前3个表示其后面每次读入多少0或1的字符的个数,即前3个表示的个数从二进制变成10进制之后的个数,如果这个位数的所以全为1,则表示这次读入的结束,如果3个全为0,则表示为这次读入字符串的结束;之后输出对应的即对应表示的原来的字符串中的字符;

思路:先统计其三位二进制可以表示的有几种情况,最多有7种,即8-1种;再考虑每一种三位二进制情况和后面其存储的字符的个数的联系,比如010,可以存00,01,10三种;所以这里就要这里再通过总结就可以得到010存3个(2*2-1)。所以这里就会涉及到2进制中的位运算<<;(通过位运算来进行有关二进制的运算问题);之后再考虑的如何将读入的字符存到对应的位置,因为这里为从第一个字符往后依次顺序被二进制表示,所以这时候就可以用二维数组进行存储对应字符,且把行表示为其是0或者00这样位数,列数表示后面对应个数,即00为第一个元素,01为第二个元素,这样就可以将存入的字符与二进制存储建立联系,在循环中实现时用位运算符进行表示;之后读入输入的01字符,则先输入3个字符判断位数即判断行数,再后面依次读入对应个数,然后表示其列数,找到对应的行列之后就可以找到对应表示的字符了;(在输入字符串的时候因为回车不影响,所以需要在输入回车符的时候不能返回而要循环输入,还要有在读入编码头字符串的时候要判断是否读到文件尾了,即EOF);

新技巧:通过位运算符进行二进制与十进制之间的转换,还知道对于二进制字符串将其变为经常用的十进制的时候也是通过二进制依次进行;(后面代码会有);

代码:

include<stdio.h>

include<string.h>

int readcode ();
char readchar ();
int readint(int n);

char a11;
int main()
{

   int len,s;
   while(readcode())
   {
        while(1)
       {
           len=readint(3);
           if(len==0)
               break;
           while(1)//因为其同一行中读入的个数再没有读到全为1的时候是可以无限次读入的
           {        //所以不能在循环中限定次数;
               s=readint(len);
               if(s==(1<<len)-1)
                   break;
               putchar(a[len][s]);
           }
       }
       printf("\n");
   }
   return 0;

}

char readchar()
{

   char c;
   while(1)
   {
       c=getchar();
       if(c!='\n'&&c!='\r')
           return c;
   }

}

int readcode()
{

   memset(a,0,sizeof(a));
   char c;int i,j;
   a[1][0]=readchar();
   if(a[1][0]==EOF)
       return 0;
   for(i=2;i<8;i++)
   {
       for(j=0;j<(1<<i)-1;j++)
       {
           c=getchar();
           if(c==EOF)
               return 0;
           if(c=='\n'||c=='\r')
               return 1;
           a[i][j]=c;
       }
   }
   return 1;

}

int readint(int n)

{
   int t=0;
   while(n)
   {
       t=(t<<1)+readchar()-'0';
       n--;
   }
   return t;
}


返回顶部