1 /********************************************************
2 ** 功能:求哈夫曼编码 **
3 ** 时间:2015年5月10号 **
4 ********************************************************/
5 #include<stdio.h>
6 #include<stdlib.h>
7 #include<string.h>
8 #define MAXLEN 10000
9 #define MAXVALUE 10000
10
11 //结构体形式的字符包含的信息
12 struct ChNode
13 {
14 int ascii;//存储字符的asci码
15 char ch;//存储字符
16 int count;//字符出现的次数
17 };
18
19 //定义哈夫曼树节点的结构体
20 typedef struct HTNode
21 {
22 int weight;
23 int parent,lchild,rchild;
24 }HTNode;
25
26 typedef char * *HuffmanCode;//定义指针类型的数据类型HuffmanCode
27 typedef struct ChNode ChNode;//定义数据类型ChNode
28
29 void Count_Times(char text[],ChNode freq[]);
30 void Select(HTNode HT[],int i,int &s1,int &s2);
31 void HuffmanCoding(HTNode HT[],HuffmanCode &HC,ChNode freq[],char text[]);
32
33 void main()
34 {
35 ChNode freq[256];//存储字符出现次数的数组
36 char text[MAXLEN];//将字符存储到数组中以后反编译时用
37 HTNode HT[511];
38 HuffmanCode HC;
39
40 Count_Times(text,freq);
41 HuffmanCoding(HT,HC,freq,text);
42 }
43 void Count_Times(char text[],ChNode freq[])
44 {
45 FILE *fp;//文件指针
46 char chtmp;//临时存储从文件中读取的字符
47
48 //跟freq数组赋初值
49 for(int i=0;i<256;i++)
50 {
51 freq[i].ascii=i;
52 freq[i].ch=(char)i;//强制转换为ascii码对应的字符型
53 freq[i].count=0;
54 }
55
56 i=0;
57 fp=fopen("a.txt","r");//以读的方式打开文件
58
59 //统计文件里的字符的出现次数并赋值给text
60 fscanf(fp,"%c",&chtmp);
61 while(!feof(fp))
62 {
63 freq[chtmp].count++;
64 fscanf(fp,"%c",&chtmp);
65 text[i++]=chtmp;
66
67 }
68 fclose(fp);
69
70 //以写方式打开文件并将统计结果输出到文件中
71 fp=fopen("freq.txt","w");
72 for(i=0;i<256;i++)
73 fprintf(fp,"%d %c %d\n",freq[i].ascii,freq[i].ch,freq[i].count);
74 fclose(fp);
75
76 }
77
78 //选出两个权值最小的结点
79 void Select(HTNode HT[],int i,int &s1,int &s2)
80 {
81 int m1,m2;//用来存储最小的两个权值
82
83 m1 = m2 = MAXVALUE;
84 s1 = s2 = -1;//用来存储最小权值的字符的序号
85
86 for(int j = 0;j <= i;j ++)
87 {
88 //若一个字符的权值小于m1且parent为空(没有已经用过)
89 if(HT[j].weight > 0 && HT[j].weight < m1 && HT[j].parent == -1)//s1存储的是字符中权值最小的序号
90 {
91 //权值比s1小,将s1赋值给s2再将字符序号给s1
92 m2 = m1;
93 s2 = s1;
94 m1 = HT[j].weight;
95 s1 = j;
96 }
97 else if(HT[j].weight > 0 && HT[j].weight < m2 && HT[j].parent == -1)//s2存储的是字符中权值第二小的序号
98 {
99 m2 = HT[j].weight;
100 s2 = j;
101
102 }
103 }
104
105
106 }
107
108 void HuffmanCoding(HTNode HT[],HuffmanCode &HC,ChNode freq[],char text[])
109 {
110 //前256个单位有可能出现的字符将权值赋初值
111 for(int i = 0;i < 256;i ++)
112 {
113 HT[i].weight = freq[i].count;
114 HT[i].parent = -1;
115 HT[i].lchild = -1;
116 HT[i].rchild = -1;
117 }
118 //后面255的赋初值
119 for(i = 256;i < 511;i ++)
120 {
121 HT[i].weight = 0;
122 HT[i].parent = -1;
123 HT[i].lchild = -1;
124 HT[i].rchild = -1;
125 }
126
127 int s1,s2;
128
129 //构造哈夫曼树的开始,构造parent节点
130 for(i = 256;i < 511;i++)
131 {
132 Select(HT,i - 1,s1,s2);
133 if(s1 != -1 && s2 != -1)
134 {
135 HT[i].weight = HT[s1].weight + HT[s2].weight;
136 HT[s1].parent = i;
137 HT[s2].parent = i;
138 HT[i].lchild = s1;
139 HT[i].rchild = s2;
140 }
141 else
142 {
143 HT[i - 1].parent = -1;
144 break;
145 }
146 }
147
148 //HuffmanTree.txt文件用来存放各个字符的权值、父母、孩子等信息
149 FILE *fp;
150 fp = fopen("HuffmanTree.txt","w");
151 for(i = 0;i < 511;i ++)
152 fprintf(fp,"(%d) %d %d %d %d\n",i,HT[i].weight,HT[i].parent,HT[i].lchild,HT[i].rchild);
153 fclose(fp);
154
155 //HC相当于一个存放指针类型的数组,每一个元素相对应于一个字符编码数组的首地址
156 HC = (HuffmanCode)malloc(256 * sizeof(char *));
157 char cd[256];
158 cd[255] = '\0';
159 int c,f;
160 int start;
161 for(i =0 ;i < 256;i ++)
162 {
163 if(HT[i].parent != -1)
164 {
165 start = 255;
166 //记录每个字符的编码,是0还是1
167 for(c = i;f = HT[c].parent,f != -1;c = f,f = HT[f].parent)
168 {
169 if(HT[f].lchild == c)
170 cd[--start] = '0';
171 else
172 cd[--start] = '1';
173 }
174 HC[i] = (char *)malloc((256 - start) * sizeof(char));
175 strcpy(HC[i],&cd[start]);
176 }
177 else
178 {
179 HC[i] = NULL;
180 }
181 }
182
183 //HuffmanCode.txt文件中记录字符出现的次数及其哈弗曼编码
184 fp = fopen("HuffmanCode.txt","w");
185 fprintf(fp,"ASCII值\t字符\t出现次数\t编码 \n");
186 for(i = 0;i < 256;i ++)
187 if(HC[i] != NULL)
188 fprintf(fp,"%d\t%c\t%d\t%s\n",i,i,freq[i]);
189 fclose(fp);
190
191 //以对应的哈弗曼编码形式输出到文件中去
192 fp = fopen("translate.txt","w");
193 char ch;
194 i =0;
195 while(text[i] != '\0')
196 {
197 ch = text[i ++];
198 fprintf(fp,"%s",HC[ch]);
199 }
200 fclose(fp);
201
202 }