二叉树应用——最优二叉树(Huffman树)、贪心算法—— Huffman编码

news2025/2/25 2:12:08

1、外部带权外部路径长度、Huffman树

在这里插入图片描述
从图中可以看出,深度越浅的叶子结点权重越大,深度越深的叶子结点权重越小的话,得出的带权外部路径长度越小。
Huffman树就是使得外部带权路径最小的二叉树

2、如何构造Huffman树

(1)步骤

(1)根据给定的n个权值{W1,W2,…,Wn},构造n棵二叉树的集合F={T1,T2,…,Tn},其中每棵二叉树中均只含有一个带权值为Wi的根结点,其左右子树为空树
(2)在F中选取其根结点的权值为最小的两棵二叉树,分别作为左、右子树构造一棵新的二叉树,并置这棵新的二叉树根结点的权值为其左、右子树根结点的权值之和;
(3)从F中删去这两棵树,同时加入刚生成的新树;
(4)重复(2)和(3)两步,直至F中只含一棵树为止

以上图的结点为例:
在这里插入图片描述

(2)代码

在这里插入图片描述

用bfs广度优先搜索遍历这个二叉树来检验
在这里插入图片描述

(3)代码注意点

在这里插入图片描述

2、ASCII码

在ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)编码中,每个大写或小写英文字母都被赋予一个唯一的数字值。这些值都是7位的二进制数,但在实际存储和传输时,它们通常会被填充为一个字节(8位),最高位(第8位)设置为0。

对于小写字母 ‘a’,其ASCII码值是97(十进制)。在二进制表示中,它是 01100001。

同理,大写字母 ‘A’ 的ASCII码值是65(十进制),二进制表示为 01000001。

请注意,ASCII码只包含128个字符,包括大小写英文字母、数字、标点符号和一些控制字符。如果需要表示更多的字符,比如各种语言的文字符号,就需要使用扩展的字符编码,如ISO 8859系列、Unicode等。

3、Huffman编码

哈夫曼编码,它是一种可变长编码方式,根据字符出现频率来构造异字头的平均长度最短的码字,是数据压缩算法中的一种。哈夫曼编码是贪婪算法的应用之一。哈夫曼树又称最优二叉树,带权路径长度最短的二叉树。所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的路径长度(若根结点为0层,叶结点到根结点的路径长度为叶结点的层数)。树的带权路径长度记为WPL=(W1L1+W2L2+W3L3+…+WnLn),N个权值Wi(i=1,2,…n)构成一棵有N个叶结点的二叉树,相应的叶结点的路径长度为Li(i=1,2,…n)。可以证明哈夫曼树是WPL最小的二叉树,故有时也称哈夫曼编码为最优前缀码。

(1)Huffman编码对比其他编码方式的优势

这里先给出一个字符串:"this is isinglass’’
其中共有15个字符。

假如用ASCII码编码,ASCII编码每个字符用7个二进制数,但在存储时会被填充成一个字节,即8位,因此占位:15*8=120
在ASCII码的基础上进行改进,每个字符用3位表示,占位:15*3=45
我们再来看一下Huffman编码

文字部分可以打开图片直接对照,也可以先看文字解释
在这里插入图片描述

在这里插入图片描述
经过上述对比可以很明显看出Huffman编码的好处

(2)Huffman编码具有前缀特性

思考:为什么不给频率最高的字母s和i以最短的编号,如分别是0、1,然后剩余编号:00,01,10,11,000,001?这样不就能最大程度节省空间了吗?
其实这样是不正确的 。
首先,我们需要理解Huffman编码的目标:它是为了创建一种前缀编码(prefix code),在这种编码中,任何字符的编码都不是其他字符编码的前缀。这意味着编码字符串可以无歧义地解码回原始字符序列。如果我们简单地给频率最高的字母分配最短的编码(如0或1),那么很可能会有多个字符的编码成为其他字符编码的前缀,从而违反了前缀编码的原则。(解码时会出现二异性)

