先经过一个小例子来引出哈夫曼树,例:将学生的百分制成绩转换为五分制成绩:≥90 分: A,80~89分: B,70~79分: C,60~69分: D,<60分: E。bash
if (a < 60){
b = "E";
}
else if (a < 70) {
b = "D";
}
else if (a<80) {
b = "C";
}
else if (a<90){
b = "B";
}
else {
b = "A";
}
复制代码
若考虑上述程序所耗费的时间,就会发现该程序的缺陷。在实际中,学生成绩在五个等级上的分布是不均匀的。当学生百分制成绩的录入量很大时,上述断定过程须要反复调用,
此时程序的执行效率将成为一个严重问题。编码
上述判断方式对应的判别树以下:spa
所以 10000 个数据比较的 次数为: 10000 (5%+2×15%+3×40%+4×40%)=31500次
设计
再看另外一种判断方式:3d
10000 (3×20%+2×80%)=22000次
显然:两种判别树的效率是不同的。code
哈夫曼树定义:在权为w1,w2,…,wn的n个叶子结点的全部二叉树中,带权路径长度WPL最小的二叉树称为赫夫曼树或最优二叉树。cdn
带权路径长度的最优值叫作WPL也就是上述例子的判断总次数31500次或者22000次 blog
构造规则:string
例:有4 个结点 a, b, c, d,权值分别为 7, 5, 2, 4,构造哈夫曼树。it
根据给定的n个权值{w1,w2,…,wn}构成二叉树集合F={T1,T2,…,Tn}
哈夫曼树的应用很广,哈夫曼编码就是应用之一。
例:若是需传送的电文为 ‘ABACCDA’,它只用到四种字符,用两位二进制编码即可分辨。假设 A, B, C, D 的编码分别为 00, 01,10, 11,则上述电文便为 ‘00010010101100’(共 14 位),译码员按两位进行分组译码,即可恢复原来的电文。 这种编码的特色是译码简单且具备惟一性,但编码长度并非最短的。
在传送电文时,为了使其二进制位数尽量地少,能够将每一个字符的编码设计为不等长的,使用频度较高的字符分配一个相对比较短的编码,使用频度较低的字符分配一个比较长的编码。例如,能够为A,B,C,D四个字符分别分配0,00,1,01,并可将上述电文用二进制序列:000011010发送,其长度只有9个二进制位,但随之带来了一个问题,接收方接到这段电文后没法进行译码,由于没法判定前面4个0是4个A,1个B、2个A,仍是2个B,即译码不惟一,所以这种编码方法不可以使用。
所以,为了设计长短不等的编码,以便减小电文的总长,还必须考虑编码的惟一性,即在创建不等长编码时必须使任何一个字符的编码都不是另外一个字符的前缀,这宗编码称为前缀编码(prefix code)利用哈夫曼树来实现
以电文中的字符做为叶子结点构造二叉树。而后将二叉树中结点引向其左孩子的分支标 ‘0’,引向其右孩子的分支标 ‘1’
; 每一个字符的编码即为从根到每一个叶子的路径上获得的 0, 1 序列。如此获得的即为二进制前缀编码。
任意一个叶子结点都不可能在其它叶子结点的路径中。
好比有ABCDEF六个字母,经过0和1编码用二进制字符发送。普通编码后的数据为000001010011100101
,解码的时候能够按照3位一份来解码。 假设ABCDEF出现的几率分别为27%、8%、15%、15%、30%、5%。则造成的赫夫曼树以下图。此外咱们能够将左右分支分别改成0和1,而后用0和1来编码字母。
A=0一、B=100一、C=10一、D=00、E=十一、F=1000。
本来的编码结果为:000001010011100101
如今的编码结果为: 0110011010011100
复制代码
如今的编码结果明显要比以前的少了一些,短短是几个字母编码后,少的量不是很大,若是是通篇的文章或更多,那么编码量将会节省不少,这就是文件压缩的原理。而且随着字符的增多,按照权重优先级编码,这种压缩会进一步提高不少。