数据结构 —— 哈夫曼树

数据结构 —— 哈夫曼树

  • 哈夫曼树
      • 定义
      • 构造算法
      • 特性
      • 应用
  • 哈夫曼编码
      • 核心概念
      • 工作原理
      • 特点

我们今天来看哈夫曼树

哈夫曼树

哈夫曼树(Huffman Tree),是一种特殊的二叉树,由D.A. Huffman在1952年提出,主要用于数据压缩,特别是哈夫曼编码(Huffman Coding)中。以下是关于哈夫曼树的全面概念:

定义

哈夫曼树是一种带权路径长度最短的二叉树,也称为最优二叉树。它是在给定一组具有不同权重的叶子节点(通常代表数据中的符号或字符)的情况下,通过特定的构建算法得到的。该树的特点是,所有叶子节点位于最底层或倒数第二层,且没有度为1的节点(除了根节点可能外),同时保证了从根节点到任何叶子节点的路径上的权值之和(即带权路径长度)最小。

举个例子:
在这里插入图片描述
在这里插入图片描述

构造算法

  1. 初始化:将每个权重作为一个叶子节点,放入一个优先队列(优先级基于节点权重,通常使用最小堆实现)。
  2. 合并节点:从队列中取出两个权重最小的节点,创建一个新的内部节点,其权重为这两个节点的权重之和,新节点作为这两个节点的父节点。
  3. 重复步骤2:将新创建的节点放回优先队列,重复上述过程,直到队列中只剩下一个节点,该节点即为哈夫曼树的根节点。
  4. 生成编码:从根到每个叶子节点的路径可以转化为一个唯一的二进制字符串(路径上向左走记为0,向右走记为1),这个字符串就是该叶子节点代表的字符的哈夫曼编码。

在这里插入图片描述这里我没有写得那么复杂,我用一个vector维护森林,并且排好序,然后依次拿出构造哈夫曼树:

#pragma once
#include<algorithm>
#include<iostream>
#include<vector>// 定义霍夫曼树节点结构体
template<class T>
struct HuffManTreeNode
{
public:// 构造函数,初始化节点数据、左孩子和右孩子HuffManTreeNode(T data):_data(data), _leftchild(nullptr), _rightchild(nullptr){}// 拷贝构造函数,用于复制已有节点的信息HuffManTreeNode(HuffManTreeNode<T>* node):_data(node->_data), _leftchild(node->_leftchild), _rightchild(node->_rightchild){}// 析构函数~HuffManTreeNode(){}// 创建新节点并返回指针HuffManTreeNode<T>* CreateNode(T data){HuffManTreeNode<T>* newnode = new HuffManTreeNode(data);return newnode;}// 根据已有节点创建新节点并返回指针HuffManTreeNode<T>* CreateNode(HuffManTreeNode<T>* node){HuffManTreeNode<T>* newnode = new HuffManTreeNode(node);return newnode;}// 向树中插入新节点void Insert(HuffManTreeNode<T>*& node, T data){HuffManTreeNode<T>* newnode = CreateNode(data);if (newnode == nullptr){perror("new fail");return;}if (node->_leftchild == nullptr){node->_leftchild = newnode;}else if (node->_rightchild == nullptr){node->_rightchild = newnode;}return;}// 向树中插入已有节点void Insert(HuffManTreeNode<T>*& node, HuffManTreeNode<T>* temp){if (node->_leftchild == nullptr){node->_leftchild = CreateNode(temp);}else if (node->_rightchild == nullptr){node->_rightchild = CreateNode(temp);}return;}// 重载赋值运算符HuffManTreeNode<T>& operator=(const HuffManTreeNode<T>* node){if (this == node){return *this;}_data = node->_data;_leftchild = node->_leftchild;_rightchild = node->_rightchild;return *this;}// 数据成员T _data;// 左右孩子指针HuffManTreeNode<T>* _leftchild;HuffManTreeNode<T>* _rightchild;
};// 中序遍历霍夫曼树
template<class T>
void Inorder(HuffManTreeNode<T>* node)
{if (node == nullptr){return;}Inorder(node->_leftchild); // 遍历左子树std::cout<< node->_data << " "; // 访问当前节点Inorder(node->_rightchild); // 遍历右子树
}
#include"Huffman.h"int main()
{std::vector<int> vt = {1,45,12,56,78,0,1,3};std::sort(vt.begin(),vt.end());for(auto e : vt){std::cout << e << " ";}std::cout<<std::endl;//创建哈夫曼树HuffManTreeNode<int>* node = new HuffManTreeNode(vt[0]+vt[1]);node->Insert(node,vt[0]);node->Insert(node,vt[1]);for(int i = 2 ; i < vt.size(); i++){HuffManTreeNode<int>* temp = node;node = node->CreateNode(node->_data +vt[i]);node->Insert(node,temp);node->Insert(node,vt[i]);}Inorder(node);return 0;
}