其次,Huffman编码追求的是整体编码长度的最小化,而不仅仅是单个字符编码长度的最小化。通过将频率最低的字符分配最长的编码,而频率最高的字符分配最短的编码,Huffman编码确保了整体编码长度最短。这是基于信息论中的最优编码理论,即使用最少的位数来表示最可能出现的事件。

Huffman树的前缀特性是由其构建过程自然产生的。Huffman树的构建过程确保了每个字符的编码都是唯一的,并且没有一个是另一个的前缀。这是因为Huffman树是一个二叉树,每个字符都是树的一个叶子节点,从根节点到该叶子节点的路径决定了该字符的编码。由于树的结构保证了从根到每个叶子节点的路径是唯一的,因此每个字符的编码也是唯一的,并且没有前缀冲突。

最后,虽然将频率最高的字母的编码设置为0和1可能在某些情况下看似节省空间,但这并不适用于所有情况。Huffman编码是一种通用的、自适应的编码方法,它根据字符的实际频率分布来构建编码,从而在各种不同的情况下都能达到较好的压缩效果。而简单地给某个字符分配固定的短编码可能会在某些特定情况下导致较差的压缩性能。

综上所述,Huffman编码不直接将频率最高的字母的编码设置为0和1,而是基于Huffman树来构建前缀编码系统,这是为了确保编码的唯一性和无前缀冲突,同时追求整体编码长度的最小化。Huffman树的前缀特性是由其构建过程自然产生的,保证了每个字符的编码都是唯一的。

(2)代码实现

在这里插入图片描述

代码拆分理解构

1、构建最优二叉树:

在这里插入图片描述

2、编码函数

在这里插入图片描述

3、解码函数

在这里插入图片描述

4、实例使用

在这里插入图片描述

import heapq
from collections import defaultdict, Counter

# 辅助函数:构建Huffman树
def build_huffman_tree(freq_dict):
    heap = [[weight, [char, ""]] for char, weight in freq_dict.items()]
    heapq.heapify(heap)
    while len(heap) > 1:
        lo = heapq.heappop(heap)
        hi = heapq.heappop(heap)
        for pair in lo[1:]:
            pair[1] = '0' + pair[1]
        for pair in hi[1:]:
            pair[1] = '1' + pair[1]
        heapq.heappush(heap, [lo[0] + hi[0]] + lo[1:] + hi[1:])
    return heap[0][1:]#打印char编码:[['r', '00'], ['t', '010'], ['y', '011'], ['u', '10'], ['o', '11']]

# 编码函数
def huffman_encode(s):
    freq_dict = Counter(s)#Counter({'o': 5, 'u': 4, 'r': 3, 'y': 2, 't': 1})
    huff_tree = build_huffman_tree(freq_dict)#[['r', '00'], ['t', '010'], ['y', '011'], ['u', '10'], ['o', '11']]
    huff_dict = {pair[1]: pair[0] for pair in huff_tree}#huff_dict={'00':'r','010':'t','011':'y','10':'u','11':'o'}
    huff_dict1 = {pair[0]: pair[1] for pair in huff_tree}#huff_dict1={'r': '00', 't': '010', 'y': '011', 'u': '10', 'o': '11'}
    encoded_str = ' '.join(huff_dict1[char] for char in s)#encoded_str='00 010 11 011 00 10 11 10 011 10 00 11 10 11 11'
    return encoded_str, huff_dict

# 解码函数
def huffman_decode(encoded_str, huff_dict):
    a=encoded_str.split()#['00', '010', '11', '011', '00', '10', '11', '10', '011', '10', '00', '11', '10', '11', '11']
    decoded_str = ""
    current_dict = huff_dict#huff_dict={'00':'r','010':'t','011':'y','10':'u','11':'o'}
    for bit in a:
        l = current_dict[bit]#l='r'
        if isinstance(l, str):#如果l是str类型就放进encoded_str里
            decoded_str += l
    return decoded_str

