重温经典之赫夫曼(Huffman)编码

先看看赫夫曼树
假设有n个权值{w1,w2,…,wn},构造一个有n个叶子结点的二叉树,每个叶子结点权值为wi,则其中带权路径长度WPL最小的二叉树称作赫夫曼树或最优二叉树。
 
赫夫曼树的构造,赫夫曼最早给出了带有一般规律的算法,俗称赫夫曼算法。如下:
(1)根据给定的n个权值{w1,w2,…,wn}构造n棵二叉树的集合F={T1,T2,…,Tn},其中Ti中只有一个权值为wi的根结点,左右子树为空。
(2)在F中选取两棵根结点的权值为最小的数作为左、右子树以构造一棵新的二叉树,且置新的二叉树的根结点的权值为左、右子树上根结点的权值之和。
(3)在F中删除这两棵树,同时将新得到的二叉树加入到F中。
(4)重复(2)和(3)直到F中只含一棵树为止,这棵树就是赫夫曼树。

 

例如下图便是赫夫曼树的构造过程。其中,根节点上标注的是所赋的权值。

 

 

设计一棵赫夫曼树,由此得到的二进制前缀编码就是赫夫曼编码。那么什么是前缀编码呢?所谓前缀编码,就是若要设计长短不等的编码,则必须是任意一个字符的编码都不是另一个字符编码的前缀。所以我们可以利用二叉树来设计二进制的前缀编码。

 

假设需要传送的字符为:A B A C C D A。如下图就是一个前缀编码的示例。

 http://blog.csdn.net/fengchaokobe/article/details/6969217