在这里插入图片描述

特性

  • 最优性:在所有叶子节点数量相同且节点权值已知的二叉树中,哈夫曼树的带权路径长度是最小的。
  • 编码效率:哈夫曼编码根据字符出现的频率分配编码,高频字符的编码较短,低频字符的编码较长,从而在整体上达到高效的数据压缩效果。
  • 无损编码:哈夫曼编码是一种无损数据压缩方法,可以完全恢复原始数据。
  • 自适应性:虽然经典哈夫曼编码基于静态概率模型,但存在变体如自适应哈夫曼编码,能够根据数据流动态调整编码表,适用于数据统计特性随时间变化的情况。

应用

  • 数据压缩:广泛应用于文本、图像、音频等数据的无损压缩。
  • 通信系统:优化数据传输,减少带宽需求。
  • 文件存储:减小文件大小,节约存储空间。
  • 编译器:用于词法分析中的关键字识别,通过为常用关键字分配较短编码,提高解析速度。

哈夫曼编码

哈夫曼编码(Huffman Coding)是一种高效的熵编码(Entropy Encoding)方法,用于无损数据压缩。它是基于哈夫曼树(Huffman Tree)构造的一种数据编码方式,由David A. Huffman在1952年提出。以下是哈夫曼编码的核心概念、工作原理以及特点:

核心概念

哈夫曼编码的基本思想是根据数据中各个符号(如字符、像素值等)出现的频率来为它们分配不同的编码,出现频率高的符号分配较短的编码,而频率低的符号则分配较长的编码。这样,当整个数据集被编码时,由于高频符号使用的短编码能频繁重复,从而实现整体数据量的压缩。

工作原理

  1. 频率统计:首先统计待编码数据中每个符号出现的频率。
  2. 构建哈夫曼树:使用频率作为权重,通过哈夫曼树的构造算法(见前述哈夫曼树的构造过程),构建一棵二叉树。在这个过程中,每次都将两个最小频率的节点合并成一个新的节点,新节点的频率是两个子节点频率之和。
  3. 生成编码:从哈夫曼树的根到每个叶子节点的路径定义了该叶子节点代表符号的编码。具体来说,向左分支时编码添加一个“0”,向右分支时添加一个“1”。因此,叶子节点越深,其对应的编码就越长。
  4. 编码数据:使用生成的哈夫曼编码表对原始数据进行编码,即将数据中的每个符号替换为其对应的编码字符串。

特点

  • 无损编码:哈夫曼编码是一种无损数据压缩技术,意味着解码后可以完全恢复原始数据。
  • 自适应性:虽然标准哈夫曼编码需要预先知道数据的概率分布,但可以通过动态哈夫曼编码技术,在不知道全部数据的情况下逐步更新编码表,适应数据流的变化。
  • 效率:在所有前缀编码(即任意编码都不会是另一个编码的前缀)中,哈夫曼编码提供了理论上的最优平均编码长度,即熵的上限。
  • 简单性:尽管编码效率高,哈夫曼编码的算法实现相对直接且易于理解。

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

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

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