# 示例使用
s = "this is an example for huffman encoding"
encoded_str, huff_dict = huffman_encode(s)
print(f"Encoded string: {encoded_str}")
print(f"Huffman dictionary: {huff_dict}")

decoded_str = huffman_decode(encoded_str, huff_dict)
print(f"Decoded string: {decoded_str}")

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1585818.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

InternlM2

第一次作业 基础作业 进阶作业 1. hugging face下载 2. 部署 首先,从github上git clone仓库 https://github.com/InternLM/InternLM-XComposer.git然后里面的指引安装环境

鸿蒙4.2开放升级,首批公测包含24款机型,快来升级尝鲜

在今天下午刚刚结束的鸿蒙生态春季沟通会上,余承东提到了一个关于鸿蒙系统的细节,那就是目前top5000的App里,已经有4000多款App确定加入。 如此量级,预测基本能够覆盖常用的应用了,此前担心的应用生态问题也得到解决&a…

Harmony鸿蒙南向驱动开发-I3C接口使用

功能简介 I3C(Improved Inter Integrated Circuit)总线是由MIPI Alliance开发的一种简单、低成本的双向二线制同步串行总线。 I3C是两线双向串行总线,针对多个传感器从设备进行了优化,并且一次只能由一个I3C主设备控制。相比于I…

[计算机效率] 鼠标手势工具:WGestures(解放键盘的超级效率工具)

3.22 鼠标手势工具:WGestures 通过设置各种鼠标手势和操作进行绑定。当用户通过鼠标绘制出特定的鼠标手势后就会触发已经设置好的操作。有点像浏览器中的鼠标手势,通过鼠标手势操纵浏览器做一些特定的动作。这是一款强大的鼠标手势工具,可以…

Unity 布局 HorizontalLayoutGroup 多行 换行

演示Gif: 现象: 子元素宽度不同,超出父元素后不会换行 GridLayout则是固定宽度也不能用, 需求 水平排版的同时,超出父级后换行 代码: 催更就展示[狗头]

李廉洋;4.11#黄金,WTI原油#行情走势分析策略。

美国银行预计,在今天召开的欧洲央行会议上不会有重大的政策变化,但欧洲央行正逐渐接近开始降息,尽管它采取的是一种谨慎的、依赖数据的方式。虽然欧洲央行对降息轨迹的信心不断增强,但降息的具体速度和幅度仍未公布,而…

第06章 网络传输介质

6.1 本章目标 了解双绞线分类和特性了解同轴电缆分类和特性了解光纤分类和特性了解无线传输介质分类和特性 6.2 传输介质分类 现在社会还是以有线介质为主 计算机通信 - 有线通信 - 无线通信有线通信传输介质 - 双绞线 - 同轴电缆 - 光导纤维无线通信 - 卫星 - 微波 - 红外…

SpringBoot 整合RocketMQ

目录 一、引入依赖 二、配置文件 三、生产者 四、消费者 五、结果 一、引入依赖 <dependency><groupId>org.apache.rocketmq</groupId><artifactId>rocketmq-spring-boot-starter</artifactId><version>2.2.0</version> </d…

Linux网络名称空间的调试方法全面分析

Linux网络名称空间是一种广泛使用的技术&#xff0c;用于隔离网络环境&#xff0c;特别是在容器化和微服务架构中&#x1f4e6;。然而&#xff0c;随着网络名称空间的广泛应用&#xff0c;开发者和系统管理员可能会遇到需要调试网络名称空间配置和性能的情况&#x1f50d;。本文…

Splitpanes拆分窗格插件使用

