【构造哈夫曼树】

假设有n个叶子结点,对应的权值分别是w1、w2、....,wn则哈夫曼树的构造如下:

(1)将w1,w2,....wn看成是有n课树的森林(每棵树仅有一个结点)。
(2)在森林中选出两个根结点权值最小的树合并,作为一棵新树的左、右子树,且新树的根结点权值为左、右子树结点权值之和。
(3)从森林中删除选取的两棵树,并将新树加入森林。
(4)重复执行(2)和(3),直到森林中只剩一棵树为止,该树即为所求的哈夫曼树。

【哈夫曼编码】

哈夫曼编码常应用在数据通信中,在数据传送时,需要将字符转换为二进制的字符串。例如,如果传送的电文是ACBAADCB,电文中有A、B、C和D四种字符,如果规定A、B、C和D的编码分别为00、01、 10和11,则上面的电文代码为00001011001,共16个二进制数。

在传送电文时,希望电文的代码尽可能的短。如果按照每个字符长度不等进行编码,出现频率高的字符采用尽可能短的编码,那么电文的代码长度就会减少。这可以利用哈夫曼树对电文进行编码,最后得到的编码就是长度最短的编码。具体构造方法如下:

假设需要编码的字符集合为{c1,c2,...,cn}相应的字符在电文中的出现次数{w1,w2,...,wn},以字符c1,c2,...,cn作为叶子结点,以w1,w2,...,wn为对应叶子结点的权值构造一棵二叉树,规定哈夫曼树的左孩子分支为0,右孩子分支为1,从根结点到每个叶子结点经过的分支组成的0和1序列就是结点对应的编码。

例如,字符集合为{A.B.C,D},各个字符相应的出现次数为{4,1,1,2},将这些字符作为叶子结点,出现次数作为叶子结点的权值,相应的哈夫曼树如图.

从图中不难看出,字符A的编码为0,字符B的编码为110,字符C的编码为11,字符D的编码为10。因此,可以得到电文ACBAADCB的C的编码为,' 01111100010111110。这样就保证了电文的编码长度最短。

在设计不等长编码时,必须使任何一个字符的编码都不是另外一个字符编码的前缀。例如,字符A的编码为11,字符B的编码为110,则字符A的编码就称为字符B的编码的前缀。如果一个代码为 11010, 在进行译码时,无法确定是将前两位译为A,还是要将前三位译为B。但是在利用哈夫曼树进行编码时,不会出现-个字符的编码是另一 个字 符编码的前缀编码。

【分析】

构造哈夫曼树的过程利用了贪心选择的性质,每次都是从结点集合中选择权值最小的两个结点构造一个新树。 这就保证了贪心选择的局部最优的性质。

code:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <iostream>
typedef struct
{unsigned int weight;  /*权值*/unsigned int parent, LChild, RChild;  /*指向双亲、左右孩子结点的指针*/
} HTNode, *HuffmanTree;  /*存储哈夫曼树*/
typedef char *HuffmanCode;  /*存储哈夫曼编码*/
void CreateHuffmanTree(HuffmanTree *ht, int *w, int n);
void Select(HuffmanTree *ht, int n, int *s1, int *s2);
void CreateHuffmanCode(HuffmanTree *ht, HuffmanCode *hc, int n);
void main()
{HuffmanTree HT;HuffmanCode HC;int *w, i, n, w1;printf("***********哈夫曼编码***********\n");printf("请输入结点个数:");scanf("%d", &n);w = (int *)malloc((n + 1)*sizeof(int));printf("输入这%d个元素的权值:\n", n);for (i = 1; i <= n; i++){printf("%d: ", i);//      fflush(stdin);scanf("%d", &w1);w[i] = w1;}CreateHuffmanTree(&HT, w, n);/*构造哈夫曼树*/CreateHuffmanCode(&HT, &HC, n);/*构造哈夫曼编码*/system("pause");
}
void CreateHuffmanTree(HuffmanTree *ht, int *w, int n)
/*构造哈夫曼树ht,w存放已知的n个权值*/
{int m, i, s1, s2;m = 2 * n - 1;    /*结点总数*/*ht = (HuffmanTree)malloc((m + 1)*sizeof(HTNode));for (i = 1; i <= n; i++)  /*初始化叶子结点*/{(*ht)[i].weight = w[i];(*ht)[i].LChild = 0;(*ht)[i].parent = 0;(*ht)[i].RChild = 0;}for (i = n + 1; i <= m; i++)  /*初始化非叶子结点*/{(*ht)[i].weight = 0;(*ht)[i].LChild = 0;(*ht)[i].parent = 0;(*ht)[i].RChild = 0;}printf("\n哈夫曼树为: \n");for (i = n + 1; i <= m; i++)   /*创建非叶子结点,建哈夫曼树*//*在(*ht)[1]~(*ht)[i-1]的范围内选择两个最小的结点*/{Select(ht, i - 1, &s1, &s2);(*ht)[s1].parent = i;(*ht)[s2].parent = i;(*ht)[i].LChild = s1;(*ht)[i].RChild = s2;(*ht)[i].weight = (*ht)[s1].weight + (*ht)[s2].weight;printf("%d (%d, %d)\n",(*ht)[i].weight, (*ht)[s1].weight, (*ht)[s2].weight);}printf("\n");
}
void CreateHuffmanCode(HuffmanTree *ht, HuffmanCode *hc, int n)
/*从叶子结点到根,逆向求每个叶子结点对应的哈夫曼编码*/
{char *cd;   /*定义的存放编码的空间*/int a[100];int i, start, p, w = 0;unsigned int c;hc = (HuffmanCode *)malloc((n + 1)*sizeof(char *));  /*分配n个编码的头指针*/cd = (char *)malloc(n*sizeof(char));  /*分配求当前编码的工作空间*/cd[n - 1] = '\0';  /*从右向左逐位存放编码,首先存放编码结束符*/for (i = 1; i <= n; i++)/*求n个叶子结点对应的哈夫曼编码*/{a[i] = 0;start = n - 1;  /*起始指针位置在最右边*/for (c = i, p = (*ht)[i].parent; p != 0; c = p, p = (*ht)[p].parent)/*从叶子到根结点求编码*/{if ((*ht)[p].LChild == c){cd[--start] = '0';  /*左分支记作0*/a[i]++;}else{cd[--start] = '1';  /*右分支记作1*/a[i]++;}}/*为第i个编码分配空间*/hc[i] = (char *)malloc((n - start)*sizeof(char));strcpy(hc[i], &cd[start]); /*将cd复制编码到hc*/}free(cd);for (i = 1; i <= n; i++)printf("权值为%d的哈夫曼编码为:%s\n", (*ht)[i].weight, hc[i]);for (i = 1; i <= n; i++)w += (*ht)[i].weight*a[i];printf("带权路径为:%d\n", w);
}
void Select(HuffmanTree *ht, int n, int *s1, int *s2)
/*选择两个parent为0,且weight最小的结点s1和s2*/
{int i, min;for (i = 1; i <= n; i++){if ((*ht)[i].parent == 0){min = i;break;}}for (i = 1; i <= n; i++){if ((*ht)[i].parent == 0){if ((*ht)[i].weight < (*ht)[min].weight)min = i;}}*s1 = min;for (i = 1; i <= n; i++){if ((*ht)[i].parent == 0 && i != (*s1)){min = i;break;}}for (i = 1; i <= n; i++){if ((*ht)[i].parent == 0 && i != (*s1)){if ((*ht)[i].weight < (*ht)[min].weight)min = i;}}*s2 = min;
}

结果:

贪心算法2——哈夫曼编码相关推荐

  1. 贪心算法-03哈夫曼编码问题

    哈夫曼编码 简介 哈夫曼编码是一种字符编码方式,可以对指定的字符集进行数据压缩,压缩率在20%到90%. 问题描述 现在有一个包含5个字符{A,B,C,D,E},各个字符的出现频率依次为{0.35, ...

  2. 算法导论——贪心算法:哈夫曼编码(霍夫曼编码)

    2019独角兽企业重金招聘Python工程师标准>>> package org.loda.greedy;import org.junit.Test; import org.loda. ...

  3. 霍夫曼算法_霍夫曼编码算法

    霍夫曼算法 In this tutorial, we'll be discussing and implementing the Huffman Coding Algorithm in Java. 在 ...

  4. 哈夫曼算法证明+哈夫曼编码译码程序实现

    哈夫曼算法证明 哈夫曼算法是一种贪心算法,我们考虑证明其最优子结构和贪心选择性质: 最优子结构:假设一个树是哈夫曼树,则以其任意节点为根节点的最大子树也是哈夫曼树. 证明:子树的根节点的值是其所有叶子 ...

  5. 数据结构与算法之霍夫曼编码解码实现

    目标:将字符串"can you can a can as a can canner can a can."编码再解码 流程: 将字符串转成bytes (byte[]格式)(eg.[ ...

  6. 18.C#写算法之“哈夫曼编码” 是什么鬼?

    文章参考自:程序员小灰:漫画:"哈夫曼编码" 是什么鬼? 哈夫曼编码是一种高效的编码方式,在信息存储和传输过程中,用于对信息进行压缩. 计算机系统是如何存储信息的呢? 计算机不是人 ...

  7. 哈夫曼编码压缩率计算_程序员的算法课(8)-贪心算法:理解霍夫曼编码

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/m0_37609579/article/ ...

  8. 贪心算法之用优先队列(priority_queue)实现哈夫曼编码问题

    1.问题 参考我的博客:贪心算法之哈夫曼编码问题 2.优先队列知识复习 参考我的博客: C++之STL之priority_queue 3.代码实现 #include <iostream> ...

  9. 程序员的算法课(8)-贪心算法:理解霍夫曼编码

    一.一种很贪婪的算法定义 贪心是人类自带的能力,贪心算法是在贪心决策上进行统筹规划的统称. [百度百科]贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择.也就是说,不从整体 ...

最新文章

  1. nginx系列:nginx反向缓存代理详解
  2. 李彦宏:正在发生的智能经济 4 大变革 | 赠书
  3. EMC Networker与mhvtl虚拟磁带库的结合on rhel5.5
  4. 如何编写和应用Java的自定义异常类
  5. 微服务化之缓存的设计
  6. 【进程】进程通信-共享内存
  7. 堆栈图解CSAPP Bomb Lab实验解析
  8. html5中event获取data和class
  9. SQLite查询优化(转)
  10. 手机处理器排名2019_手机CPU天梯图2020年3月最新版 你的手机处理器排名高吗?...
  11. python alphago_使用 Python 搭建简易版AlphaGo
  12. 光谱数据计算色彩指标的软件(功能强大,齐全)
  13. FID - Web特征数据来了
  14. Yapi远程命令执行漏洞
  15. 腾讯C++后台开发实习面经(已拿offer)
  16. 使用Kaggle API下载数据集
  17. [转载]多普达手机全揭露
  18. 自学编程的艰辛和乐趣
  19. python3使用腾讯企业邮箱发送邮件
  20. 第一课时(下):破解基础之常见加壳程序特征

热门文章

  1. ReflectionClass
  2. jmeter导出jtl文件和report文件夹
  3. iPhone让路MOTO王者觉醒 里程碑购机请注意
  4. springboot tomcat 线程数相关配置
  5. JavaScript基础(一)(编程语言,计算机基础,初始JavaScript,JavaScript注释,输入输出语句,变量的概念,变量的使用,数据类型,解释型语言和编译型语言)
  6. 微软不再支持XP 韩国怒了!
  7. 骁龙820A高级驾驶辅助系统(ADAS)
  8. 画栋雕梁:定制投资体系4——持有、波动与卖出
  9. 十九、帧间预测编码_1、帧间预测编码的基本原理
  10. 简陋的spring cloud搭建并部署云服务器