相关文章

[面试题]计算机网络

[面试题]Java【基础】[面试题]Java【虚拟机】[面试题]Java【并发】[面试题]Java【集合】[面试题]MySQL[面试题]Maven[面试题]Spring Boot[面试题]Spring Cloud[面试题]Spring MVC[面试题]Spring[面试题]MyBatis[面试题]Nginx[面试题]缓存[面试题]Redis[面试题]消息队列[面试题]…

WAIC2024 | 华院计算邀您共赴2024年世界人工智能大会,见证未来科技革新

在智能时代的浪潮汹涌澎湃之际&#xff0c;算法已成为推动社会进步的核心力量。作为中国认知智能技术的领军企业&#xff0c;华院计算在人工智能的广阔天地中&#xff0c;不断探索、创新&#xff0c;致力于将算法的潜力发挥到极致。在过去的时日里&#xff0c;华院计算不断探索…

Java - Execl自定义导入、导出

1.需求&#xff1a;问卷星答 下图框出区域&#xff0c;为用户自定义字段问题及答案 2.采用技术EasyExcel 模板所在位置如下 /*** 导出模板** param response*/ Override public void exportTemplate(HttpServletResponse response) throws IOException {ClassPathResource c…

配置 Cmder 到鼠标右键

win Q 快捷键搜索 cmd&#xff0c;以管理员身份运行 在命令行输入 cmder.exe /REGISTER ALL

OpenCloudOS开源的操作系统

OpenCloudOS 是一款开源的操作系统&#xff0c;致力于提供高性能、稳定和安全的操作系统环境&#xff0c;以满足现代计算和应用程序的需求。它结合了现代操作系统设计的最新技术和实践&#xff0c;为开发者和企业提供了一个强大的平台。本文将详细介绍 OpenCloudOS 的背景、特性…

品牌进行3D数字化转型,有哪些优势?

各行业都在经历着从增量市场向存量市场的转变&#xff0c;同时用户的消费观念也日趋成熟&#xff0c;更加注重产品的体验和服务质量。 无论是线上购物平台还是线下实体门店&#xff0c;提供个性化和增强体验感的产品与服务已成为未来发展的核心驱动力&#xff0c;品牌转型也迫…

SyncFolders文件备份—办公人员必备

SyncFolders支持在两个或多个文件夹之间同步文件&#xff0c;用户可以将重要文件同步到多个位置&#xff0c;如备份硬盘、网络共享文件夹或云存储等。通过设定同步规则&#xff0c;可以自动备份和同步更新&#xff0c;减少手动操作的繁琐&#xff0c;确保文件的安全和可访问性。…

uniapp横屏移动端卡片缩进轮播图

uniapp横屏移动端卡片缩进轮播图 效果&#xff1a; 代码&#xff1a; <!-- 简单封装轮播图组件:swiperCard --> <template><swiper class"swiper" circular :indicator-dots"true" :autoplay"true" :interval"10000&quo…

软件必须要进行跨浏览器测试吗?包括哪些内容和注意事项?

随着互联网的普及和发展&#xff0c;用户对软件的要求越来越高。无论是在台式机、笔记本还是移动设备上&#xff0c;用户都希望能够以最好的体验来使用软件。然而&#xff0c;不同的浏览器在解析网页的方式、支持的技术标准等方面存在差异&#xff0c;这就导致了同一个网页在不…

fpga bitstream userid

fpga version register # xdc 文件 set_property BITSTREAM.CONFIG.USERID "0xDEADC0DE" [current_design] set_property BITSTREAM.CONFIG.USR_ACCESS 0x66669999 [current_design]ug908 在bit下载之后的property可以看到 &#xff0c;GUI里面Tools → Edit Devic…