项目开发中用到了拆分窗格(就是下面的效果&#xff0c;可以拆分网页&#xff0c;我们项目通常都是用左右两块拆分&#xff0c;可以通过拖动图标进行左右拖动)&#xff0c;于是就发现了一个很好用的插件&#xff1a;Splitpanes 官网地址&#xff1a;Splitpanes (antoniandre.git…

ONERugged车载平板电脑厂家丨工业车载电脑优势体现丨3年质保

作为现代社会中必不可少的出行工具&#xff0c;汽车不仅仅是代步工具&#xff0c;更是我们生活中的重要一部分。而在如此多功能的汽车内&#xff0c;一款高可靠性、适应不同行业应用的车载平板电脑成为了当下的热门选择。ONERugged车载平板电脑以其卓越的品质和强大的功能而备受…

FMix: Enhancing Mixed Sample Data Augmentation 论文阅读

1 Abstract 近年来&#xff0c;混合样本数据增强&#xff08;Mixed Sample Data Augmentation&#xff0c;MSDA&#xff09;受到了越来越多的关注&#xff0c;出现了许多成功的变体&#xff0c;例如MixUp和CutMix。通过研究VAE在原始数据和增强数据上学习到的函数之间的互信息…

【力扣】125.验证回文串

刷题&#xff0c;过了真的好有成就感&#xff01;&#xff01;&#xff01; 题解&#xff1a; 根据题目要求&#xff0c;我们需要处理一下几个问题&#xff1a; 将大写字母转变成小写对原来的字符串进行处理&#xff0c;只要字母和数字考虑只有一个和字符串为空的情况 1、将…

Nginx 基础应用实战 06 构建一个PHP的站点

Nginx 基础应用实战 06 构建一个PHP的站点 使用套件 lmnp https://oneinstack.com 安装完成后 搭建bbs https://www.discuz.net/ 搭建博客 https://wordpress.com https://cn.wordpress.org/ CMS系统 http://www.dedecms.com/ 构建Lua站点 Openresty Nginx Lua …

lomobok源码编译学习笔记(1)

lomobok学习笔记&#xff08;1&#xff09; 项目导入 lombok的github地址 GitHub - projectlombok/lombok: Very spicy additions to the Java programming language. 开发工具 idea不知道为啥&#xff0c;装上ant工具也不好用&#xff0c;eclipse默认自带有ant,不需要装。…

0 idea搭建springboot项目

1 2 3 4 5 配置文件 application.yaml server:servlet:context-path: /app #项目名controller //注入到spring容器 Controller public class HelloController {GetMapping("hello")ResponseBodypublic String hello(){return "Hello,SpringBoot";} }启…

多态——C++

这里写目录标题 衔接继承总结继承和组合白箱复用黑箱复用 多态的概念多态的定义以及实现虚函数重写的两个例外协变面试题析构函数的重写 finalvoerride重载隐藏(重定义)重写(覆盖)抽象类什么是抽象类&#xff1f; 实现继承和接口继承多态的原理虚函数表 那多态的调用是怎么实现…

我为什么选择当程序员

在当今这个数字化时代&#xff0c;程序员已经成为了一个非常受欢迎的职业选择。无论是出于对技术的热爱&#xff0c;还是因为看到了这个行业的广阔前景&#xff0c;越来越多的人选择加入程序员的行列&#xff0c;尤其是最近几年AI带动整体行业的发展。本文将深入探讨人们选择成…

giteegit的连结使用

目标&#xff1a;在windows的本地的git上操作的项目存放到Gitee云端上 不适用于linux的terminal终端下 1.先下载好Git这个软件 2.创建一个文件夹&#xff08;项目名称&#xff09; 然后用gitbash的形式打开 3.创建ssh密钥到Gitee上 因为我们在Git与Gitee上的传输是通过ssh…

用友NC open SQL注入漏洞复现(XVE-2023-29119)

0x01 产品简介 用友NC是由用友公司开发的一套面向大型企业和集团型企业的管理软件产品系列。这一系列产品基于全球最新的互联网技术、云计算技术和移动应用技术,旨在帮助企业创新管理模式、引领商业变革。 0x02 漏洞概述 用友NC /portal/pt/PaWfm/open接口的proDefPK参数存…