您的位置:首页 > 其它

Huffman树的建立、字符界面下的显示及序列化(一)

2016-03-09 23:15 260 查看
本文主要是Clifford A. Shaffer所著的《Data Structures and Algorithm Analysis in C++》一书中项目设计习题5.7的实现。
Huffman树是一种可以用来压缩文件的技术。为在计算机上存取文件,需要为文件中的每个字符分配一个编码,一般情况下,每个字符的编码长度相同。例如,每个ASCII字符的编码长度为8位。那么,保存一个有着1000个字符的文件需要8*1000=8000位,也就是1000个字节。但是,在英语的使用中,每个字符的出现频率是不相同的,而且差别很大。如果能够为出现频率高的字符分配较短的编码,而出现频率高的字符分配较长的编码,则存储文件所需的空间有可能会减少。
本文首先简单描述了什么是Huffman树;然后给出了从文件中统计每个字符出现频率,并把其转换为Huffman树的算法及实现;接下来实现了在字符界面输出Huffman树的算法,该算法也可以应用于其它类型的二叉树;然后是序列化保存Huffman树的工作。

Huffman树概述

满二叉树:二叉树中的每个结点,要么是叶结点,要么有两个子结点。也就是说,不存在只有一个子结点的结点。

加权路径长度:叶结点的加权路径长度定义为该结点的权重乘以其深度。
Huffman树是一个由给定的带权重结点的所组成的一颗满二叉树,所有叶结点的加权路径长度最小。
可以把每个英文字母作为一个叶结点,出现频率就是其权值,结点的深度与权重的乘积就是加权路径长度。图1是英语句子”Hello,World!“中出现的字母所组成的Huffman树。该图是笔者所编写的程序在字符界面下输出的Huffman树。树中的叶结点的内容(ASCII字符)及其对应的权值(weight)以冒号隔开;内部结点没有具体的字符与之对应,所以用”*“表示其内容,其权值是其子结点权值的和。在这个二叉树中,叶结点的权值被设置为其出现的次数。从图中可知”r”和”d”各出现1次;”l”出现3次;”H”、”!”、”,”、”e”和”W”分别出现一次。”10“是换行符的ASCII码,出现一次。图中深度为0的结点就是根结点,其权值为13,该结点有两个子结点,权值分别为5和8。权值为5的结点有两个子结点,一个是权值为2内部结点,另一个是权值为3的l结点。依此类推。
为满足”所有叶结点的加权路径长度最小“的要求,Huffman树中,权值大的,也就是出现频率高的,应该具有较小的深度。图1就满足此条件,例如出现次数最多的字符”l“的深度为2,是所有叶结点中最小的。图2是一段摘自wikipedia网站Huffman词条的第一段话以及对应的Huffman树。图中a和e的出现频率最高,为13,基本符合英文字母的统计规律,它们的深度为4。



图1 Huffman树示例



图2 较大Huffman树示例

Huffman编码是从Huffman树中,为每个字符推导出一个编码,用编码来代表字符,从而实现压缩的功能。推导编码的过程如下:从根结点出发,沿着满二叉树,寻找一条到达字符的路径。当经过左子树(假设在图中是上面的分支)的时候,对应编码0,经过右子树(假设在图中是下面的分支)的时候,对应编码1。从根结点到达字符的编码序列就是该字符所对应的Huffman编码。例如在图1中,r的编码为000,而l的编码为01。出现次数多的l具有较短的编码,从而可以实现文本的压缩功能。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息