1. 程式人生 > >例題 4-4 資訊解碼 (Message Decoding) UVa 213

例題 4-4 資訊解碼 (Message Decoding) UVa 213

題意:

給一個編碼頭和一串編碼(編碼可以換行),編碼頭根據以下規則對應編碼{  考慮下面的01串:  0,00,01,10,000,001,010,101,110,0000,0001.....首先是長度為1的串,然後是長度為二的串,以此類推。並且每一段長度的數字從0到(1<<n)-1(第n段)排列,即題目中所說不包括全為1的串。

   編碼文字由多個小節組成,每小節前三位數字表示該小節中每個編碼的長度(例010表示編碼長度為2),然後是各個字元的編碼,每小節以全1結束。例第一小節:00101。

   你的任務是編寫一個解碼程式,將輸入的編碼轉化為對應編碼頭中字元的句子輸出。

實現:

#include<stdio.h>
#include<string.h>

int code[8][1<<7];
int readchar()//讀取字元 拋棄換行符
	{
		while(1){
			int ch = getchar();
			if(ch != '\n' && ch != '\r')
				return ch;
		}
	}

int readint(int c) //把c位 二進位制數轉換為十進位制數
	{
		int v = 0;
		while(c--){
			v = v*2 + readchar()-'0';
		}	
		return v;
	}

int readcodes()//讀取編碼頭 這裡讀取的時候 長度為len的 第 i 位(i就是相應的編碼的二進位制對應的十進位制的值)
	{
		memset(code, 0, sizeof(code));//對於單獨讀取編碼頭第一個字元時候這個 不必要
		code[1][0] = readchar();//讀取下一串編碼頭時候 單獨用readchar()讀取第一個 它可以拋棄換行符
		for(int len = 2; len <= 7; 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;  // code 中儲存的就是 相應字元的ASCII
			}
		}
		
		return 1;
	}

void printcodes()//題解用不到 用於除錯
	{
		for(int len = 1; len <= 7; len++ ){
			for(int 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()
	{
		//freopen("C:\\Users\\zhangwei\\Desktop\\input.txt","r",stdin); 
		while(readcodes()){
		//	printcodes();
			while(1){
				int len = readint(3);//讀取編碼的長度
				if(len == 0) break;
				while(1){
					int v = readint(len);
					if(v == (1<<len)-1)//判斷 是否是該長度下的結束位置(全為1)
						break;
					putchar(code[len][v]);//輸出相應ASCII 對應的字元	
				}
			}
			putchar('\n');
		}
		
		return 0;	
	}	
		

注意: (1)putchar() 可以把 ASCII 轉換為對應的 字元輸出

(2)還有的 是code[len][i] 中 的i 對應的 就是當前二進位制位長度下的 編碼字元對應的 十進位制的值

例如 code[3][2] 對應的就是二進位制位為三位時候 對應的 010(十進位制為2)

(3)readchar()中 可以拋棄 換行符 並且在沒讀取一個字元的時候 快取區裡的這個字元就出去了(不再存在於緩衝區) 這也就使得能夠依次讀取輸入的所有字元