【问题描述】
编写一程序采用Huffman编码对一个正文文件进行压缩。具体压缩方法如下:
<!--[if !supportLists]-->1. <!--[endif]-->对正文文件中字符(换行字符'\'除外,不统计)按出现次数(即频率)进行统计
<!--[if !supportLists]-->2. <!--[endif]-->依据字符频率生成相应的Huffman树(未出现的字符不生成)
<!--[if !supportLists]-->3. <!--[endif]-->依据Huffman树生成相应字符的Huffman编码
<!--[if !supportLists]-->4. <!--[endif]-->依据字符Huffman编码压缩文件(即按照Huffman编码依次输出源文件字符)。
说明:
<!--[if !supportLists]-->1. <!--[endif]-->只对文件中出现的字符生成Huffman,注意:一定不要处理\n,即不要为其生成Huffman码。
<!--[if !supportLists]-->2. <!--[endif]-->采用ASCII码值为0的字符作为压缩文件的结束符(即可将其出现次数设为1来参与编码).
<!--[if !supportLists]-->3. <!--[endif]-->在生成Huffman树时,初始在对字符频率权重进行(由小至大)排序时,频率相同的字符ASCII编码值小的在前;新生成的权重节点插入到有序权重序列中时,出现相同权重时,插入到其后(采用稳定排序)。
<!--[if !supportLists]-->4. <!--[endif]-->遍历Huffman树生成字符Huffman码时,左边为0右边为1。
5. 源文件是文本文件,字符采用ASCII编码,每个字符占8位;而采用Huffman编码后,高频字符编码长度较短(小于8位),因此最后输出时需要使用C语言中的位运算将字符Huffman码依次输出到每个字节中。
【输入形式】
对当前目录下文件input.txt进行压缩。
【输出形式】
将压缩后结果输出到文件output.txt中,同时将压缩结果用十六进制形式(printf("%x",...))输出到屏幕上,以便检查和查看结果。
【样例输入1】
若当前目录下input.txt中内容如下:
aaabbc
【样例输出1】
15f0
同时程序将压缩结果输出到文件output.txt中。
【样例说明】
输入文件中字符的频率为:a为3,b为2,c为1,此外,\0字符将作为压缩文件的结束标志,其出现次数设为1。因此,采用Huffman码生成方法,它们的Huffman编码分别为:
a : 0
b : 10
c : 111
\0 : 110
因此,最终文件压缩结果(按位)为:
0001010111110000
将上述结果按字节按十六进制输出到屏幕上则为15f0(即0001010 111110000的十六进制表示)。
说明:采用Huffman码输出字符序列长度为:1+1+1+2+2+3+3=13(位),由于C语言中输出的最小单位为字节(8位),因此,最后补了三个位0,压缩后实际输出为2个字节。由于文本文件是按ASCII来解释的,因此,以文本方式打开压缩文件将显示乱码(最好用二进制文件查看器来看)。
【样例输入2】
若当前目录下input.txt中内容如下:
do not spend all that you have.do not sleep as long as you want.
【样例输出2】
ea3169146ce9eee6cff4b2a93fe1a5d462d21d9a87c0eb2f3eb2a9cfe6cae
同时程序将压缩结果输出到文件output.txt中。
【题解】
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 5 struct cc 6 { 7 char c; 8 int num; 9 }; 10 struct Huff 11 { 12 struct cc ccount; 13 struct Huff *left,*right; 14 struct Huff *next; 15 }; 16 struct Huff *head=NULL; 17 char Huffman[9]; 18 char Code[128][9]; 19 20 void read(FILE *fp,struct cc ccount[]); 21 void insertSortLink(struct Huff *p); 22 void creatList(struct cc ccount[]); 23 void creatHuffman(void); 24 void creatCode(struct Huff *p,char code,int level); 25 void madeZIP(FILE *src,FILE *obj); 26 27 int main() 28 { 29 FILE *fp,*fq; 30 struct cc ccount[128]; 31 int i; 32 for(i=0;i<128;i++) 33 { 34 ccount[i].c=0; 35 ccount[i].num=0; 36 } 37 38 if((fp=fopen("input.txt","r"))==NULL) 39 exit(-1); 40 if((fq=fopen("output.txt","w"))==NULL) 41 exit(-1); 42 43 read(fp,ccount); 44 creatList(ccount); 45 creatHuffman(); 46 creatCode(head,'0',0); 47 madeZIP(fp,fq); 48 49 return 0; 50 } 51 52 void read(FILE *fp,struct cc ccount[]) 53 { 54 char c; 55 while((c=fgetc(fp))!=EOF) 56 if(c!='\n') 57 { 58 ccount[c].c=c; 59 ccount[c].num++; 60 } 61 ccount[0].c='\0'; 62 ccount[0].num=1; 63 return; 64 } 65 void insertSortLink(struct Huff *p) 66 { 67 struct Huff *q=NULL,*r=NULL; 68 if(head==NULL) 69 head=p; 70 else 71 { 72 q=head; 73 if(p->ccount.num<q->ccount.num) 74 { 75 p->next=q; 76 head=p; 77 } 78 else 79 { 80 while(q!=NULL && p->ccount.num>=q->ccount.num) 81 { 82 r=q; 83 q=q->next; 84 } 85 p->next=q; 86 r->next=p; 87 } 88 } 89 return; 90 } 91 void creatList(struct cc ccount[]) 92 { 93 int i; 94 struct Huff *p; 95 96 for(i=0;i<128;i++) 97 if(ccount[i].num!=0) 98 { 99 p=(struct Huff *)malloc(sizeof(struct Huff)); 100 p->ccount=ccount[i]; 101 p->left=p->right=p->next=NULL; 102 insertSortLink(p); 103 } 104 return; 105 } 106 void creatHuffman(void) 107 { 108 struct Huff *p; 109 while(head->next!=NULL) 110 { 111 p=(struct Huff *)malloc(sizeof(struct Huff)); 112 p->ccount.num=head->ccount.num+head->next->ccount.num; 113 p->left=head; 114 p->right=head->next; 115 p->next=NULL; 116 head=head->next->next; 117 insertSortLink(p); 118 } 119 return; 120 } 121 void creatCode(struct Huff *p,char code,int level) 122 { 123 if(level!=0) 124 Huffman[level-1]=code; 125 if(p->left==NULL && p->right==NULL) 126 { 127 Huffman[level]='\0'; 128 strcpy(Code[p->ccount.c],Huffman); 129 } 130 else 131 { 132 creatCode(p->left,'0',level+1); 133 creatCode(p->right,'1',level+1); 134 } 135 return; 136 } 137 void madeZIP(FILE *src,FILE *obj) 138 { 139 unsigned char *pc,hc; 140 int c=0,i=0; 141 fseek(src,0,SEEK_SET); 142 do 143 { 144 c=fgetc(src); 145 if(c==EOF) 146 c=0; 147 for(pc=Code[c];*pc!='\0';pc++) 148 { 149 hc=(hc<<1)|(*pc-'0'); 150 i++; 151 if(i==8) 152 { 153 fputc(hc,obj); 154 printf("%x",hc); 155 i=0; 156 } 157 } 158 if(c==0 && i!=0) 159 { 160 while(i++<8) 161 hc=(hc<<1); 162 fputc(hc,obj); 163 printf("%x",hc); 164 } 165 }while(c); 166 return; 167 }