Huffman Code是应用很广泛的一种文本压缩编码方式。它的原理就是用不等长的编码来表示不同出现频率的字符。出现频率高的字符,就用比较短的编码来表示,出现频率低的,就是较长的编码来表示。如下表:
图中是一个文件中出现的字符(abcdeft)以及相应的出现频率。如果使用等长编码方式,则每个字符都要用三位来表示,总的长度就是300个bit,如果用变长码来表示,则总长度为224个bit。(对于出现频率最高的a,我们就用一个0来表示它,这样,可以节省很多空间)。Huffman编码的压缩比通常都在20%-90%。
Huffman编码是一种前缀编码方式,所谓前缀编码,即,在编码集合中,没有任何一个编码是另一个编码的前缀。例如,用0来表示a, 用10表示b,那么a的编码就不是b的编码的前缀部分。(其实把这种编码叫"前缀编码"实在是别扭,意思刚好相反了。不过《算法导论》一书也提出这种说法,"前缀编码"已经是一个通用的叫法了,所以只好一直沿用下去)
一个字符集合的最优压缩编码方案总是可以用前缀编码表示出来。前缀编码最大的好处就是没有二义性,当我们顺序读取编码文件时,只要有编码与字符匹配,就可以直接把读出来的数据翻译成相应的字符,然后再继续后面的解码。因为前缀编码决定了一个已经匹配的编码,决不可能是另一个编码的一部分,所以可以直接确定对应的字符是什么。
使用Huffman编码的时候,一般要生成对应文本的编码集合(Huffman树),然后再将文本的每个字符相应都转成压缩码。解码时也要依赖于对应的Huffman树,Huffman树是满二叉树(即除了叶节点之外,内部节点都有两个子节点)。如上面图中的字符以及出现频率来讲,其中的一种Huffman树可能如下图所示:
在解码时,先获取相应的压缩码,然后每次取一位,从树部开始查找,如果取出的位是0,就向左子节点移动,如果取出的位是1,则向右子节点移动,然后再取下一位,一直到叶节点为止。每个叶节点都是一个相应的字符。由于Huffman编码是前缀编码,所以到达叶节点时可以确定对应这个压缩码的字符就是当前所在的叶节点了。然后再取后面的压缩码,继续前面过程,最终就可以将整个文件都解码出来。
Huffman树的构造:
Huffman树的构造可以采用贪婪算法。用贪婪算法解决的问题,一般要满足两个条件:
Huffman树构造问题对应的,有这样的性质(这里只阐述性质,并不进行证明了,具体的证明可以参考《算法导论》16.3节,比较详细了):
- 1. 对于一字符的集合所构造的Huffman树中,频率最低的两个字符对应的节点x和y,是最优树从节点开始的最大路径长度,且x和y或为子节点。这也就意味着,频率最低的两个字符对应的编码是等长的(在压缩编码中也是最长的),而且它们之间只有最后一个bit是不同的。这一性质,表明Huffman树构造问题,是存在贪婪选择性质的。
- 2. 对于一个字符集C,c是C中的元素,f[c]表示字符c的出现频率。x和y是字符集C中最低频率的两个字符。如果将x和y节点去掉,换一个新节点z,且使得f[z] = f[x] + f[y],并令,字符集C'表示这样的集合{c,c属于C-{x,y}+z}。用树T'对应字符集C'的最优编码树。那么,将T'的叶节点z去掉,并将一个包含x、y为子节点的新内节点放在z的位置,那么,得到的树T就是字符集C的一棵最优编码树。这一性质表示Huffman构造问题也存在最优子结构。
这样,Huffman树的构造问题就可以用贪婪算法来解决了。附件中是相应的代码。对于本文开头图中提到的例子,构造过程将如下图所示:
代码如下:
# 仅仅模拟了最小优先级队列的功能,并未用最小堆来实作
class MinPriorityQ:
def __init__(self):
self.heaplist = []
def Dequeue(self):
minObj = self.heaplist[0]
idxMin = 0
for o in self.heaplist:
if o.comFun(minObj) < 0:
minObj = o
idxMin = self.heaplist.index(o)
del self.heaplist[idxMin]
return minObj
def Insert(self, objectIn):
self.heaplist.append(objectIn)
def Empty(self):
return len(self.heaplist) == 0
# Huffman树上的每个节点
class HuffmanTreeNode:
def __init__(self, freq, char):
self.key = freq # 存储字符的频率
self.char = char # 存储字符本身
self.left = 0 # 左子节点
self.right = 0 # 右子节点
def comFun(self, OtherNode): # 比如树节点,是以字符出现的频率为key来进行的
if self.key > OtherNode.key:
return 1
elif self.key == OtherNode.key:
return 0
else:
return -1
# 生成一树Huffman树。
def MakeHuffmanTree(charList, freList):
num = len(charList)
minQ = MinPriorityQ()
# 将所有字符以及出现频率生成相应的树节点,插入到以频率为key的
# 最小优先级队列中去
for i in range(0, num):
node = HuffmanTreeNode(freList[i], charList[i])
minQ.Insert(node)
for i in range(0, num - 1):
# 最出优先级最低的两个节点
x = minQ.Dequeue()
y = minQ.Dequeue()
# 用取出的两个节点的频率和作为新节点的频率
z = HuffmanTreeNode(x.key + y.key, 0)
# 取出的两个节点作为新节点的左右子节点
z.left = x
z.right = y
minQ.Insert(z) # 将新节点插入到队列中
return minQ.Dequeue()
#-----------------------------------------------
# 以下程序仅用于测试
def PrintHuffmanTree(ht):
code = []
Traval(code, ht)
def Traval(code, root, dir='3'):
if not dir == '3':
code.append(dir)
if not root.char == 0:
print root.char, " : ", "".join(code)
else:
Traval(code, root.left, '0')
code.pop()
Traval(code, root.right, '1')
code.pop()
if __name__ == '__main__':
charList = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
freqList = [ 2, 5, 9, 3, 40, 6, 10 ]
TreeTop = MakeHuffmanTree(charList, freqList)
PrintHuffmanTree(TreeTop)
分享到:
相关推荐
中文名: 算法导论 原名: Introduction to Algorithms 作者: Thomas H. Cormen Ronald L. Rivest Charles E. Leiserson Clifford Stein 资源格式: PDF 版本: 文字版 出版社: The MIT Press书号: 978-0262033848发行...
【数据结构与算法】-哈夫曼树(Huffman Tree)与哈夫曼编码
分享MATLAB霍夫曼Huffman编码译码GUI界面设计源程序代码-MATLAB霍夫曼Huffman编码译码GUI界面设计 源程序代码.rar 实现霍夫曼的编码和解码,GUI界面设计,供参考
C语言开发----链表HuffmanTree
霍夫曼huffman_psk_fsk matlab源码 个人作业 PCM编码 霍夫曼huffman_psk_fsk matlab源码 个人作业 PCM编码 霍夫曼huffman_psk_fsk matlab源码 个人作业 PCM编码 霍夫曼huffman_psk_fsk matlab源码 个人作业 PCM编码 ...
MATLAB霍夫曼Huffman编码译码GUI界面设计 源程序代码.rarMATLAB霍夫曼Huffman编码译码GUI界面设计 源程序代码.rarMATLAB霍夫曼Huffman编码译码GUI界面设计 源程序代码.rarMATLAB霍夫曼Huffman编码译码GUI界面设计 源...
北京工业大学--算法作业3--huffman编码对文本文件进行压缩与解压---... 输入:一个文本文件 输出:压缩后的文件 算法过程: (1)统计文本文件中每个字符的使用频度 (2)构造huffman编码 (3)以二进制流形式压缩文件
PCM编码_霍夫曼huffman_psk_fsk_matlab源码实现.7zPCM编码_霍夫曼huffman_psk_fsk_matlab源码实现.7zPCM编码_霍夫曼huffman_psk_fsk_matlab源码实现.7zPCM编码_霍夫曼huffman_psk_fsk_matlab源码实现.7z
霍夫曼(Huffman)和Run Length压缩编码,示例使用程序里面给了压缩比,感觉用处不大,因为压缩比不高
算法导论,英文 【本书目录】 I Foundations Introduction 3 l The Role of Algorithms in Computing 5 l.l Algorithms 5 l.2 Algorithms as a technology 10 2 Getting Started I5 2.l Insertion sort 15 2.2 ...
matlab_基于DPCM和huffman编解码的图像压缩重构算法matlab仿真_源码
非常适合大学数据结构课上使用。强烈推荐!~
编码算法,在构造haffman树的过程中,使用一个辅助数组记录haffman树中的每个结点的左孩子、右孩子、双亲在数组中的下标,编码时从叶子结点开始往上直到根结点,左子树为0,右子树为1。数组中元素的存放顺序先写入每...
MATLAB霍夫曼Huffman编码译码GUI界面设计 源程序代码.zip实际问题建模MATLAB源程序代码下载MATLAB霍夫曼Huffman编码译码GUI界面设计 源程序代码.zip实际问题建模MATLAB源程序代码下载MATLAB霍夫曼Huffman编码译码GUI...
自己实现huffman树的代码,分享出来
hufferman的算法,构造huffman树二叉排序树,c语言
matlab算法源码MATLAB霍夫曼Huffman编码译码GUI界面设计源程序代码提取方式是百度网盘分享地址
1、了解该树的应用实例,熟悉掌握 Huffman 树的构造方法及 Huffman 编码的应用, 2、了解 Huffman 树在通信、编码领域的应用过程 1、输入
实验三、Huffman编码(二叉树) 实验目的:熟练掌握二叉树应用(Huffman编码)的基本算法实现。... 构造Huffman树的函数 Huffman编码的函数 建立正文的编码文件的函数 代码文件的译码函数 主函数
对一段 英文 文本先统计每个字符所出现的概率,再根据频率构造Huffman 树,由此产生每个字符所对应的前缀码,写入另外一个文本文件,再通过扫描前缀码来解码