哈夫曼树与哈夫曼编码

一、哈夫曼树相关概念

        路径:从树中的一个节点到另一个节点之间的分支构成两个节点间的路径。

        节点的路径长度:两节点间路径的分支数(路径的个数)

        树的路径长度(TL):从根节点到树中每一个点的路径长度之和

路径长度:

        节点A到A,B,C,D,E,F的路径长度分别为0,1,1,2,2,2

 树的路径长度(TL):

        节点A到树中每个节点的路径之和 TL=0+1+1+2+2+2=8

        

        权(权重):将树中的节点赋值(具体实际意义与场合有关)。

        节点的带权路径长度:从根节点到该节点之间的路径长度与节点上权的乘积。

        树的带权路径长度(WPL):树中所有叶子节点的带权路径长度之和

        WPL=4*2+5*2+6*2=30

 哈夫曼树:最优二叉树,带权路径长度(WPL)最小的树。

二、哈夫曼树构造方法

        1.n个给定权值的节点构成n棵树(1个森林),每个树都有且仅包含一个节点(不重复)

        2.选择两棵最小节点权值的树结合构成一棵新的二叉树,并且新二叉树的根节点的权值为其左右子树上根节点的权值之和.

        3.在森林中删除这两棵树,并且将新二叉树加入森林

        4.重复2-3操作,直至森林中仅剩一棵树为止,为哈夫曼树

         根据哈夫曼树的构建可以得出:

        1.初始时有n棵二叉树,经过n-1次合并成为哈夫曼树

        2.n-1次合并产生n-1个新节点,新节点都是具有两个孩子的分支节点

        哈夫曼树中共有n+n-1 =2n-1个结点,且其所有的分支结点的度均不为1。

三、代码实现哈夫曼树 

        构建哈夫曼树:需要每次根据各个节点的权重值,筛选出其中最小且无父的两个节点,然后构建二叉树                                              查找权值最小的两个节点:从数组起始位置开始,首先找到两个无父的节点(还未与其他树结合构建),然后和后续无父的节点作比较

        1.如果比两个节点中较小的那个还小,则保留这个节点,删除较大的节点

        2.如果介于两个权重值之间,替换较大的节点

查找权值最小节点的代码:

//HT数组中存放的哈夫曼树,end表示HT数组中存放结点的最终位置,s1和s2传递的是HT数组中权重值最小的两个结点在数组中的位置
void Select(HuffmanTree HT, int x, int *s1, int *s2)
{int min1,min2;int i=1;//找到还没构建树的结点while(HT[i].parent!=0 && i<=x){i++;}min1=HT[i].weight;*s1=i;i++;while(HT[i].parent!=0 && i<=nx{i++;}//对找到的两个结点比较大小,min2为较大的,min1较为小的if(HT[i].weight<min1){min2=min1;*s2=*s1;min1=HT[i].weight;*s1=i;}else{min2=HT[i].weight;*s2=i;}for(int j=i+1;j<=nxj++){//如果有父结点,直接跳过,进行下一个if(HT[j].parent!=0){continue;}//如果比最小的还小if(HT[j].weight<min1){min2=min1;min1=HT[j].weight;*s2=*s1;*s1=j;}//如果介于两者之间else if(HT[j].weight>=min1 && HT[j].weight<min2){min2=HT[j].weight;*s2=j;}}
}

构建哈夫曼树代码:

//HT为地址传递的存储哈夫曼树的数组,w为存储结点权重值的数组,n为结点个数
void CreateHuffmanTree(HuffmanTree *HT,int *w,int n)
{int m=2*n-1; // m为哈夫曼树总节点数,n为叶子结点*HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode)); // 0号位置不用HuffmanTree p=*HT;// 初始化哈夫曼树中的所有结点for(int i=1;i<=n;i++){(p+i)->weight=*(w+i); // p[i].weight=w[i](p+i)->parent=0;(p+i)->left=0;(p+i)->right=0;}//从树组的下标 n+1 开始初始化哈夫曼树中除叶子结点外的结点for(int i=n+1;i<=m;i++){(p+i)->weight=0;(p+i)->parent=0;(p+i)->left=0;(p+i)->right=0;}//构建哈夫曼树for(int i=n+1;i<=m;i++){int s1,s2;Select(*HT,i-1,&s1,&s2);(*HT)[s1].parent=(*HT)[s2].parent=i;  //新添第i个节点(*HT)[i].left=s1;(*HT)[i].right=s2;(*HT)[i].weight=(*HT)[s1].weight+(*HT)[s2].weight;}
}

