利用哈弗曼树压缩文件

这个程序从上周复习完树开始写,中途一有空就调这程序,到今天才正式写完。

中途遇到不少问题,但是写完了确实有成就感,也觉得这是自己目前写得最有意义的一个程序.

这个程序的思路如下

1.按字节读取文件

2.将1个字节看做一个单位统计每个单位出现的次数(0x00-0xff)

3.根据出现的次数创建一颗哈弗曼树

4.根据哈弗曼树创建对应的索引表

5.重新读取文件,根据索引表找出每个单位的哈弗曼编码写入文件,这里有一个很难搞定的东西,就是每个单位的哈弗曼编码是不等长的,有的不足一字节,有的甚至达到5,6个字节,为了将这些东西写入文件我做了很多位的处理,希望看明白我代码的通知有更好的处理办法告诉我

解压按照上面5步反过来既可!

写这个程序有一大半时间花在处理末尾字节的乱码上,试过很多种办法,最后发现自己越走越远,办法越来越复杂。

最后用了一个很简单却有效的方法,用了一个long long型的变量来统计文件的位数,long long型变量在的范围在2^64-1/2,完全不存在溢出的可能性,以前的代码为了处理这最后几个字节乱码凭空多了100多行,没想到就这么解决了,所以说,简单往往也有效。

最后,上代码