QT项目实战:拼图小游戏

一、拼图智益-经典游戏&#xff08;开发环境&#xff09; 1&#xff1a;操作系统&#xff1a;Windows 10 x64专业版。 2&#xff1a;开发工具&#xff1a;Qt 5.12.8。 二、拼图智益-经典游戏&#xff08;功能模块&#xff09; 1&#xff1a;功能模块1&#xff1a;游戏启动…

1.1电路模型

1.1电路模型 任何实际电路由以下三部分组成&#xff1a; ①提供电能的能源 – 电源 ②用电装置 – 负载 ③传输电能的金属连线 – 导线 实际电路完成的功能&#xff1a;主要有以下两个方面&#xff1a; &#xff08;1&#xff09;进行能量的产生、传输和转换。&#xff08;如…

flash申请内存失败,导致老化问题解决

背景 在闪光灯初始化阶段客制化了一个buffer&#xff0c;下发到kernel的闪光灯驱动中用于保存读取闪光灯寄存器的值。功能测试都是正常的&#xff0c;但是一旦开始批量跑产线老化测试会有1/4500左右概率的后主摄拍照卡住。定位根因是闪光灯初始化失败&#xff0c;进一步原因就…

牛筋面,一口难忘的劲道滋味

在众多的平凉美食中&#xff0c;牛筋面以其独特的口感和丰富的口味&#xff0c;赢得了无数食客的喜爱。牛筋面&#xff0c;这一名字就给人一种坚韧、有嚼劲的印象。它并非由牛筋制成&#xff0c;而是因其面条的口感如牛筋般劲道而得名。牛筋面的制作过程颇具巧思。选用优质的面…

sheng的学习笔记-AI-K均值算法

ai目录&#xff1a;sheng的学习笔记-AI目录-CSDN博客 需要学习前置知识&#xff1a;聚类&#xff0c;可参考 sheng的学习笔记-聚类(Clustering)-CSDN博客 目录 什么是k均值算法 流程 伪代码 数据集 伪代码 代码解释 划分示意图 优化目标 随机初始化 选择聚类数…

鸿蒙期末项目(3)

服务器搭建完成之后&#xff0c;编写了诸多api用于数据传输工作&#xff08;略&#xff09; 编写完成之后&#xff0c;回到鸿蒙开发工具&#xff0c;开始编写搜索页面的代码。 打开搜索页面时&#xff0c;先会展示历史搜索记录&#xff08;如果有的话&#xff09;&#xff0c;…

Kafka入门到精通(四)-SpringBoot+Kafka

一丶IDEA创建一个空项目 二丶添加相关依赖 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springf…

用户订单管理API:轻松管理,购物无忧

在当今数字化时代&#xff0c;电子商务已经成为人们购物的首选方式。与传统的实体店相比&#xff0c;电商的优势在于便捷、快速、多样化等特点&#xff0c;使得更多的消费者选择了通过网络购物。而作为电商平台&#xff0c;如何提供更好的购物体验&#xff0c;是每个平台都需要…

企业工程项目管理系统源码:Java版源码解析

一、项目概述 鸿鹄工程项目管理系统是基于Spring Cloud、Spring Boot、Mybatis、Vue和ElementUI技术栈&#xff0c;采用前后端分离架构构建的工程管理软件。它旨在应对企业快速发展中的管理挑战&#xff0c;提升工程管理效率&#xff0c;减轻工作负担&#xff0c;加速信息处理…

一次关于k8s的node节点NotReady的故障排查

master现象 分析 kubectl get nodes -A 看了下pod的状态&#xff0c;好多CrashLoopBackOff kubectl get nodes -o wide 定位到那个具体node的IP地址&#xff0c;登录对应的IP去查看为什么会这样 node节点 journalctl -xe -f -u kubelet 查看此节点的 kubelet 服务&#xff…