四、哈夫曼编码(贪心思想)      

   哈夫曼编码也翻译为赫夫曼编码(Huffman Coding),又称霍夫曼编码,是一种编码方式, 属于一种程序算法,赫夫曼编码是赫哈夫曼树在电讯通信中的经典的应用之一。 赫夫曼编码广泛地用于数据文件压缩。其压缩率通常在20%~90%之间赫夫曼码是可变字长编码(VLC)的一种。Huffman于1952年提出一种编码方法,称之为最佳编码

        在远程通讯中,将待传字符转化成二进制的字符串。

        1.在通信领域中信息的其他处理方式

        ①定长编码:字符通过ASCII代码转化,再用二进制表示

        将 i like like like java do you like a java 定长编码       // 共40个字符(包括空格)  

        105 32 108 105 107 101 32 108 105 107 101 32 108 105 107 101 32 106 97 118 97 32 100 111 32 121 111 117 32 108 105 107 101 32 97 32 106 97 118 97  //对应Ascii码

        01101001 00100000 01101100 01101001 01101011 01100101 00100000 01101100 01101001 01101011 01100101 00100000 01101100 01101001 01101011 01100101 00100000 01101010 01100001 01110110 01100001 00100000 01100100 01101111 00100000 01111001 01101111 01110101 00100000 01101100 01101001 01101011 01100101 00100000 01100001 00100000 01101010 01100001 01110110 01100001 //对应的二进制 按照二进制来传递信息,总的长度是  359   (包括空格)

        定长编码的方法保证了信息传递的正确性,但是从上述过程可以看出,效率并不是最优的

        ②变长编码:将各个字符按照出现的次数进行编码,即出现次数越多的,编码越小.(出现次数越多的尽可能使其编码越小)

       

