1 //eg:
2 // 4 A B C D 9 5 2 4
3 // A: 0 B: 10 C: 110 D: 111
4 // ABCDCBA 010110111110100
5 #include<stdio.h>
6 #include<stdlib.h>
7 #include<string.h>
8 #include<conio.h>
9 #define OK 1
10 #define ERROR 0
11 typedef struct HTNode{
12 char ch;
13 int weight;
14 int parent, lchild, rchild;
15 } HTNode;
16 typedef struct HTNode* HuffmanTree;
17 typedef char** HuffmanCode;
18 //定义全局变量
19 HuffmanTree HT;
20 HuffmanCode HC;
21 int n;
22 //选择两个最小结点
23 void select(int k, int *s1, int *s2){
24 int i, ti, t=1000;
25 for(i = 1; i <= k; i++){
26 if(!HT[i].parent){
27 if(t > HT[i].weight){
28 t = HT[i].weight;//t最后为最小的weight
29 ti = i;
30 }
31 }
32 }
33 *s1 = ti;
34 t = 1000;
35 ti = 0;
36 for(i = 1; i <= k; i++){
37 if((!HT[i].parent) && i!=*s1){ //parent为0
38 if(t > HT[i].weight){
39 t = HT[i].weight;
40 ti = i;
41 }
42 }
43 }
44 *s2 = ti;
45 }
46 //打印哈夫曼树
47 void printHT(int m){
48 int i;
49 printf("\n");
50 printf("char weight parent lchild rchild\n");
51 for(i = 1; i <= m; i++){
52 printf(" %c %5d %5d %5d %5d\n", HT[i].ch, HT[i].weight, HT[i].parent, HT[i].lchild, HT[i].rchild);
53 }
54 printf("\n");
55 }
56 //初始化(建树和编码表)
57 int Init(){
58 int m = 2*n-1;
59 int i, s1, s2;
60 int w[n+1];//weight 0下标不使用
61 char ch[n+1];//字符
62 char title;
63 char* cd;
64 int start, c, f;
65 //建立哈夫曼树
66 while(title = getchar() != '\n');
67 printf("■请输入各字符(用空格分开):");
68 for(i=1; i<=n; i++){
69 scanf("%c", &ch[i]);
70 getchar();
71 }
72 printf("■请输入各权值(用空格分开):");
73 for(i=1; i<=n; i++)
74 scanf("%d", &w[i]);
75 HT = (HuffmanTree)malloc((m+1)*sizeof(HTNode));//0号节点不使用
76 for(i=1; i<=n; i++){
77 HT[i].ch = ch[i];
78 HT[i].weight = w[i];
79 HT[i].lchild = 0;
80 HT[i].rchild = 0;
81 HT[i].parent = 0;
82 }
83 for(; i<=m; i++){
84 HT[i].ch='-';
85 HT[i].weight=0;
86 HT[i].lchild=0;
87 HT[i].rchild=0;
88 HT[i].parent=0;
89 }
90 for(i=n+1; i<=m; i++){
91 select(i-1, &s1, &s2);
92 HT[s1].parent=i;
93 HT[s2].parent=i;
94 HT[i].lchild=s1;
95 HT[i].rchild=s2;
96 HT[i].weight=HT[s1].weight+HT[s2].weight;
97 }
98 printf("\n■生成的哈夫曼树为:");
99 printHT(m);
100 //从叶子到根逆向求每个字符的哈夫曼编码
101 HC = (HuffmanCode)malloc((n+1)*sizeof(char*));//分配n个字符编码的头指针向量
102 cd = (char*)malloc(n*sizeof(char));//分配求编码的工作空间
103 cd[n-1]='\0';//编码结束符
104 printf("■其编码表为:\n");
105 for(i=1; i<=n; i++){//逐个字符求哈夫曼编码
106 start = n-1;//编码结束符位置
107 for(c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent){
108 if(HT[f].lchild==c)
109 cd[--start]='0';
110 else
111 cd[--start]='1';
112 }
113 HC[i] = (char*)malloc((n-start)*sizeof(char));//为第i个字符编码分配空间
114 strcpy(HC[i], &cd[start]);//从cd复制编码到HC
115 printf("%c: ", HT[i].ch);
116 puts(HC[i]);
117 }
118 free(cd);
119 return OK;
120 }
121 //编码
122 int Encoding(){
123 char s[20], title;
124 int i, j;
125 while(title = getchar() != '\n');
126 printf("\n■请输入字符串:\n");
127 scanf("%s", s);
128 printf("■编码结果为:\n");
129 for(i=0; s[i]!='\0'; i++){
130 for(j=1; j<=n; j++){
131 if(s[i]==HT[j].ch){
132 printf("%s", HC[j]);
133 continue;
134 }
135 }
136 }
137 printf("\n");
138 return OK;
139 }
140 //译码
141 int Decoding(){
142 char s[20], title;
143 int i=0, p=2*n-1;//p在根节点位置;
144 while(title = getchar() != '\n');
145 printf("\n■请输入编码:\n");
146 scanf("%s", s);
147 printf("■译码结果为:\n");
148 for(i = 0; s[i] != '\0'; i++){
149 if(s[i]=='0')
150 p=HT[p].lchild;
151 if(s[i]=='1')
152 p=HT[p].rchild;
153 if(p<=n){
154 printf("%c", HT[p].ch);
155 p=2*n-1;
156 }
157 }
158 printf("\n");
159 return OK;
160 }
161 //菜单
162 void menu(){
163 printf("■■■■■哈夫曼编译码器■■■■■\n");
164 printf("■\t ★1-建立哈夫曼树\t■\n");
165 printf("■\t ★2-编码\t\t■\n");
166 printf("■\t ★3-译码\t\t■\n");
167 printf("■\t ★4-退出\t\t■\n");
168 printf("■■■■■■■■■■■■■■■■■\n");
169 printf("■请选择:");
170 }
171 int main(){
172 char ch, title;
173 while(1){
174 menu();
175 scanf("%c", &ch);
176 switch(ch){
177 case '1':
178 printf("\n■请输入字符数n(n>0):");
179 scanf("%d", &n);
180 Init();
181 break;
182 case '2':
183 Encoding();
184 break;
185 case '3':
186 Decoding();
187 break;
188 case '4':
189 printf("Finished, God bless you!");
190 exit(0);
191 }
192 printf("\n");
193 while(title = getchar() != '\n');
194 }
195 return 0;
196 }