说了这么多理论,总该实践一下了,下面是赫夫曼编码的具体实现代码:

  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <malloc.h>  
  4. #include <assert.h>  
  5.   
  6. #define NUM 256  
  7.   
  8. typedef struct{  
  9.     int weight;  
  10.     int parent, lchild, rchild;  
  11. }HTNode, *HuffmanTree;  
  12.   
  13. /******* Choose two smallest from 0 to n in T *************/  
  14. void Select(HuffmanTree T, int len, int *s1, int *s2)  
  15. {  
  16.     int i = 0;  
  17.     while (T[i++].parent != -1);  
  18.     *s1 = i-1;  
  19.     while (T[i++].parent != -1);  
  20.     *s2 = i-1;  
  21.     if (T[*s1].weight>T[*s2].weight) {  
  22.         i = *s1;  
  23.         *s1 = *s2;  
  24.         *s2 = i;  
  25.     }  
  26.     for (i=0; i<=len; i++) {  
  27.         if(T[i].parent == -1) {  
  28.             if (T[*s1].weight > T[i].weight) {  
  29.                 *s2 = *s1;  
  30.                 *s1 = i;  
  31.             }  
  32.             else if (T[*s2].weight >T[i].weight && i != *s1)  
  33.                 *s2 = i;  
  34.         }  
  35.     }  
  36.     return;  
  37. }  
  38.   
  39. void show_binary(char ch)  
  40. {  
  41.     char i;  
  42.   
  43.     for (i = 0; i < 8; i++) {   
  44.         if (ch&0x80)  
  45.             printf("1");  
  46.         else printf("0");  
  47.         if (i == 3)  
  48.             printf(",");  
  49.         ch <<= 1;  
  50.     }  
  51.     printf(" ");  
  52. }  
  53.   
  54. void HuffmanCoding(FILE *psrc, FILE *pdst, FILE *pdeciphering)  
  55. {  
  56.     int i;  
  57.     char ch;  
  58.         int m = 2*NUM-1;  
  59.         int size = m*sizeof(HTNode);  
  60.         HuffmanTree HT = (HuffmanTree)malloc(size);  
  61.         assert(HT);  
  62.         memset(HT, -1, size);  
  63.   
  64.         for (i=0; i<NUM; i++)  
  65.             HT[i].weight = 0;  
  66.         while ((ch=fgetc(psrc)) != EOF) {  
  67.             (HT[ch].weight)++;  
  68.         }  
  69.         rewind(psrc);  
  70. /******************printf the Huffman weight**** 
  71.     int j; 
  72.     for(j=0; j<NUM; j++) { 
  73.         printf("%c:%d\t", j, HT[j].weight); 
  74.     } 
  75. **********************************************/  
  76.         int s1, s2;  
  77.         for (i=NUM; i<m; i++) {  
  78.             Select(HT, i-1, &s1, &s2);  
  79.             HT[s1].parent = i; HT[s2].parent = i;  
  80.             HT[i].lchild = s1; HT[i].rchild = s2;  
  81.             HT[i].weight = HT[s1].weight + HT[s2].weight;  
  82.         }  
  83. /*******************printf the HuffmanTree********* 
  84.         int j; 
  85.         for (j=0; j<m; j++) 
  86.             printf("%d:w%d p%d l%d r%d\t\t", j, HT[j].weight,  
  87.                     HT[j].parent, HT[j].lchild, HT[j].rchild); 
  88. **************************************************/       
  89.         char **HC = (char**)malloc(NUM*sizeof(char*));  
  90.         char* cd = (char*)malloc(NUM*sizeof(char));  
  91.         cd[NUM-1] = '\0';  
  92.         int start,c,f;  
  93.         for (i=0; i<NUM; i++) {  
  94.             start = NUM-1;  
  95.             for (c=i,f=HT[i].parent; f!=-1; c=f,f=HT[f].parent) {  
  96.                 if (HT[f].lchild==c) cd[--start] ='0';  
  97.                 else cd[--start] ='1';  
  98.             }  
  99.             HC[i] = (char *)malloc((NUM-start)*sizeof(char));  
  100.             strcpy(HC[i], &cd[start]);  
  101.         }  
  102. /************printf the Huffmancode****************************** 
  103.         int j; 
  104.         for (j=0; j<NUM; j++) { 
  105.             printf("%c:%s\t", j, HC[j]); 
  106.         } 
  107. ****************************************************************/  
  108.         char buff[100] = {0};     
  109.         char k = 0, j = 0;  
  110.         while ((ch=fgetc(psrc)) != EOF) {  
  111.             i = -1;   
  112.             while (HC[ch][++i] != '\0') {  
  113.                 buff[j] <<= 1;  
  114.                 k++;  
  115.                 if (HC[ch][i] == '1')  
  116.                     buff[j] |= 0x01;  
  117.                 if ((k %= 8) == 0)  
  118.                     j++;  
  119.                 if (j == 100) {  
  120.                     j =0;  
  121.                     fwrite(buff, 1, 100, pdst);  
  122.                 }  
  123.   
  124.             }  
  125.         }  
  126.         buff[j] <<= (8-k);  
  127.         fwrite(buff, 1, j + 1, pdst);  
  128.         /***************************************************** 
  129.         printf("\ndata write to %s\n", dstfile); 
  130.         for (i=0; i<=j; i++) 
  131.         show_binary(buff[i]); 
  132.         ***************************************************/  
  133.         rewind(pdst);  
  134.         fflush(pdst);  
  135.         c = 510;  
  136.         while (!feof(pdst)) {  
  137.             j = fread(buff, 1, 100, pdst);  
  138.             /******************************************** 
  139.             printf("\nfrom read:\n"); 
  140.             for (i=0; i<j; i++) 
  141.                 show_binary(buff[i]); 
  142.             *******************************************/  
  143.             for (i=0; i<j; i++) {  
  144.                 for (k=0; k<8; k++) {  
  145.                     if (buff[i]&0x80)  
  146.                         c = HT[c].rchild;  
  147.                     else c = HT[c].lchild;  
  148.                     if (HT[c].lchild == -1) {  
  149.                     fputc((char)c, pdeciphering);  
  150.                     c = 510;  
  151.                     }  
  152.                     buff[i] <<= 1;  
  153.                 }     
  154.             }  
  155.         }  
  156.   
  157. /**************free the memery and return*******************/  
  158.         for(i=0; i<NUM; i++) {  
  159.             free(HC[i]);  
  160.         }  
  161.         free(cd);  
  162.         free(HC);  
  163.         free(HT);  
  164.         HT = NULL;  
  165.         fclose(pdst);  
  166.         fclose(psrc);  
  167.         fclose(pdeciphering);  
  168.     return;  
  169.   
  170. }  
  171.   
  172. int main(void)  
  173. {  
  174.     char srcfile[100], dstfile[100],deciphering[100];  
  175.     printf("Input source file:");  
  176.     scanf("%s", srcfile);  
  177.     printf("Input dest file:");  
  178.     scanf("%s", dstfile);  
  179.     printf("Input deciphering file:");  
  180.     scanf("%s", deciphering);  
  181.     FILE *psrc = fopen(srcfile, "r");  
  182.     FILE *pdst = fopen(dstfile, "w+");  
  183.     FILE *pdeciphering = fopen(deciphering, "w");  
  184.     if (psrc == NULL || pdst == NULL || pdeciphering == NULL) {  
  185.         printf("file opened failed\n");  
  186.         return -1;  
  187.     }   
  188.     else   
  189.     HuffmanCoding(psrc, pdst, pdeciphering);  
  190.     return 0;  
  191. }  
posted @ 2018-06-30 14:06  lightmare  阅读(157)  评论(0编辑  收藏  举报