哈夫曼树的构造及应用
哈夫曼树的构造及应用
文章目录
- 哈夫曼树的构造及应用
- 带权路径长度
- 哈夫曼树定义
- 哈夫曼树的性质:
- 构造哈夫曼树
- 构造哈夫曼树存储及生成算法
- 算法框架
- 代码实操:
- 应用: 哈夫曼编码
带权路径长度
设二叉树具有n个带权值的叶子节点,那么从根节点到各个叶子节点的路径长度与相应节点权值的乘积之和,叫做二叉树的带权路径长度(WPL)。
▪ n 表示叶子结点的树木
▪ wi 表示叶子结点ki 的权值
▪ li分别表示根到ki之间的路径长度(即从叶子节点到达根节点的分指数)。
哈夫曼树定义
▪ 具有最小带权路径长度的二叉树称为哈夫曼树,或称为最优二叉树。
哈夫曼树的性质:
n个叶子节点的二叉树,共有2n-1个节点.
证明:
设有二叉树有X个节点,则根据题意得叶子结点为n个,
由哈夫曼树的性质可得, 该树除了叶子节点的度数为零外, 其余节点度数都为2 ,所以
总度数 = (X - n) * 2 ①
并且根据总结点数 X , 和 除了根节点外,其他节点都有一个前驱分支,所以
总度数 = (X - 1) ②
上面① ② 两式联立: (X - n) * 2 = (X - 1)
得, X = 2n - 1
构造哈夫曼树
▪ 策略
要使带权路径长度最小,须使权值越大的叶子节点越靠近根节点,而权值越小的叶子结点越远离根节点.
▪ 方法
(1)给定的n个权值(W1,W2,…Wn)构造n棵只有叶子节点的二叉树,从而得到一个二叉树的集合 F = {T1,T2,…,Tn};
(2)在F中选取根节点的权值最小和次小的两颗二叉树作为左、右子树,构造一棵新的二叉树,新的二叉树根节点的权值为其左、右子树根节点权值之和。
(3)在集合F中删除作为左、右子树的两颗二叉树,并将新建的二叉树加入到集合F中;
(4)重复(2)、(3)两步,当F中只剩下一颗二叉树时,这颗二叉树便是要建立的哈夫曼树。
构造哈夫曼树存储及生成算法
#define N 5 //叶子节点数
typedef struct
{char data; //节点值float weight; //权重int parent; //双亲节点int lchild; //左孩子节点int rchild; //右孩子节点
}HTNode;
HTNode ht[2*N-1];
步骤1:初始化
n 个叶子节点只有data和weight域值,所有2n-1个节点的parent、lchild和rchild域置为初值-1.
步骤2:
开始构造,逐步选出两个最小和次小的权值节点,然后作为组合,形成哈夫曼树
重复处理每个非叶子节点ht[i] ,(ht[n] ~ ht[2n-2], i: n ~ 2n-2 )
▪ 从 ht[0] ~ h [i-1]中找出根节点(即其parent域为-1)最小的两个节点ht[lnode]和ht[rnode]
▪ ht[node]和ht[rnode]作为左右子树,增加他们的双亲节点ht[i],有: ht[i].weight = ht[node].weight + ht[rnode].weight
算法框架
//传入
代码实操:
//传入构建所用数组和 叶子节点的个数,方便后续操作
void CreateHT(HTNode ht[],int n)
{//定义计数器,定义节点左右孩子的序号int i,j,k,lnode,rnode;//定义权值最小和次小的数组序号float min1,min2;//所有节点的数据区初始化,包括数组中记录节点双亲、左右孩子的数据区。for(i=0;i<2*n-1;i++){ht[i].parent=ht[i].lchild = ht[i].rchild = -1;}//开始构建叶子节点的双亲节点,运用哈夫曼树的思想,先挑出权值最小和次小的节点,将他们合并成新节点,剔除选中后的节点,后续接着操作for(i = n; i<2*n-1; i++){//找出权重最小的两个节点//先把两个变量变成超过所有权值的数值min1 = min2 = 32145;//构建的新节点,刚开始左右孩子置为 -1 ,表示无lnode = rnode = -1;//开始寻找最小和次小//开始遍历所有节点,for(k=0;k<=i-1;k++) //注意细节, k<i-1 , 只遍历构建的新节点的前面的节点{if(ht[k].parent=-1) //挑选不为 - 1 的节点,意思就是没有被挑选的{if(ht[k].weight<min1) //比最小的还小 , 那就给老大{min2 = min1; //给老大之前, 老大穿过的给老二rnode = lnode; // 左孩子是上次最小的,找到更小的了,所以现在交给右孩子 min1 = ht[k].weight; //最小的序号给老大lnode = k; // 左孩子的序号 是 k, 是最小的节点的序号} else if(ht[k].weight<min2) //如果老大 , 有的节点没看上, 比老大大,又比老二小, 那我们老二不能放过了{min2 = ht[k].weight; //序号安排rnode = k; // 仍然是变成右孩子,因为是次小的} } } //生成一个双亲节点ht[lnode].parent = i; //现在生成最小和次小的双亲 , 左孩子的父母,右孩子的父母ht[rnode].parent = i;ht[i].weight = ht[lnode].weight + ht[rnode].weight; //新节点的权重为两个孩子的和ht[i].lchild = lnode; // 标记左右孩子ht[i].rchild = rnode;}
}
应用: 哈夫曼编码
• 问题: 符号编码问题
• 举例
▪ 用于通信的电文(或一幅图像),有8个符号(设为’a’~‘h’)
▪ 各符号出现的概率分别为:
0.07、0.19、0.02、0.06、0.32、0.21、0.10
▪ 如何确定各符号的二进制编码,使编码后的代码长度最短?
• 解决方法1
▪ 等长编码: a:000 b:001 c:010 d:011 e:100 f:101 g:110 h:111
▪ 平均码长:3
• 解决方法2
• 哈夫曼非等长编码:
a: 1010 b:00 c:10000 d:1001 e:11 f:10001 g:01 h:1011
• 遵循的原则
出现概率高的,我们的编码尽可能的短, 出现频率低的,我们可以长一些
• 编码原则:
把概率当做权值,把各个字母当做对应的叶子节点,变成哈夫曼树,然后左子树标记为0,右子树标记为1,来保证唯一性,从而降低代码长度,实现代码的压缩.
• 平均码长:
各个字母的概率乘以其对应的哈夫曼树的路径长度之和, 所求得的即为平均码长.
哈夫曼树的构造及应用相关推荐
- 哈夫曼树的构造及C++代码实现
哈夫曼树的构造过程: (1) 以权值分别为W1,W2...Wn的n各结点,构成n棵二叉树T1,T2,...Tn并组成森林F={T1,T2,...Tn},其中每棵二叉树 Ti仅有一个权值为 Wi的根结点 ...
- 数据结构学习记录——哈夫曼树(什么是哈夫曼树、哈夫曼树的定义、哈夫曼树的构造、哈夫曼树的特点、哈夫曼编码)
目录 什么是哈夫曼树 哈夫曼树的定义 哈夫曼树的构造 图解操作 代码实现 代码解析 哈夫曼树的特点 哈夫曼编码 不等长编码 二叉树用于编码 哈夫曼编码实例 什么是哈夫曼树 我们先举个例子: 要将百分制 ...
- c语言最优树的构造,哈夫曼树的构造及编码 Haffman树的构造及其编码
写出构造完整的哈夫曼树的编码 void HuffmanCoding(HuffmanCode HC[], int w[], int n) // w存放n个字符的权值(均>0),构造哈夫曼树HT, ...
- 哈夫曼树的构造算法代码
代码: #include<stdio.h> #define ERROR 0 #define OK 1 typedef int Status; //采用顺序存储结构,一维结构数组 //定义结 ...
- 哈夫曼树的构造C/C++代码实现
哈夫曼树: 所谓哈夫曼(Huffman)树就是最优二叉树,是带权路径长度WPL最小的二叉树. 哈夫曼树的构造: 根据哈夫曼树的特点:权值越大的结点离根结点越近. 具体方法:依次选择权值最小的二个结点作 ...
- 哈夫曼树的构造(C语言实现)
哈夫曼树的构造过程可以详见推荐博客:哈夫曼树以及哈夫曼编码的构造步骤 建议先看完推荐博客中的文字说明,或者自己找一本数据结构的树来仔细阅读以下关于哈夫曼树的构造 然后再来看下面给出的code 这里给出 ...
- 数据结构教程—哈夫曼树的构造算法
哈夫曼树算法如下 (1)根据给定的n个权值,使对应节点构成n棵二叉树的森林,其中每棵二叉树都只有一个根节点,其左右子树均为空. (2)在森林中选取两棵节点权值最小的子树分别作为左右子树构造一棵新的二叉 ...
- 哈夫曼树的构造(手写图解)
哈夫曼树的构造
- 哈夫曼树的构造 java_Java实现哈夫曼树的构造
哈夫曼树的内容这里不作解释,请自己搜索.下面给出哈夫曼树构造过程的 Java 实现. 结点类: 1./**2. * 二叉树节点3. */4.public class Node implements C ...
最新文章
- CentOS5 部署 戴尔OMSA
- 真格量化-主力跟买策略
- 信息系统项目管理师_信息系统项目管理师通过率是多少?
- 泰坦尼克号数据集_机器学习-预测泰坦尼克号生存概率
- 【tarjan缩点】受欢迎的牛
- 日期格式化插件 --- moment
- Android编程之另一种原因造成Cursor未关闭错误
- Powershell都有哪些好用的技能?
- win10报错网络未识别的问题
- 电子科技大学 计算机学院 夏令营,2018年电子科技大学全校各学院保研夏令营通知信息大汇总...
- 【项目介绍】单发动机驱动的多旋翼飞行器及其控制系统
- java 按 大写字母_用大写字母拆分字符串
- 世界上第一台计算机论文,世界上公认的第一台电子计算机是1946年诞生。.doc
- AR/VR---沉浸式体验
- cie1931 python绘制_科学网—gnuplot与CIE1931 XYZ三刺激值曲线 - 范学良的博文
- (附源码)php单招志愿采集系统 毕业设计 091409
- 自控原理学习笔记-反馈控制系统的动态模型(4)-频率特性函数Nyquist图及Bode图
- 《网络安全应急响应技术实战指南》知识点总结(第10章 流量劫持网络安全应急响应)
- Emacs 入门指引(一) Emacs简介
- Python语言程序设计基础 第二版(嵩天著)课后答案第六章
热门文章
- 北漂第一弹——应届前端的北漂开始
- input输入,限制小数点,小数位数,数字格式,中英文小数点
- Towards High-Fidelity 3D Face Reconstruction from In-the-Wild Images Using GCN
- 漫谈互联网产品设计之人性的弱点
- Github账户开启双重验证(two-factor authentication)
- 原声表格中将thead固定,tobody超出高度滚动,滚动条样式改变
- 快速学会corn表达式
- 超级详细!!!Windows解决GitHub网页打开很慢的问题!!!!
- 九月十月百度,迅雷,华为,阿里巴巴最新校招笔试面试三十题(10.18)
- 同济大学计算机其中考试时间,期中考试几月几号