• 重温经典之赫夫曼(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 ", 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 ", 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] = '';  
    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 ", 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] != '') {  
    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(" data write to %s ", 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(" from read: "); 
    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 ");  
    186.         return -1;  
    187.     }   
    188.     else   
    189.     HuffmanCoding(psrc, pdst, pdeciphering);  
    190.     return 0;  
    191. }  
  • 相关阅读:
    go语言练习:go实现md5
    go语言练习:结构体
    go语言练习:指针
    go语言练习:数组
    DEL: MySQL Learning
    EV: Notepad++: Insert Timestamp -- Using Python
    EV: 文件共享的问题
    EV: Ruby: 安装和运行rails
    EV: MySQL Clear Screen
    EV: Ubuntu 的root用户password问题
  • 原文地址:https://www.cnblogs.com/lightmare/p/10434843.html
Copyright © 2020-2023  润新知