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

重温经典之赫夫曼(Huffman)编码的更多相关文章

  1. puk1521 赫夫曼树编码

    Description An entropy encoder is a data encoding method that achieves lossless data compression by ...

  2. 哈夫曼(Huffman)编码

    哈夫曼编码(Huffman Coding)是一种非常经典的编码方式,属于可变字长编码(VLC)的一种,通过构造带权路径长度最小的最优二叉树以达到数据压缩的目的.哈弗曼编码实现起来也非常简单,在实际的笔 ...

  3. javascript实现数据结构: 树和二叉树的应用--最优二叉树(赫夫曼树),回溯法与树的遍历--求集合幂集及八皇后问题

    赫夫曼树及其应用 赫夫曼(Huffman)树又称最优树,是一类带权路径长度最短的树,有着广泛的应用. 最优二叉树(Huffman树) 1 基本概念 ① 结点路径:从树中一个结点到另一个结点的之间的分支 ...

  4. 【算法】赫夫曼树(Huffman)的构建和应用(编码、译码)

    参考资料 <算法(java)>                           — — Robert Sedgewick, Kevin Wayne <数据结构>       ...

  5. C++哈夫曼树编码和译码的实现

    一.背景介绍: 给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree).哈夫曼树是带权路径长度最短的树,权值较大的 ...

  6. 【数据结构】赫夫曼树的实现和模拟压缩(C++)

    赫夫曼(Huffman)树,由发明它的人物命名,又称最优树,是一类带权路径最短的二叉树,主要用于数据压缩传输. 赫夫曼树的构造过程相对比较简单,要理解赫夫曼数,要先了解赫夫曼编码. 对一组出现频率不同 ...

  7. Android版数据结构与算法(七):赫夫曼树

    版权声明:本文出自汪磊的博客,未经作者允许禁止转载. 近期忙着新版本的开发,此外正在回顾C语言,大部分时间没放在数据结构与算法的整理上,所以更新有点慢了,不过既然写了就肯定尽力将这部分完全整理好分享出 ...

  8. 赫夫曼树JAVA实现及分析

    一,介绍 1)构造赫夫曼树的算法是一个贪心算法,贪心的地方在于:总是选取当前频率(权值)最低的两个结点来进行合并,构造新结点. 2)使用最小堆来选取频率最小的节点,有助于提高算法效率,因为要选频率最低 ...

  9. Java数据结构和算法(四)赫夫曼树

    Java数据结构和算法(四)赫夫曼树 数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html) 赫夫曼树又称为最优二叉树,赫夫曼树的一个 ...

随机推荐

  1. CC20:高度最小的BST

    题目 对于一个元素各不相同且按升序排列的有序序列,请编写一个算法,创建一棵高度最小的二叉查找树. 给定一个有序序列int[] vals,请返回创建的二叉查找树的高度. 解法 这道题感觉如果没有创建树的 ...

  2. HDU-3639-Hawk-and-Chicken(强连通,缩点,DFS)

    链接:https://vjudge.net/problem/HDU-3639 题意: 有n个小朋友在一个班级中,现在要选择班长.收集了小朋友们的意见,一条意见表示为A认为B合适.这个是具备传递性的,A ...

  3. python 4学习 list 和 tuple

    list Python内置的一种数据类型是列表:list.list是一种有序的集合,可以随时添加和删除其中的元素. 比如,列出班里所有同学的名字,就可以用一个list表示: >>> ...

  4. 使用MRUnit对MapReduce进行单元测试

    1. 为什么需要单元测试 一旦MapReduce项目提交到集群之后,若是出现问题是很难定位和修改的,只能通过打印日志的方式进行筛选.又如果数据和项目较大时,修改起来则更加麻烦.所以,在将MapRedu ...

  5. 网络文件系统(NFS)的使用

    一.简介 NFS--Network FileSystem,即网络文件系统,主要功能是让网络上的不同操作系统之间共享数据. 远程服务器端共享出文件或目录,然后远羰共享出来的文件或目录就可通过挂 载的方式 ...

  6. javascript对象的学习

    一.对象的定义: 对象是JavaScript的一个基本数据类型,是一种复合值,它将很多值(原始值或者其他对象)聚合在一起,可通过名字访问这些值.即属性的无序集合. JavaScript 提供多个内建对 ...

  7. 【js类库AngularJs】解决angular+springmvc的post提交问题

    [js类库AngularJs]解决angular+springmvc的post提交问题 AngularJS诞生于2009年,由Misko Hevery 等人创建,后为Google所收购.是一款优秀的前 ...

  8. 微软大礼包 | 集合在线学习资源,助你秒变AI达人

    编者按:人工智能的浪潮正如火如荼地袭来,未来人工智能将大有所为,人们的生活轨迹也正在技术不断向前推进的过程中逐渐改变.人工智能不是科研人员或开发人员的专属,微软希望能够将人工智能带给每个人,从开发者到 ...

  9. python读xml文件

    # -*- coding:utf-8 -*- import jsonimport requestsimport os curpath=os.path.dirname(os.path.realpath( ...

  10. web端 第一天认识基础

    .NET 分为两大类 一.客户端应用程序   C/S 技术: Winform WPF MFC   MVVM 二.外部端应用程序  B/S(网页端应用程序/WEB端/WEB端应用程序) 目前学的技术是A ...