通过上述图例,可以很明显看出存在编码多义,即一段编码可以得出多种结果,显然是错误的方法.

        若需要运用上述思想,可以作前缀编码(每个字符的编码都不能是其他字符编码的前缀),例如上述 A=0 与 B=00,A的编码就是B编码的前缀.而哈夫曼编码就是运用这一想法.

        2.哈夫曼编码

        ①统计每个字符在字符串中出现的次数(出现次数越多,要求编码越短

        ②利用哈夫曼树的特点,以每个字符出现的次数作为权值,权越大的叶子节点离根越近,构造哈夫曼树

        ③在哈夫曼树的左分支标上0,右分支标上1

        则某个节点的编码即为从根节点到该节点路径上的标号连接而成,这样保证了前缀编码,不出现歧义

        3.哈夫曼编码代码实现

        首先根据数据构建哈夫曼树(上述代码已讲),再通过遍历哈夫曼树找出字符对应的二进制编码.

        法一:从叶子节点一直找到根节点,逆向记录途中的标记.

        法二:从根节点出发,一直到叶子节点,记录途中经过的标记

//HT为哈夫曼树,HC为存储结点哈夫曼编码的二维动态数组,n为结点的个数
void HuffmanCoding(HuffmanTree HT, HuffmanCode *HC,int n)
{*HC=(HuffmanCode) malloc((n+1)*sizeof(char*));char *cd=(char *)malloc(n*sizeof(char)); //存放结点哈夫曼编码的字符串数组cd[n-1]='\0';//字符串结束符for(int i=1;i<=n;i++){//从叶子结点出发,得到的哈夫曼编码是逆序的,需要在字符串数组中逆序存放int start=n-1;//当前结点在数组中的位置int c=i;//当前结点的父结点在数组中的位置int j=HT[i].parent;// 一直寻找到根结点while(j!=0){// 如果该结点是父结点的左孩子则对应路径编码为0,否则为右孩子编码为1if(HT[j].left==c)cd[--start]='0';elsecd[--start]='1';//以父结点为孩子结点,继续朝树根的方向遍历c=j;j=HT[j].parent;}//跳出循环后,cd数组中从下标 start 开始,存放的就是该结点的哈夫曼编码(*HC)[i]=(char *)malloc((n-start)*sizeof(char));strcpy((*HC)[i],&cd[start]);}//使用malloc申请的cd动态数组需要手动释放free(cd);
}

学习博文

​​​​​​【数据结构与算法】-哈夫曼树(Huffman Tree)与哈夫曼编码_哈夫曼编码树-CSDN博客

哈夫曼编码详解-CSDN博客

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

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

相关文章

基于FPGA的AD7705芯片驱动设计VHDL代码Quartus仿真

名称&#xff1a; 软件&#xff1a;Quartus基于FPGA的AD7705芯片驱动设计VHDL代码Quartus仿真&#xff08;文末获取&#xff09; 语言&#xff1a;VHDL 代码功能&#xff1a; AD77025芯片控制及串口输出 1、使用FPGA控制AD77025芯片&#xff0c;使其输出AD值 2、将数据计…

安卓开发(二)Android开发基础知识

了解Android Android大致可以分为4层架构&#xff1a;Linux内核层、系统运行库层、应用框架层和应用层。 内核层&#xff1a;Android系统是基于Linux内核的&#xff0c;这一层为Android设备的各种硬件提供了底层的驱动&#xff0c;如显示驱动、音频驱动、照相机驱动、蓝牙驱动…

CANdela/Diva系列2--CANdela Studio的工作树介绍1

本系列的第一篇文章&#xff08;CANdela/Diva系列1--CANdela Studio的基本介绍&#xff09;主要介绍了CANdela这个工具&#xff0c;本篇文章将对CANdela Studio的工作树的每个模块进行详细介绍&#xff0c;不啰嗦&#xff0c;直接开始&#xff01; 目录 1. ECU Information的…

技术速递|使用 .NET 为 Microsoft AI 构建可扩展网关

作者&#xff1a;Kara Saucerman 排版&#xff1a;Alan Wang Microsoft AI 团队构建了全面的内容、服务、平台和技术&#xff0c;以便消费者在任何设备上、任何地方获取他们想要的信息&#xff0c;并为企业改善客户和员工的体验。我们的团队支持多种体验&#xff0c;包括 Bing、…

MapReduce的Shuffle过程

Shuffle是指从 Map 产生输出开始,包括系统执行排序以及传送Map输出到Reduce作为输入的过程. Shuffle 阶段可以分为 Map 端的 Shuffle 阶段和 Reduce 端的 Shuffle 阶段. Shuffle 阶段的工作过程,如图所示: Map 端的 Shuffle 阶段 1&#xff09;每个输入分片会让一个 Map 任务…

【探索Java编程:从入门到入狱】Day4

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java、PHP】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收…

【YoloDeployCsharp】基于.NET Framework的YOLO深度学习模型部署测试平台

YoloDeployCsharp|基于.NET Framework的YOLO深度学习模型部署测试平台 1. 项目介绍2. 支持模型3. 时间测试4. 总结 1. 项目介绍 基于.NET Framework 4.8 开发的深度学习模型部署测试平台&#xff0c;提供了YOLO框架的主流系列模型&#xff0c;包括YOLOv8~v9&#xff0c;以及其系…

MySql数据库(概念篇)

数据库概念 什么是数据库 数据库见名之意&#xff0c;就是用来存储数据的仓库&#xff0c;是一个长期存储在计算机内的、有组织的、可共享的、统一管理的大量数据的集合。 没接触数据库之前&#xff0c;一般都是将数据存储在文件中。比如execl文件&#xff0c;word文件中。但是…

基于SpringBoot的饭店外卖平台的设计与实现

项目描述 这是一款基于SpringBoot的饭店外卖平台的系统 模块描述 用户端 登录 首页 商家信息 点餐 菜品列表 下单 订单列表 账号下单列表 个人中心 个人资料 修改信息 评论管理 评论菜品 查看评论 打赏骑手 打赏骑手 管理员 登录 菜品管理 修改 下架 订单列表 下单记录 菜品管理…

nginx 负载均衡、反向代理实验

nginx 负载均衡、反向代理实验 实验目的 理解概念&#xff1a;明确反向代理和负载均衡的基本概念及其在网络架构中的作用。 掌握技能&#xff1a;学习如何配置Nginx以实现反向代理和负载均衡功能。 实践应用&#xff1a;通过实际操作&#xff0c;体验Nginx如何提升Web服务的可…

LeetCode406:根据身高重建队列

题目描述 假设有打乱顺序的一群人站成一个队列&#xff0c;数组 people 表示队列中一些人的属性&#xff08;不一定按顺序&#xff09;。每个 people[i] [hi, ki] 表示第 i 个人的身高为 hi &#xff0c;前面 正好 有 ki 个身高大于或等于 hi 的人。 请你重新构造并返回输入数…

TinyXML-2介绍

1.简介 TinyXML-2 是一个简单、小巧的 C XML 解析库&#xff0c;它是 TinyXML 的一个改进版本&#xff0c;专注于易用性和性能。TinyXML-2 用于读取、修改和创建 XML 文档。它不依赖于外部库&#xff0c;并且可以很容易地集成到项目中。 tinyXML-2 的主要特点包括&#xff1a…

远程工作的数据安全挑战和解决策略

随着远程工作的普及&#xff0c;数据安全面临了前所未有的挑战。企业在应对这些挑战时&#xff0c;必须采取切实有效的策略来保护敏感信息。以下是远程工作数据安全的主要挑战和相应的解决策略&#xff1a; 数据安全挑战 设备丢失或被盗&#xff1a;员工在外工作时&#xff0c…

ldap对接jenkins

ldap结构 配置 - jenkins进入到 系统管理–>全局安全配置 - 安全域 选择ldap - 配置ldap服务器地址&#xff0c;和配置ldap顶层唯一标识名 配置用户搜索路径 - 配置管理员DN和密码 测试认证是否OK

AIGC技术带给我们什么?基于AIGC原理及其技术更迭的思考

AIGC技术带给我们什么&#xff1f;基于AIGC原理以及技术更迭的思考 前言 AI&#xff0c;这个词在如今人们的视野中出现频率几乎超过了所有一切其他的事物&#xff0c;更有意思的是&#xff0c;出现频率仅次于这个词的&#xff0c;几乎都会加上一个修饰亦或是前缀——AI&#…

ROS机器人实用技术与常见问题解决

问题速查手册&#xff08;时实更新&#xff09;更加全面丰富的问题手册记录 1.机器人使用GPARTED挂载未分配空间 需要在图型界面下操作&#xff0c;建议使用no machine连接 安装gparted磁盘分区工具, sudo apt-get install gparted -y 启动软件 sudo gparted 点击磁盘/内存…

如何使用vue脚手架创建项目

前言 使用vue搭建项目的时候&#xff0c;我们可以通过对应的cmd命令去打开脚手架&#xff0c;然后自己配置对应的功能插件 说明&#xff1a; 要使用Vue脚手架创建项目&#xff0c;你需要先确保你已经安装了Node.js和npm&#xff08;Node.js的包管理器&#xff09;。然后&#…

热敏电阻怎么进行性能测试?并以LabVIEW为例进行说明

过程也可用于执行热敏电阻测量。RTD和热敏电阻遵循非常相似的功能原理&#xff0c;测量步骤与下面提供的步骤相同。有关热敏电阻的更多信息&#xff0c;请参阅本文档。 查找设备引脚排列 在连接任何信号之前&#xff0c;请找到您的设备引脚排列。 打开NI MAX并展开设备和接口。…

视频素材库在哪里找免费手机版?8个可以用手机浏览的素材网

在视觉内容占据主导地位的今天&#xff0c;合适的视频素材可以大大提升项目的吸引力和效果。以下列出的视频素材网站为广告制作者、社交媒体策略师及电影制作人提供了从传统到现代风格的各种视频素材选择&#xff0c;满足不同的创作需求。 1. 蛙学府&#xff08;中国&#xff…

PyGame 文字显示问题及解决方法

在 Pygame 中显示文字时可能会遇到一些问题&#xff0c;例如文字显示不清晰、字体不正确或者文字位置不准确等。以下是一些常见的问题及其解决方法&#xff0c;具体情况可以看看情况。 1、问题背景 一位用户在使用 PyGame 库进行游戏开发时&#xff0c;遇到了一个问题&#xf…