详解哈夫曼树和哈夫曼编码
哈夫曼树、哈夫曼编码
- 哈夫曼树
- 初始化哈夫曼树
- 构造哈夫曼树
- Select()
- 哈夫曼编码
- 根据哈夫曼树求哈夫曼编码
- 测试代码
- 运行实例
哈夫曼树
定义:带权路径长度最短的树
如上图三棵二叉树,都包含4个叶子结点a、b、c、d,分别带权7、5、2、4,它们的带权路径长度分别为36(a),46(b),35c。
显然,c树带权路径长度最小,经验证c树即为哈夫曼树。
哈夫曼树的结构:
typedef struct
{int weight;int parent,lchird,rchild;
}HTNode,*HuffmanTree;
初始化哈夫曼树
说明:初始化带有n个叶子结点的哈夫曼树。
void InitHuffmanTree(HuffmanTree &H,int n)
{if(n<=1) return ;int m=2*n-1;H=new HTNode[m+1];for (int i = 1; i <= m; i++){H[i].parent=0;H[i].lchird=0;H[i].rchild=0;}for (int i = 1; i <= n; i++){cin>>H[i].weight;}
}
实现:①二叉树的结点数m=2*n-1,n为二叉树的叶子结点数。
②为了实现方便,从数组下标为1的位置开始使用,所以分配m+1个空间。
③将叶子结点存储在前面1~n个位置,后面n-1个位置存储构造后的其他节点。
构造哈夫曼树
void CreateHuffmanTree(HuffmanTree &H,int n)
{int m=2*n-1;int s1,s2;for (int i = n+1; i <= m; i++){Select(H,i-1,s1,s2);H[s1].parent=i; H[s2].parent=i;H[i].lchird=s1; H[i].rchild=s2;H[i].weight=H[s1].weight+H[s2].weight;}
}
实现:Select()函数的作用为每次选择前1到i-1个结点,挑选两个双亲域为0且权值最小的节点,利用s1和s2返回两个结点的下标。
接着将两个节点的双亲域赋值为当前节点的下标i,将当前节点的孩子域分别置为s1和s2.
最后将两个节点权值相加,和储存在当前“生成”结点的weight。
此哈夫曼树带权路径长度为:23x2+29x2+11x3+14x3+3x4+5x4+7x4+8x4=271
Select()
bool cmp(HTNode a,HTNode b)
{return a.weight<b.weight;
}
void Select(HuffmanTree H,int l,int &s1,int &s2)
{HuffmanTree M;M=new HTNode[l+1];for (int i = 1; i <= l; i++){M[i].weight=H[i].weight;M[i].parent=H[i].parent;M[i].lchird=H[i].lchird;M[i].rchild=H[i].rchild;}sort(M+1,M+l+1,cmp);int a[2]={0};int num=0;for (int i = 1; i <= l; i++){if(M[i].parent==0) {for (int j = 1; j <= l; j++){if(M[i].weight==H[j].weight&&H[j].parent==0&&j!=a[0]){a[num++]=j;break;}}}if(num==2) break;}s1=a[0];s2=a[1];delete M;
}
实现:创建一个副本M,每次将待查找的前1-l个单元复制给M,接着对M按照权值由低到高排序。
接着匹配原树和副本,查找权值最小且双亲域为0的两个结点,存储这两个结点本身(在原树中)的下标。
j!=a[0]
避免了权值相等时重复添加同一结点的情况。
创建副本的操作目的是不改变原树中结点的位置。
即1-n仍然是叶子结点,n+1~m为创建的节点。
哈夫曼编码
哈夫曼编码:对一棵具有n个叶子的哈夫曼树,若对树中的每个左分支赋0,右分支赋1,则从根到每个叶子的路径上,各分支的赋值分别构成一个二进制串,该二进制串就称为哈夫曼编码。
哈夫曼编码的基本思想是:为出现次数较多的字符编以较短的编码,在压缩原理中有重要作用。
如图,各叶子对应哈夫曼编码。
哈夫曼编码表的存储表示:
typedef char** HuffmanCode;
利用二级指针存储每个叶子的哈夫曼编码。
根据哈夫曼树求哈夫曼编码
void CreateHuffmanCode(HuffmanTree H,HuffmanCode &HC,int n)
{HC=new char*[n+1];char* cd=new char[n];cd[n-1]='\0';for (int i = 1; i <= n; i++){int start=n-1;int c=i;int f=H[i].parent;while (f!=0){--start;if (H[f].lchird==c){cd[start]='0';}else cd[start]='1';c=f;f=H[f].parent;}HC[i]=new char[n-start];strcpy(HC[i],&cd[start]);}delete cd;
}
利用cd存储每个字符的哈夫曼编码,start指向最后一个位置,f指向当前节点的双亲节点,c储存当前节点的下标。
不断向上遍历,若当前节点是双亲的左儿子就赋值0,右儿子就赋值1。
继续更新f和c向上遍历,直到走到树根,f==0
(树根双亲域为0)。
接着申请[n-start]空间的内存,将求得的编码从临时空间cd复制到HC的当前行中。
哈夫曼树可以不是唯一的,只要满足和带权路径长度最小值相等的树都是哈夫曼树。显然,哈夫曼编码也不唯一。
测试代码
int main()
{HuffmanTree H;HuffmanCode HC;int n;cin>>n;InitHuffmanTree(H,n);CreateHuffmanTree(H,n);CreateHuffmanCode(H,HC,n);for (int i = 1; i <= n; i++){cout<<HC[i]<<endl;}return 0;
}
运行实例
详解哈夫曼树和哈夫曼编码相关推荐
- 数据结构图文解析之:哈夫曼树与哈夫曼编码详解及C++模板实现
0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...
- 哈夫曼树(霍夫曼树)-详解
哈夫曼树(霍夫曼树)-详解 哈夫曼树(霍夫曼树)-详解 何为权值?我们看下百度百科的解释. 何为路径? 何为路径长度? 何为树的路径长度? 何为结点的带权路径长度? 何为树的带权路径长度(WPL)? ...
- 哈夫曼树、哈夫曼编码详解
哈夫曼树介绍 hello,大家好,我是bigsai.本以为哈夫曼树.哈夫曼编码很难,结果很容易嘛! 哈夫曼树.哈夫曼编码很多人可能听过,但是可能并没有认真学习了解,今天这篇就比较详细的讲一下哈夫曼树. ...
- 哈夫曼树及哈夫曼编码详解
一.预备知识 • 结点的路径长度:从根结点到该结点的路径上所包括的边的数目: • 树的内路径长度:除叶结点外,从根到树中其他所有结点的路径长度之和: • 树的外路径长度:从根结点到树中所有叶子结点的路 ...
- 哈夫曼树(赫夫曼树、最优树)详解
赫夫曼树,别名"哈夫曼树"."最优树"以及"最优二叉树".学习哈夫曼树之前,首先要了解几个名词. 哈夫曼树相关的几个名词 路径:在一棵树中, ...
- 【数据结构】-哈夫曼树以及哈夫曼编码
哈夫曼树的几个定义 哈夫曼树又叫最优二叉树:特点是带权路径最短 带权路径长度:该结点到根结点的路径长度乘以该结点的权值. 树的带权路径长度(WPL):所有叶子结点到根结点的带全路径长度之和. 最优二叉 ...
- 【Java数据结构与算法】第十二章 哈夫曼树和哈夫曼编码
第十二章 哈夫曼树和哈夫曼编码 文章目录 第十二章 哈夫曼树和哈夫曼编码 一.哈夫曼树 1.基本术语 2.构建思路 3.代码实现 三.哈夫曼编码 1.引入 2.介绍 3.代码实现哈夫曼编码综合案例 一 ...
- 【数据结构】树与树的表示、二叉树存储结构及其遍历、二叉搜索树、平衡二叉树、堆、哈夫曼树与哈夫曼编码、集合及其运算
1.树与树的表示 什么是树? 客观世界中许多事物存在层次关系 人类社会家谱 社会组织结构 图书信息管理 分层次组织在管理上具有更高的效率! 数据管理的基本操作之一:查找(根据某个给定关键字K,从集合R ...
- 哈夫曼树和哈夫曼编码应用之图片压缩编码c++实现
本人正在学习数据结构,在前几天做了压缩图片的项目,感觉到有必要分享给大家.因此今天我就分享给大家c语言数据结构有关哈夫曼树压缩图片的项目实现. 一:下面先介绍有关的知识: 1.背景 压缩软件是用特定算 ...
- Huffman霍夫曼树,霍夫曼编码
霍夫曼树基本概念: 路径:从一个结点往下到孩子或孙子结点之间的同理 路径长度:如结点1到结点7的路径长度=2 结点的权:将结点的某一属性值作为结点的权 带权路径长度:从根节点到该结点*该结点的权:如结 ...
最新文章
- 浅析营销型网站SEO优化的四大原则!
- 机器学习经典分类算法 —— C4.5算法(附python实现代码)
- python 接口自动化测试_python接口自动化测试之接口数据依赖
- vue中 使用md5加密
- Springboot集成axis1.4
- BZOJ 1041 数学
- Tensorflow2.0:使用Keras自定义网络实战
- boost安装_Boost编译与使用
- chattr和lsattr的基本用法
- qt定时器暂停与重新开始_Qt编写自定义控件22-蚂蚁线
- T61|NV显卡门|根据售后维修部数据显示爆发期来临|预防显卡门|解决显卡门
- veeam_backup的几种备份方式
- Verilog 练习 7段数码管译码器
- C# Word文档添加水印
- 微信这几个好用的功能,你该知道
- CAD自学笔记21条,零基础学CAD可以看看
- 径向渐变加阴影html,CSS径向渐变阴影 - 反转
- 编译原理实验一:词法分析程序设计与实现
- 安卓 7.0 无法获取外置SD卡问题解决方案 | Failed to find configured root that contains
- 英语dyamaund钻石dyamaund单词
热门文章
- Unity场景打包AssetBundle并加载
- LoadRunner教程(22)-LoadRunner C语言脚本
- Objective-C 函数
- ret2text涉及到的堆栈平衡问题
- 老电脑xp系统最流畅的浏览器_1步打造极限精简的win10系统,让老电脑像新机般流畅,再也不卡了...
- 小川opencv100例 之 准备食材 之 读取视频
- python实例(二):判断输入的车牌归属地
- 如何在SOLIDWORKS中使用PDM模板?
- android最新adt下载地址,Android SDK和最新ADT下载地址
- 防火墙服务器-iptables