哈夫曼树相关的几个名词

图1 哈夫曼树

路径:在一棵树中,一个结点到另一个结点之间的通路,称为路径

图 1 中,从根结点到结点 a 之间的通路就是一条路径

路径长度:在一条路径中,每经过一个结点,路径长度都要加 1

图 1 中,从根结点到结点 c 的路径长度为 

结点的权:给每一个结点赋予一个新的数值,被称为这个结点的权

图 1 中,结点 a 的权为 ,结点 b 的权为 

结点的带权路径长度:指的是从根结点到该结点之间的路径长度与该结点的权的乘积

图 1 中,结点 b 的带权路径长度为 

WPL:树的带权路径长度为树中所有叶子结点的带权路径长度之和

图 1 中,所示的这颗树的带权路径长度为:

什么是哈夫曼树

当用 n 个叶子结点构建一棵树时,如果构建的这棵树的带权路径长度(WPL)最小,称这棵树为最优二叉树,有时也叫赫夫曼树或者哈夫曼树

在构建哈弗曼树时,要使树的带权路径长度最小,只需要遵循一个原则:权重越大的结点离树根越近

构建哈夫曼树的过程

对于给定的有各自权值的 n 个叶子结点,构建哈夫曼树有一个行之有效的办法:

  1. 在 n 个权值中选出两个最小的权值,对应的两个结点组成一个新的二叉树,且新二叉树的根结点的权值为左右孩子权值的和
  2. 在原有的 n 个权值中删除那两个最小的权值,同时将新的权值加入到 n–2 个权值的行列中,以此类推
  3. 重复 1 和 2 ,直到所有的结点构建成了一棵二叉树为止,这棵树就是哈夫曼树

图 2 哈夫曼树的构建过程

上图 2中,给定了4个叶子结点,如果我们想构建哈夫曼树,构建过程是怎么样的呢!

第一步:在4个权值中选出二个最小的权值(2 和 4),将这二个权值对应的结点组成一个新的二叉树,且新二叉树的根结点(第五个结点)的权值为结点 c 和 d 的权值和 ,在原有4个权值中删除权值为 2 和 4后得到 7 和 5 二个权值,将新的权值 6 加入其中

第二步:在3个权值中选出二个最小的权值(5 和 6),将这二个权值对应的结点组成一个新的二叉树,且新二叉树的根结点(第六个结点)的权值为结点 b 和第五个结点的权值和 ,在原有3个权值中删除权值为 5 和 6后得到 7 一个权值,将新的权值 11 加入其中

第三步:在2个权值中选出二个最小的权值(7 和 11),将这二个权值对应的结点组成一个新的二叉树,且新二叉树的根结点(第七个结点)的权值为结点 a 和第六个结点的权值和  ,在原有2个权值中删除权值为 7 和 11,将新的权值 18 加入其中

第四步:此时已经构成了二叉树!这棵树称为哈夫曼树

哈弗曼树中结点结构

构建哈夫曼树时,首先需要确定树中结点的构成(叶子结点和构建结点)

由于哈夫曼树的构建是从叶子结点开始,不断地构建新的父结点,直至树根,所以结点中应包含指向父结点的指针,但是在使用哈夫曼树时是从树根开始,根据需求遍历树中的结点,因此每个结点需要有指向其左孩子和右孩子的指针

// 哈夫曼树结点结构
typedef struct{int weight;  // 结点权重int parent, left, right;// 父结点、左孩子、右孩子在数组中的位置下标
} HTNode;

对实现哈夫曼树的代码实现

完全代码!!!

