霍夫曼树和哈夫曼树一样吗_霍夫曼树和哈夫曼树一样吗为什么

霍夫曼树和哈夫曼树一样吗_霍夫曼树和哈夫曼树一样吗为什么哈夫曼树(赫夫曼树、最优树)详解赫夫曼树,别名“哈夫曼树”、“最优树”以及“最优二叉树”。学习哈夫曼树之前,首先要了解几个名词。哈夫曼树相关的几个名词路径:在一棵树中,一个

哈夫曼树(赫夫曼树、最优树)详解
  赫夫曼树,别名“哈夫曼树”、“最优树”以及“最优二叉树”。学习哈夫曼树之前,首先要了解几个名词。

  哈夫曼树相关的几个名词

  路径:在一棵树中,一个结点到另一个结点之间的通路,称为路径。图 1 中,从根结点到结点 a 之间的通路就是一条路径。

  路径长度:在一条路径中,每经过一个结点,路径长度都要加 1 。例如在一棵树中,规定根结点所在层数为1层,那么从根结点到第 i 层结点的路径长度为 i – 1 。图 1 中从根结点到结点 c 的路径长度为 3。

  结点的权:给每一个结点赋予一个新的数值,被称为这个结点的权。例如,图 1 中结点 a 的权为 7,结点 b 的权为 5。

  结点的带权路径长度:指的是从根结点到该结点之间的路径长度与该结点的权的乘积。例如,图 1 中结点 b 的带权路径长度为 2 * 5 = 10 。

  树的带权路径长度为树中所有叶子结点的带权路径长度之和。通常记作 “WPL” 。例如图 1 中所示的这颗树的带权路径长度为:

  WPL = 7 * 1 + 5 * 2 + 2 * 3 + 4 * 3

  霍夫曼树和哈夫曼树一样吗_霍夫曼树和哈夫曼树一样吗为什么

  图1 哈夫曼树

  什么是哈夫曼树

  当用 n 个结点(都做叶子结点且都有各自的权值)试图构建一棵树时,如果构建的这棵树的带权路径长度最小,称这棵树为“最优二叉树”,有时也叫“赫夫曼树”或者“哈夫曼树”。

  在构建哈弗曼树时,要使树的带权路径长度最小,只需要遵循一个原则,那就是:权重越大的结点离树根越近。在图 1 中,因为结点 a 的权值最大,所以理应直接作为根结点的孩子结点。

  构建哈夫曼树的过程

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

  在 n 个权值中选出两个最小的权值,对应的两个结点组成一个新的二叉树,且新二叉树的根结点的权值为左右孩子权值的和;

  在原有的 n 个权值中删除那两个最小的权值,同时将新的权值加入到 n–2 个权值的行列中,以此类推;

  重复 1 和 2 ,直到所以的结点构建成了一棵二叉树为止,这棵树就是哈夫曼树。

  霍夫曼树和哈夫曼树一样吗_霍夫曼树和哈夫曼树一样吗为什么

  图 2 哈夫曼树的构建过程

   

  图 2 中,(A)给定了四个结点a,b,c,d,权值分别为7,5,2,4;第一步如(B)所示,找出现有权值中最小的两个,2 和 4 ,相应的结点 c 和 d 构建一个新的二叉树,树根的权值为 2 + 4 = 6,同时将原有权值中的 2 和 4 删掉,将新的权值 6 加入;进入(C),重复之前的步骤。直到(D)中,所有的结点构建成了一个全新的二叉树,这就是哈夫曼树。

  哈弗曼树中结点结构

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

  所以,哈夫曼树中结点构成用代码表示为:

  //哈夫曼树结点结构

  typedef struct {

  int weight;//结点权重

  int parent, left, right;//父结点、左孩子、右孩子在数组中的位置下标

  }HTNode, *HuffmanTree;

  构建哈弗曼树的算法实现

  构建哈夫曼树时,需要每次根据各个结点的权重值,筛选出其中值最小的两个结点,然后构建二叉树。

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

  如果比两个结点中较小的那个还小,就保留这个结点,删除原来较大的结点;

  如果介于两个结点权重值之间,替换原来较大的结点;

  实现代码:

  //HT数组中存放的哈夫曼树,end表示HT数组中存放结点的最终位置,s1和s2传递的是HT数组中权重值最小的两个结点在数组中的位置

  void Select(HuffmanTree HT, int end, int *s1, int *s2)

  {

  int min1, min2;

  //遍历数组初始下标为 1

  int i = 1;

  //找到还没构建树的结点

  while(HT[i].parent != 0 && i <= end){

  i++;

  }

  min1 = HT[i].weight;

  *s1 = i;

  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++)

  {

  //如果有父结点,直接跳过,进行下一个

  if(HT[j].parent != 0){

  continue;

  }

  //如果比最小的还小,将min2=min1,min1赋值新的结点的下标

  if(HT[j].weight < min1){

  min2 = min1;

  min1 = HT[j].weight;

  *s2 = *s1;

  *s1 = j;

  }

  //如果介于两者之间,min2赋值为新的结点的位置下标

  else if(HT[j].weight >= min1 && HT[j].weight < min2){

  min2 = HT[j].weight;

  *s2 = j;

  }

  }

  }

  注意:s1和s2传入的是实参的地址,所以函数运行完成后,实参中存放的自然就是哈夫曼树中权重值最小的两个结点在数组中的位置。

  构建哈弗曼树的代码实现如下:

  //HT为地址传递的存储哈夫曼树的数组,w为存储结点权重值的数组,n为结点个数

  void CreateHuffmanTree(HuffmanTree *HT, int *w, int n)

  {

  if(n<=1) return; // 如果只有一个编码就相当于0

  int m = 2*n-1; // 哈夫曼树总节点数,n就是叶子结点

  *HT = (HuffmanTree) malloc((m+1) * sizeof(HTNode)); // 0号位置不用

  HuffmanTree p = *HT;

  // 初始化哈夫曼树中的所有结点

  for(int i = 1; i <= n; i++)

  {

  (p+i)->weight = *(w+i-1);

  (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;

  (*HT)[i].left = s1;

  (*HT)[i].right = s2;

  (*HT)[i].weight = (*HT)[s1].weight + (*HT)[s2].weight;

  }

  }

  注意,如果使用此程序,对权重值分别为 2、8、7、6、5 的节点构建哈夫曼树,最终效果如图 4(A) 所示。但其实,图 4(B) 中显示的哈夫曼树也满足条件,这两棵树的带权路径长度相同。

  霍夫曼树和哈夫曼树一样吗_霍夫曼树和哈夫曼树一样吗为什么

  图 4 两种哈夫曼树

  之所以使用此程序构建的哈夫曼树,是图 4(A) 而不是 4(B),是因为在构建哈夫曼树时,结点 2 和结点 5 构建的新的结点 7 存储在动态树组中位置,比权重值为 7 节点的存储位置还靠后,所以,在程序继续选择两个权值最小的结点时,直接选择了的叶子结点 6 和 7 。

激活谷谷主为您准备了激活教程,为节约您的时间请移步至置顶文章:https://sigusoft.com/99576.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。 文章由激活谷谷主-小谷整理,转载请注明出处:https://sigusoft.com/98024.html

(0)
上一篇 2024年 5月 20日
下一篇 2024年 5月 20日

相关推荐

  • python安装教程mac_mac更新python

    python安装教程mac_mac更新pythonmac python 更新_python详细安装教程本章开始,我们将详细介绍Python编程环境的搭建,工欲善其事必先利其器,所以我们这里先介绍python详细安装教程。由于Python是跨平台的,他可以

    2024年 5月 8日
  • python string转换成float_python string转换为float

    python string转换成float_python string转换为floatpython中string和float之间如何转换?Python将string转换到float的实例方法当我们使用不同类型的数据时,会根据使用场景的不同,进行一定的转换操作。提起string和float大家肯定不陌生,前者作用于字符串,后者是一种常见的小数数据类型。下面

    2024年 5月 25日
  • 磁盘分区表已更改,请先保存分区表的文件_磁盘分区表已更改,请先保存分区表的文件

    磁盘分区表已更改,请先保存分区表的文件_磁盘分区表已更改,请先保存分区表的文件产品比一比查看详情 >>wowo52113140硬盘提示格式化一般情况是一种逻辑错误导致的,经常是在意外断电后出现该情况.主要原因是硬盘的分区表,或者是被称为主引导扇区的部分数据损坏和丢失

    2024年 5月 20日
  • 键盘钩子函数掉线了怎么办啊怎么解决

    键盘钩子函数掉线了怎么办啊怎么解决程序员尤其 Windows 程序员会经常说“下个钩子”,小编还是一名学生的时候,对说出这个短语的人真是崇拜至极。这么多年过去了,小编还会不经意间蹦出这几个字,即使已经了解这是一名程序员的基本功,说起来依然觉得有范儿。钩子来源于英文词hook。在Windows系统中一切皆消息,按键盘上

    激活谷笔记 2024年 5月 20日
  • 12400fcpuz测试分数_10400fcpuz测试分数

    12400fcpuz测试分数_10400fcpuz测试分数i5-12400Fi5-12400 哪个更值得入手?i5 10400i5-10400F?你应该想说的是i5-10400/F和i5-12400/F吧。这两款CPU不就说,那肯定是i5-12400/F更值得入手,要知道这款处理器要比AMD的5600X还要优秀。而i5-10400/F,

    2024年 5月 20日
  • 多线程同步的几种方法_多线程同步的几种方法有哪些

    多线程同步的几种方法_多线程同步的几种方法有哪些线程同步的几种方式前言进程有自己的独立地址空间,因此进程之间重点通信,通信方式包括:管道Pipe、命名管道FIFO、消息队列MessageQueue、共享存储SharedMemory、信号量Semaphore、套接字Socket和信号Signal

    2024年 5月 20日
  • 二叉排序树和折半查找_二叉排序树和折半查找的时间性能

    二叉排序树和折半查找_二叉排序树和折半查找的时间性能【音频带背】数据结构考前必背简答题系列(四):查找与排序抓码计算机考研将陆续推出数据结构、计网、计组、操作系统的必背文本及音频,文本由抓码专业团队的学长姐精心梳理,单篇推送后会推出PDF合集,帮助正在冲刺备考的你提高学习

    2024年 5月 29日
  • html 控件 代码_html5 控件

    html 控件 代码_html5 控件HTML5入门5-HTML5控件元素<!DOCTYPE html><html> <head> <meta charset=”utf-8″> <title>第三个页面</t

    激活谷笔记 2024年 5月 21日
  • pycharm专业版激活码2021_pycharm2021.2激活码

    pycharm专业版激活码2021_pycharm2021.2激活码Pycharm激活激活成功教程激活码2023-02最新教程【亲测有效,永久】(win+mac). 本文讲的是Pycharm 2023最新版激活激活成功教程教程,此教程支持windows、mac、linux。支持2021年以上并且支持最新版本。mac和linux的在文末讲解激活。windows激活步骤 先去jetbr

    2024年 5月 13日
  • tomcat默认线程池大小_tomcat线程池满应该如何处理

    tomcat默认线程池大小_tomcat线程池满应该如何处理Tomcat线程池及性能优化(重点)  只需安装Tomcat[root@localhost ~]# vim /usr/local/tomcat8/conf/server.xml修改处如下:&lt

    2024年 5月 13日
  • stemi英文全拼_stemi英语发音

    stemi英文全拼_stemi英语发音stemi医学上是什么意思_好在医生STEMI医学上一般指ST段抬高型心肌梗死。STEMI是ST段抬高型心肌梗死的英文简称,是急性心肌梗死的一种类型,患者具有缺血性胸痛的典型特征,且持续时间超过20min,血清心肌坏死标记物浓度升高,并且伴有动态演变,通

    激活谷笔记 2024年 6月 2日
  • linux删除文件命令

    linux删除文件命令请关注本头条号,每天坚持更新原创干货技术文章。如需学习视频,请在微信搜索公众号“智传网优”直接开始自助视频学习1. 前言本文主要讲解Linux删除文件夹或目录的命令rmdir和rm的使用方法。Windows上的文件夹与Linux系统里的目录是同一概念。默认情况下,L

    激活谷笔记 2024年 5月 19日
关注微信