求哈弗曼编码
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 }