#include <stdio.h>
#include <stdlib.h>// 哈夫曼树结点结构
typedef struct{int weight;  // 结点权重int parent, left, right;// 父结点、左孩子、右孩子在数组中的位置下标
} HTNode;void Select(HTNode *HT, int end, int *s1, int *s2){int min1, min2;// 遍历数组初始下标为 1int i = 1;// 找到还没构建树的结点while(HT[i].parent != 0 && i <= end){i++;}  // i=1 ——第一个树叶结点 min1 = HT[i].weight;  // 7 5 2 4*s1 = i; // 初始化权重最小位置为 1 i++;while(HT[i].parent != 0 && i <= end){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 <= end; j++){  // j=3(直到 j = end) // 如果有父结点,直接跳过,进行下一个if(HT[j].parent != 0){continue;}// 如果比最小的还小,将 min2=min1,min1赋值新的结点的下标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赋值为新的结点的位置下标min2 = HT[j].weight;*s2 = j;}}
}HTNode *CreateHuffmanTree(HTNode *HT, int *w, int n){if(n <= 1) return HT;int m = 2*n-1; // 哈夫曼树总节点数,n是叶子结点(m=7) HT = (HTNode*) malloc((m+1)*sizeof(HTNode));  //  HT[7]HTNode *p = HT;// 初始化哈夫曼树中的所有叶子结点for(int i = 1; i <= n; i++){  // n=4p[i].weight = w[i-1];  // p[1].weight = w[0] ... p[4].weight = w[3]p[i].parent = 0;p[i].left = 0;p[i].right = 0;}// 初始化除叶子结点外的其它结点 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;  // 保存了 HT数组中 weight较小值的二个下标 Select(HT, i-1, &s1, &s2);  // s1 = 3,s2 = 4// s1 = 1,s2 = 5// s1 = 1,s2 = 6HT[s1].parent = HT[s2].parent = i;  // 权重为 2和 4的二个结点的双亲为第五个结点 // 权重为 5和 6的二个结点的双亲为第六个结点// 权重为 7和 11的二个结点的双亲为第七个结点HT[i].left = s1;  // 初始化第五个结点的左孩子为权重为 2 的结点// 初始化第六个结点的左孩子为权重为 5 的结点// 初始化第七个结点的左孩子为权重为 7 的结点HT[i].right = s2;  // 初始化第五个结点的右孩子为权重为 4 的结点  // 初始化第六个结点的右孩子为权重为 6 的结点 // 初始化第七个结点的右孩子为权重为 11 的结点HT[i].weight = HT[s1].weight + HT[s2].weight;  // 初始化第五个结点的权重为 2+4 = 6 // 初始化第六个结点的权重为 5+6 = 11// 初始化第七个结点的权重为 7+11 = 18}return HT;
}int main(void){HTNode *ht = NULL;int weight[4] = {7, 5, 2, 4};ht = CreateHuffmanTree(ht, weight, 4);printf("树根结点权重:%d\n", ht[7].weight);  // 树根结点权重:18 return 0;
} 

部分函数代码体!!!

// 两个结点和后续的所有未构建成树的叶子结点做比较
for(int j = i+1; j <= end; j++){  // j=3(直到 j = end) // 如果有父结点,直接跳过,进行下一个if(HT[j].parent != 0){continue;}// 如果比最小的还小,将 min2=min1,min1赋值新的结点的下标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赋值为新的结点的位置下标min2 = HT[j].weight;*s2 = j;}
}

如上函数(Select)中查找权重值最小的两个结点的思想是:从数组起始位置开始,首先找到两个无父结点的结点(说明还未使用其构建成树),然后和后续无父结点的结点依次做比较,有两种情况需要考虑:

  1. 如果比两个结点中较小的那个还小,就保留这个结点,删除原来较大的结点
  2. 如果介于两个结点权重值之间,替换原来较大的结点