Code:

  1. /*利用哈夫曼编ç ?对文件进行å?‹ç¼©*/  
  2. /*ç«¥*/  
  3. #include<stdio.h>  
  4. #include<malloc.h>  
  5. #include<stdlib.h>  
  6. #include<string.h>  
  7.   
  8. #define LEN 1024/*step 1k*/  
  9. #define MAX 256  
  10. #define CHAR_B 8  
  11. #define TREE_DEEP (MAX/2+1)/*哈夫曼树最大高度是MAX/2+1*/  
  12.   
  13. typedef unsigned char uc;  
  14.   
  15. typedef struct node{  
  16.     int item;/*出ç?°çš„次数*/  
  17.     int i;/*对应的下标*/  
  18.     struct node *left;  
  19.     struct node *right;  
  20. }*link;  
  21.   
  22. /*FIXME:没有释放哈夫曼的内存*/  
  23.   
  24. /*节点æ?„造函数:用äº?æ?„造一个2å?‰æ ‘节点*/  
  25. link NODE(int item, int i, link left, link right)  
  26. {  
  27.     link t = malloc(sizeof *t);  
  28.   
  29.     t->item = item;  
  30.     t->left = left;  
  31.     t->right = right;  
  32.     t->i = i;  
  33.     return t;  
  34. }  
  35.   
  36. /*堆的下移æ“?作函数*/  
  37. void shif_down(link heap_head[], int i, int len)  
  38. {  
  39.     int tmp = i;  
  40.     while(2*tmp <= len)  
  41.     {  
  42.         i = tmp;  
  43.         tmp *= 2;  
  44.         if(tmp+1 <= len && heap_head[tmp+1]->item < heap_head[tmp]->item)   
  45.             tmp++;/*判断左å?³å­?树的大å°?*/  
  46.         if(heap_head[i]->item > heap_head[tmp]->item)  
  47.         {  
  48.             link mid = heap_head[i];  
  49.             heap_head[i] = heap_head[tmp];  
  50.             heap_head[tmp] = mid;  
  51.         }  
  52.     }  
  53. }  
  54.   
  55. /*堆的上移*/  
  56. void shif_up(link heap_head[], int i)  
  57. {  
  58.     int father = i/2;  
  59.     link tmp;  
  60.     while(father >= 1)  
  61.     {  
  62.         if(heap_head[father]->item > heap_head[i]->item)  
  63.         {  
  64.             tmp = heap_head[father];  
  65.             heap_head[father] = heap_head[i];  
  66.             heap_head[i] = tmp;  
  67.         }  
  68.         father = father/2;  
  69.     }  
  70. }  
  71.   
  72. /*创建堆*/  
  73. void build_heap(link heap_head[])  
  74. {  
  75.     int i;  
  76.     for(i = MAX / 2; i > 0; i–)  
  77.         shif_down(heap_head, i, MAX);/*max/2是ä»?å??开始第一个有孩å­?节点的节点*/  
  78. }  
  79.   
  80. /*删除并返å›?堆顶元素*/  
  81. link delmin(link heap_head[], int *len)  
  82. {  
  83.     link ret = heap_head[1];  
  84.     link tmp = heap_head[1];  
  85.     heap_head[1] = heap_head[*len];  
  86.     heap_head[*len] = tmp;  
  87.     (*len)–;  
  88.     shif_down(heap_head, 1, *len);  
  89.   
  90.     return ret;  
  91. }  
  92.   
  93. /*往堆中æ?’入元素*/  
  94. void insert(link heap_head[], int *len, link item)  
  95. {  
  96.     heap_head[++(*len)] = item;  
  97.     shif_up(heap_head, *len);  
  98. }  
  99.   
  100. /*创建哈夫曼树*/  
  101. link creat_huffman(int count[])  
  102. {  
  103.     int len = MAX, i;  
  104.     link* heap_head = malloc(len*sizeof(link));//堆中存放指针  
  105.     link min1, min2;  
  106.     heap_head–;//堆下标ä»?1开始  
  107.   
  108.     for(i = 1; i <= len; i++)  
  109.         heap_head[i] = NODE(count[i-1],i – 1, NULL, NULL);  
  110.     build_heap(heap_head);  
  111.     while(len > 1)  
  112.     {  
  113.         min1 = delmin(heap_head, &len);  
  114.         min2 = delmin(heap_head, &len);  
  115.         insert(heap_head, &len, NODE(min1->item + min2->item, -1 ,min1, min2));  
  116.     }  
  117.   
  118.     return delmin(heap_head, &len);  
  119. }  
  120.   
  121. /*统计文件中0x00-0xff分别的个数*/  
  122. void char_count(int count[], uc *buf, int len)  
  123. {  
  124.     int i;  
  125.     for(i = 0; i < len; i++)  
  126.         count[buf[i]]++;  
  127. }  
  128.   
  129. void print_count(int count[])  
  130. {  
  131.     int i;  
  132.     for(i = 0; i < MAX; i++)  
  133.         printf(“%d “, count[i]);  
  134. }  
  135.   
  136. void print_huffman(link head)  
  137. {  
  138.     if(head){  
  139. //  printf(“(“);  
  140.     printf(“%d “, head->item);  
  141.     print_huffman(head->left);  
  142.     print_huffman(head->right);  
  143. //  printf(“)”);  
  144.     }  
  145. //  else printf(“()”);  
  146. }  
  147.   
  148. /*打å?°å»ºç«‹çš„表*/  
  149. void print_table(char *table[])  
  150. {  
  151.     int i;  
  152.     for(i = 0; i < MAX; i++){  
  153.         while(*table[i] != 0)  
  154.             putchar(*table[i]++ + ‘0’);  
  155.         printf(“/n”);  
  156.     }  
  157. }  
  158.   
  159. /*创建用äº?查询的表,下标是0x00-0xff之间的值,对应的table[i]是一个字符串, 
  160.  *该字符串用äº?存放i值的哈夫曼编ç ?,为区分0ä¸?/0用2表示0 
  161.  *å?‚æ•°1是一个指针数组,将得到的所有内容带å›? 
  162.  *å?‚æ•°2是创建的哈夫曼树的根 
  163.  *å?‚æ•°3带å›?本文件å?‹ç¼©å??çš„2进制ç ?总长度 
  164.  * */  
  165. void creat_table(char *table[], link head, long long *count)  
  166. {  
  167.     static int deep = 0;  
  168.     static char buf[MAX] = {0};/*2 means the code 0*/  
  169.     if(head != NULL)  
  170.     {  
  171.         deep++;  
  172.         if(head->i >= 0)  
  173.         {  
  174.             table[head->i] = malloc((deep + 1) * sizeof(char));  
  175.             buf[deep – 1] = ‘/0’;  
  176.             (*count) += ((deep -1)*head->item);  
  177.             strcpy(table[head->i], buf);  
  178.         }  
  179.         buf[deep-1] = 2;  
  180. //      buf[deep] = ‘/0’;  
  181.         creat_table(table, head->left, count);  
  182.         buf[deep-1] = 1;  
  183.         creat_table(table, head->right, count);  
  184.         –deep;  
  185. //      buf[–deep] = ‘/0’;  
  186.     }  
  187. }  
  188.   
  189. /*å?‹ç¼©æ–‡ä»¶*/  
  190. void compress(char *filename)  
  191. {  
  192.     FILE *in, *out;  
  193.     int count[MAX] = {0};  
  194.     uc buf[LEN] = {0}, ch, bit_buf = 0;  
  195.     char *table[MAX] = {0}, name[LEN];  
  196.     int i, j;  
  197.     link head;  
  198.     long long bit_count = 0;  
  199.   
  200.     strncpy(name, filename, LEN);  
  201.   
  202.     if((in = fopen(name, “rb”)) == NULL)  
  203.     {  
  204.         printf(“Can not open file %s/n”, name);  
  205.         exit(0);  
  206.     }  
  207.    
  208.   
  209.     while(1)  
  210.     {  
  211.         for(i = 0; i < LEN && !feof(in); i++)  
  212.             buf[i] = (uc)fgetc(in);  
  213.         if(!feof(in))  
  214.         {  
  215.             char_count(count, buf, i);  
  216.         }  
  217.         else  
  218.         {   
  219.             char_count(count, buf, i – 1);/*多读了1字节*/  
  220.             break;  
  221.         }  
  222.     }  
  223.   
  224.     head = creat_huffman(count);  
  225.     creat_table(table, head, &bit_count);  
  226.       
  227.     fclose(in);  
  228.       
  229.     if((in = fopen(name, “r”)) == NULL)  
  230.     {  
  231.         perror(“Error”);  
  232.         exit(0);  
  233.     }  
  234.   
  235.     strncat(name, “.t”, LEN);  
  236.       
  237.     if((out = fopen(name, “w”)) == NULL)  
  238.     {  
  239.         perror(“Error”);  
  240.         exit(0);  
  241.     }  
  242.   
  243.     /*写入å?‹ç¼©ä¿¡æ?¯*/  
  244.     for(i = 0; i < MAX; i++)  
  245.     {  
  246.         fprintf(out, “%d/n”, count[i]);  
  247.     }  
  248.       
  249.     ch = fgetc(in);  
  250.     j = 0;  
  251.   
  252.     while(1)  
  253.     {  
  254.         if(feof(in)) break;  
  255.           
  256.         for(i = 0; i < CHAR_B; i++, j++)/*j需è¦?上一次的结æ?œ*/  
  257.         {  
  258.             bit_buf = (bit_buf<<1) | (!((uc)table[ch][j]>>1));  
  259. //          bit_count++;  
  260.             if(table[ch][j + 1] == ‘/0’)   
  261.             {     
  262.                 ch = fgetc(in);  
  263.                 j = -1;  
  264.                 if(feof(in)) break;  
  265.             }  
  266.         }  
  267.           
  268.         if(i == CHAR_B)   
  269.         {  
  270.             fputc(bit_buf, out);  
  271.         }  
  272.         else  
  273.         {  
  274.             fputc(bit_buf << (CHAR_B – i -1), out);  
  275.         }  
  276.     }  
  277.       
  278.       
  279.     fclose(in);  
  280.     fclose(out);  
  281. }  
  282.   
  283. /*解å?‹ç¼©æ–‡ä»¶*/  
  284. void decompress(char *filename)  
  285. {  
  286.     FILE *in, *out;  
  287.     int count[MAX] = {0};  
  288.     uc ch, bit_buf = 0;  
  289.     char *table[MAX] = {0}, name[LEN];  
  290.     int i;  
  291.     link head, p;  
  292.     long long bit_count = 0;  
  293.   
  294.     strncpy(name, filename, LEN);  
  295.   
  296.     if((in = fopen(name, “r”)) == NULL)  
  297.     {  
  298.         perror(“Error”);  
  299.         exit(0);  
  300.     }  
  301.       
  302.     name[strlen(name) – 2] = ‘/0’;  
  303.   
  304.     if((out = fopen(name, “w”)) == NULL)  
  305.     {  
  306.         perror(“Error”);  
  307.         exit(0);  
  308.     }  
  309.   
  310.     for(i = 0; i < MAX; i++)  
  311.     {  
  312.         fscanf(in, “%d/n”, &count[i]);  
  313.     }  
  314.       
  315.     bit_count = 0;  
  316.     head = creat_huffman(count);  
  317.     creat_table(table, head, &bit_count);  
  318.       
  319.     ch = fgetc(in);  
  320.     bit_buf = fgetc(in);  
  321.     i = 0;   
  322.       
  323.     while(bit_count > 0)  
  324.     {  
  325.         p = head;  
  326.           
  327.         for(;p->left != NULL && p->right != NULL; i++)  
  328.             //i需è¦?使用上一次循ç?¯çš„结æ?œ  
  329.         {  
  330.             if(i == CHAR_B)  
  331.             {  
  332.                 i = 0;  
  333.                 ch = bit_buf;  
  334.                 bit_buf = fgetc(in);  
  335.             }  
  336.             if(ch&0x80)  
  337.             {  
  338.                 p = p->right;  
  339.             }  
  340.             else  
  341.             {  
  342.                 p = p->left;  
  343.             }  
  344.               
  345.             ch = (ch << 1) | (bit_buf >> (CHAR_B – i – 1));  
  346.             bit_count–;  
  347.         }  
  348.   
  349.         fputc(p->i, out);  
  350.     }  
  351.     fclose(in);  
  352.     fclose(out);  
  353.   
  354. }  
  355.   
  356. #if 1  
  357. int main(int argc, char *argv[])  
  358. {  
  359.     int len;  
  360.   
  361.     if(argc > 3  || argc < 3 || !((argv[1][1] == ‘C’) ||(argv[1][1] == ‘D’)))   
  362.     {  
  363.         fprintf(stderr, “Usage <%s>[-C/D]<filename>/nC:compress/nD:decompress/n”, argv[0]);  
  364.         exit(1);  
  365.     }  
  366.   
  367.     if(argv[1][1] == ‘C’)  
  368.     {  
  369.         compress(argv[2]);  
  370.     }  
  371.     else  
  372.     {  
  373.         len = strlen(argv[2]);  
  374.         if(argv[2][len – 1] != ‘t’ || argv[2][len – 2] != ‘.’)  
  375.         {  
  376.             fprintf(stderr, “%s is not a .t file/n”, argv[2]);  
  377.             exit(1);  
  378.         }  
  379.         decompress(argv[2]);  
  380.     }  
  381.     return 0;  
  382. }  
  383.   
  384. #endif  
  385.   
  386. #if 0  
  387. int main(void)  
  388. {  
  389.     int count[] = {5, 29, 7, 8, 14, 23, 3, 11};  
  390.   
  391.     char *table[MAX] = {0};  
  392.     link head = creat_huffman(count);  
  393.   
  394.     creat_table(table, head);  
  395.     print_table(table);  
  396.     printf(“//tree”);  
  397.     print_huffman(head);  
  398.       
  399.     printf(“/n”);  
  400.     return 0;  
  401. }  
  402. #endif  

 

    原文作者:哈夫曼树
    原文地址: https://blog.csdn.net/t1397018/article/details/6479447
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