贪心算法-03哈夫曼编码问题
哈夫曼编码
- 简介
- 哈夫曼编码是一种字符编码方式,可以对指定的字符集进行数据压缩,压缩率在20%到90%。
- 问题描述
- 现在有一个包含5个字符{A,B,C,D,E},各个字符的出现频率依次为{0.35, 0.1, 0.2, 0.2, 0.15}。需要构造一种有效的编码类型,使用该编码表达以上字符表时可以产生平均长度最短的位串。
- 问题分析
- n个字符组成的文本编码时有两种方式,定长编码(为每个字符赋予一个长度固定为m,m>=log_2^n的位串,ASCII码就是如此的)和变长编码(长度各异的编码,其中出现频率高的采用较短的编码表示,摩斯电吗就是如此做的)。通常,为了提高效率一般使用定长编码,但是定长编码会遇到一个问题,就是前缀码问题。所谓前缀码,就是对任意字符使用01串表示其,并且任何一个字符的编码不是其他字符的前缀。有了前缀码,就可以在位串中准确定位字符,快速替换文本了。
- 哈夫曼提出来这种编码策略,称为哈夫曼编码。其核心就是利用二叉树这种数据结构。(前缀码是简单路径的节点值得来的,是通过从一个叶子节点到另一个叶子节点的简单路径不存在来保证的。
- 这样的二叉树称为哈夫曼树,算法如下。
- 初始化n个单节点的树,并标上字母表中字符。把每个字符的频率记录在对应的根节点中,用来标记树的权重,即树的权重为所有节点的概率和。
- 重复下面的步骤,直到只剩下一棵单独的树。找到两课权重最小的树,若权重相同,任选其中一个,分别把它们作为新二叉树的左右子树,并将其权重之和作为新的权重记录根节点中。
- 这样的树就是哈夫曼树,获得树后依据左分支为0,右分支为1,可以得到编码。
- 对题目的例子,哈夫曼编码节约了25%的存储空间。
- 对贪心选择性质和最优子结构性质理解不难,这里不做证明了。
- 代码
# -*-coding:utf-8-*-class Node(object):def __init__(self, freq):self.left = Noneself.right = Noneself.father = Noneself.freq = freqdef is_left(self):return self.father.left == selfdef __str__(self):return str(self.freq)def create_nodes(freqs):"""创建叶子节点:param freqs::return:"""return [Node(freq) for freq in freqs]def create_huffman_tree(nodes):queue = nodes[:]while len(queue) > 1:queue.sort(key=lambda item: item.freq)node_left = queue.pop(0)node_right = queue.pop(0)node_father = Node(node_left.freq+node_right.freq)node_father.left = node_leftnode_father.right = node_rightnode_left.father = node_fathernode_right.father = node_fatherqueue.append(node_father)queue[0].father = Nonereturn queue[0]def huffman_encoding(nodes, root):codes = [''] * len(nodes)for i in range(len(nodes)):node_tmp = nodes[i]while node_tmp != root:if node_tmp.is_left():codes[i] = '0' + codes[i]else:codes[i] = '1' + codes[i]node_tmp = node_tmp.fatherreturn codesif __name__ == '__main__':chars_freq = [('A', 35), ('B', 10), ('C', 20), ('D', 20), ('E', 15)]nodes = create_nodes([item[1] for item in chars_freq])root = create_huffman_tree(nodes)codes = huffman_encoding(nodes, root)for item in zip(chars_freq, codes):print('Char:{}freq:{}encoding:{}'.format(item[0][0], item[0][1], item[1]))
- 运行结果
- 补充说明
- 具体代码可以查看我的Github,欢迎Star或者Fork
- 参考书《你也能看得懂的Python算法书》
贪心算法-03哈夫曼编码问题相关推荐
- 贪心算法2——哈夫曼编码
[构造哈夫曼树] 假设有n个叶子结点,对应的权值分别是w1.w2.....,wn则哈夫曼树的构造如下: (1)将w1,w2,....wn看成是有n课树的森林(每棵树仅有一个结点). (2)在森林中选出 ...
- 算法导论——贪心算法:哈夫曼编码(霍夫曼编码)
2019独角兽企业重金招聘Python工程师标准>>> package org.loda.greedy;import org.junit.Test; import org.loda. ...
- 霍夫曼算法_霍夫曼编码算法
霍夫曼算法 In this tutorial, we'll be discussing and implementing the Huffman Coding Algorithm in Java. 在 ...
- 哈夫曼算法证明+哈夫曼编码译码程序实现
哈夫曼算法证明 哈夫曼算法是一种贪心算法,我们考虑证明其最优子结构和贪心选择性质: 最优子结构:假设一个树是哈夫曼树,则以其任意节点为根节点的最大子树也是哈夫曼树. 证明:子树的根节点的值是其所有叶子 ...
- 数据结构与算法之霍夫曼编码解码实现
目标:将字符串"can you can a can as a can canner can a can."编码再解码 流程: 将字符串转成bytes (byte[]格式)(eg.[ ...
- 18.C#写算法之“哈夫曼编码” 是什么鬼?
文章参考自:程序员小灰:漫画:"哈夫曼编码" 是什么鬼? 哈夫曼编码是一种高效的编码方式,在信息存储和传输过程中,用于对信息进行压缩. 计算机系统是如何存储信息的呢? 计算机不是人 ...
- 哈夫曼编码压缩率计算_程序员的算法课(8)-贪心算法:理解霍夫曼编码
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/m0_37609579/article/ ...
- 贪心算法之用优先队列(priority_queue)实现哈夫曼编码问题
1.问题 参考我的博客:贪心算法之哈夫曼编码问题 2.优先队列知识复习 参考我的博客: C++之STL之priority_queue 3.代码实现 #include <iostream> ...
- 程序员的算法课(8)-贪心算法:理解霍夫曼编码
一.一种很贪婪的算法定义 贪心是人类自带的能力,贪心算法是在贪心决策上进行统筹规划的统称. [百度百科]贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择.也就是说,不从整体 ...
最新文章
- Windows Phone 7 中的页面和弹出框
- Java基础语法 第2节 Java语言基本语法
- 三极管共射、共集、共基分析及比较
- 使用VS2005进行负载测试
- Centos7.3 格式化和挂载数据盘
- python画折线图-利用python画折线图
- mysql的储存原理_mysql储存原理
- 五、梯度分析与最优化
- Scala基本类型及操作、程序控制结构
- 后台管理软件测试用例,如何进行测试用例管理?
- 攻防视角下的信息收集
- 基于在线学习行为的评价模型的设计与实现
- 飞腾CPU体系结构(八)
- uniapp 微信小程序登录方法封装
- CodeBlocks 主题美化(编辑器修改主题)
- 产品经理工作是什么,你知道了?
- 微信小程序|使用小程序制作一个足球拼图小游戏
- Cocos Creator Layout组件
- Python中and和or的运算规则,短路计算
- Django Vue渲染动态数据(七)