(数据结构)哈夫曼树相关推荐

  1. 数据结构---哈夫曼树

    数据结构-哈夫曼树 原理:参考趣学数据结构 代码: #include<stdio.h> #include<stdlib.h> #define N 100 #define INF ...

  2. 【数据结构——哈夫曼树及其应用】

    [数据结构--哈夫曼树及其应用] 一.哈夫曼树的基本概念 二.哈夫曼树的构造算法 (一)哈夫曼树的构造过程 (二)哈夫曼树构造算法的实现 1.初始化 2.创建树 3.完整的创建哈夫曼树代码 三.哈夫曼 ...

  3. 数据结构哈夫曼树实现26个英文字符的编码和译码

    数据结构哈夫曼树实现26英文字符的编码和译码 那么首先什么是哈夫曼树?(知道的略过,直奔下面代码就好!) 在计算机数据处理中,霍夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编 ...

  4. 数据结构--赫夫曼树

    数据结构 –赫夫曼树 文章目录 数据结构 一.一些概念 二.最优二叉树(赫夫曼树) 三.赫夫曼树的构造 四.赫夫曼编码 五.前缀编码 一.一些概念 路径:从树中一个结点到另一个结点之间的分支构成这两个 ...

  5. 数据结构(哈夫曼树,哈夫曼编码)入门篇,JAVA实现

    什么是哈夫曼树 哈夫曼树就是一种最优判定树,举个例子,如下一个判断逻辑 if(s<60) g=1; else if(s<70) g=2 else if(s<80) g=3 else ...

  6. 数据结构 - 赫夫曼树

    wpl最小的就是赫夫曼树(所有叶子节点的带权路径长度之和最小) 写出来两个节点连接,然后循环就可以了 package tree.huffmantree;import java.util.ArrayLi ...

  7. 数据结构--赫夫曼树及其应用

    讲解请参考 赫夫曼 ------ 赫夫曼树和赫夫曼编码的存储表示------ typedef struct {unsigned int weight;unsigned int parent,lchil ...

  8. 数据结构哈夫曼树(C语言版)

    文章目录 一. 问题 需求分析 代码分析 结构体定义使用 建立哈夫曼树,首先需要找到两个权值最小的两个叶子结点,然后建树 哈夫曼编码(我采用的是从叶子结点-->根节点,所以实际是反过来的) 使用 ...

  9. 数据结构——哈夫曼树

    1.介绍 哈夫曼树就是树的带权路径长度(即WPL)最小的树,WPL等于所有叶节点的带权路径长度之和. 而叶节点的带权路径长度=该结点的路径长度*该结点的权值. 结点的路径长度就是从根节点到该结点所经历 ...

  10. 算法与数据结构 --- 哈夫曼树及其应用

    第一部分 --- 哈夫曼树的基本概念 对一个判断树的判断次序进行改变后判断的总次数就可能截然不同 如上图,在面对一万个数据的时候,左边的判断树的判断总次数为22000次,右边的判断树的判断总次数为31 ...

最新文章

  1. 如何leangoo看板工具做可视化工作流
  2. 走出回归测试困境,爱奇艺精准测试体系建设
  3. 7系列FPGA逻辑单元理解
  4. 抽象工厂类--一个简单的例子
  5. altium designer 单层显示切换两次_新论文:北京新机场装配式单层铝合金网壳结构整体稳定性能研究...
  6. 一个好用的时间管理Chrome扩展 - Calendar and Countdown
  7. 如何写登录的记住账号
  8. vs 2010 不显示解决方案文件
  9. win10个人壁纸默认保存位置
  10. 什么原数据更容易平稳_为什么老年人更容易患上艾滋病?
  11. C++11/14::右值引用
  12. (转)高新技术在高频交易中的运用
  13. 《软件工程导论》第一章
  14. Adams2019安装教程链接分享
  15. Smart 200PLC PC Access SMART OPC通信
  16. 最长递增子序列的O(NlogN)算法
  17. Google之Stopwatch 计时器
  18. 【OneDrive篇】OneDrive禁用个人保管库(网页端)
  19. Unnecessary escape character: \- no-useless-escape eslint
  20. java知识点博客园_Java知识点总结1

热门文章

  1. 中国点胶机行业市场投资现状与竞争发展策略分析报告2022-2028年版
  2. 性能度量 - 对学习器泛化能力的评估
  3. YOLOv5 小目标检测、无人机视角小目标检测
  4. 修改Win7开机界面,让Win7也炫起来。
  5. Rationaldmis 3点拟合建立坐标系
  6. Python入门小项目-计算阶乘n的三种方法+常见练习(含代码示例)
  7. 机器学习(4):决策树和随机森林
  8. libRTMP使用说明
  9. 广义表中长度与深度的计算
  10. 前端下载base64格式视频