本章介绍哈夫曼树。和以往一样,本文会先对哈夫曼树的理论知识进行简单介绍,然后给出C语言的实现。后续再分别给出C++和Java版本的实现;实现的语言虽不同,但是原理如出一辙,选择其中之一进行了解即可。若文章有错误或不足的地方,请帮忙指出!

目录

1. 哈夫曼树的介绍
2. 哈夫曼树的图文解析
3. 哈夫曼树的基本操作
4. 哈夫曼树的完整源码


转载请注明出处:如果天空不死 - 博客园

更多内容:数据结构与算法系列 目录

哈夫曼树的介绍

Huffman Tree,中文名是哈夫曼树或霍夫曼树,它是最优二叉树。起源主要是信息编码传输,主要应用于信息编码和数字压缩领域,目前也是现代压缩算法的基础。

定义:给定n个权值作为n个叶子结点,构造一棵二叉树,若树的带权路径长度达到最小,则这棵树被称为哈夫曼树。 这个定义里面涉及到了几个陌生的概念,下面就是一颗哈夫曼树,我们来看图解答。

(01) 路径和路径长度

定义:在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径。通路中分支的数目称为路径长度。若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1。
例子:100和80的路径长度是1,50和30的路径长度是2,20和10的路径长度是3。

(02) 结点的权及带权路径长度

定义:若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。
例子:节点20的路径长度是3,它的带权路径长度= 路径长度 * 权 = 3 * 20 = 60。

(03) 树的带权路径长度

定义:树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为WPL。
例子:示例中,树的WPL= 1*100 + 2*80 + 3*20 + 3*10 = 100 + 160 + 60 + 30 = 350。

比较下面两棵树

上面的两棵树都是以{10, 20, 50, 100}为叶子节点的树。

左边的树WPL=2*10 + 2*20 + 2*50 + 2*100 = 360
右边的树WPL=350

左边的树WPL > 右边的树的WPL。你也可以计算除上面两种示例之外的情况,但实际上右边的树就是{10,20,50,100}对应的哈夫曼树。至此,应该堆哈夫曼树的概念有了一定的了解了,下面看看如何去构造一棵哈夫曼树。

哈夫曼树的图文解析

假设有n个权值,则构造出的哈夫曼树有n个叶子结点。 n个权值分别设为 w1、w2、…、wn,哈夫曼树的构造规则为:

1. 将w1、w2、…,wn看成是有n 棵树的森林(每棵树仅有一个结点);
2. 在森林中选出根结点的权值最小的两棵树进行合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和;
3. 从森林中删除选取的两棵树,并将新树加入森林;
4. 重复(02)、(03)步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树。

以{5,6,7,8,15}为例,来构造一棵哈夫曼树。

第1步:创建森林,森林包括5棵树,这5棵树的权值分别是5,6,7,8,15。
第2步:在森林中,选择根节点权值最小的两棵树(5和6)来进行合并,将它们作为一颗新树的左右孩子(谁左谁右无关紧要,这里,我们选择较小的作为左孩子),并且新树的权值是左右孩子的权值之和。即,新树的权值是11。 然后,将"树5"和"树6"从森林中删除,并将新的树(树11)添加到森林中。
第3步:在森林中,选择根节点权值最小的两棵树(7和8)来进行合并。得到的新树的权值是15。 然后,将"树7"和"树8"从森林中删除,并将新的树(树15)添加到森林中。
第4步:在森林中,选择根节点权值最小的两棵树(11和15)来进行合并。得到的新树的权值是26。 然后,将"树11"和"树15"从森林中删除,并将新的树(树26)添加到森林中。
第5步:在森林中,选择根节点权值最小的两棵树(15和26)来进行合并。得到的新树的权值是41。 然后,将"树15"和"树26"从森林中删除,并将新的树(树41)添加到森林中。
此时,森林中只有一棵树(树41)。这棵树就是我们需要的哈夫曼树!

哈夫曼树的基本操作

哈夫曼树的重点是如何构造哈夫曼树。本文构造哈夫曼时,用到了以前介绍过的"(二叉堆)最小堆"。下面对哈夫曼树进行讲解。

1. 基本定义

typedef int Type;typedef struct _HuffmanNode {Type key;                     // 权值struct _HuffmanNode *left;    // 左孩子struct _HuffmanNode *right;   // 右孩子struct _HuffmanNode *parent;  // 父节点
} HuffmanNode, *HuffmanTree;

HuffmanNode是哈夫曼树的节点类。

2. 构造哈夫曼树

/** 创建Huffman树** 参数说明:*     a 权值数组*     size 数组大小** 返回值:*     Huffman树的根*/
HuffmanNode* create_huffman(Type a[], int size)
{int i;HuffmanNode *left, *right, *parent;// 建立数组a对应的最小堆create_minheap(a, size);for(i=0; i<size-1; i++){   left = dump_from_minheap();  // 最小节点是左孩子right = dump_from_minheap(); // 其次才是右孩子// 新建parent节点,左右孩子分别是left/right;// parent的大小是左右孩子之和parent = huffman_create_node(left->key+right->key, left, right, NULL);left->parent = parent;right->parent = parent;// 将parent节点数据拷贝到"最小堆"中if (dump_to_minheap(parent)!=0){printf("插入失败!\n结束程序\n");destroy_huffman(parent);parent = NULL;break;}}   // 销毁最小堆destroy_minheap();return parent;
}

首先通过create_huffman(a, size)来一个最小堆。最小堆构造完成之后,进入for循环。

每次循环时:

(01) 首先,将最小堆中的最小节点拷贝一份并赋值给left,然后重塑最小堆(将最小节点和后面的节点交换位置,接着将"交换位置后的最小节点"之前的全部元素重新构造成最小堆);
(02) 接着,再将最小堆中的最小节点拷贝一份并将其赋值right,然后再次重塑最小堆;
(03) 然后,新建节点parent,并将它作为left和right的父节点;
(04) 接着,将parent的数据复制给最小堆中的指定节点。

在二叉堆中已经介绍过堆,这里就不再对堆的代码进行说明了。若有疑问,直接参考后文的源码。其它的相关代码,也Please RTFSC(Read The Fucking Source Code)!

哈夫曼树的完整源码

哈夫曼树的源码共包括4个文件。

1. 哈夫曼树的头文件(huffman.h)

2. 哈夫曼树的实现文件(huffman.c)

3. 哈夫曼树对应的最小堆(minheap.c)

4. 哈夫曼树的测试程序(huffman_test.c)

哈夫曼树(一)基本概念与C语言实现相关推荐

  1. 哈夫曼树的基本概念及其构建(C++)

    哈夫曼树的基本概念: 在了解哈夫曼树的概念之前,我们要了解到的是带权路径长度的概念: 在实际应用当中,树中的结点往往都会被赋予某种意义的数值,这个数值就称为该结点的权: 从根结点到任意结点的路径长度( ...

  2. 【数据结构】【哈夫曼树】哈夫曼树、赫夫曼树(Huffman Tree)C语言实现

    目录 一.哈夫曼树定义与原理 二.构建哈夫曼树 三.哈夫曼编码 完整代码: 前言:章末含c语言实现完整代码 一.哈夫曼树定义与原理 哈夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树.所谓树的带权 ...

  3. 三十、赫夫曼树的设计与代码实现

    一.基本介绍 给定 n 个权值作为 n 个叶子结点,构造一棵二叉树,若该树的带权路径长度(wpl)达到最小,称这样的二叉树为 最优二叉树,也称为哈夫曼树(Huffman Tree), 还有的书翻译为霍 ...

  4. 赫夫曼树建立c语言源程序编译结果详细解释,c语言构建哈夫曼树(附运行结果图)[本站推荐]...

    #include#include#include int m,s1,s2; typedef struct { unsigned int weight; unsigned int parent,lchi ...

  5. 哈夫曼树【最优二叉树】【Huffman】

    [转载]只为让价值共享,如有侵权敬请见谅! 一.哈夫曼树的概念和定义 什么是哈夫曼树? 让我们先举一个例子. 判定树: 在很多问题的处理过程中,需要进行大量的条件判断,这些判断结构的设计直接影响着程序 ...

  6. 【数据结构(25)】5.7 哈夫曼树及其应用

    文章目录 前言 一.哈夫曼树的基本概念 1. 哈夫曼树的特点 二.哈夫曼树的构造算法 1. 哈夫曼树的构造过程 2. 哈夫曼算法的实现 2.1 哈夫曼算法思路 2.2 哈夫曼算法实现 三.哈夫曼编码 ...

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

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

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

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

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

    一.哈夫曼树的基本概念 1) 路径: 从树中一个结点到另一个结点之间的分支构成这两个结点间的路径 2) 结点的路径长度: 两结点间路径上的分支数           3) 树的路径长度:从树根到每一个 ...

  10. 哈夫曼树及哈夫曼编码(考试常考版)

    哈夫曼树的基本概念 哈夫曼树的定义是对一组具有确定权值的叶子节点,选出最小带权路径长度的二叉树为哈夫曼树(WPL最小),也称最优二叉树 哈夫曼算法的实现 注意:哈夫曼树在构造时选择两个最小的权值点,默 ...

最新文章

  1. 3名游客在长城墙体上刻字,八达岭长城:已会同公安部门调查取证
  2. @ConfigurationProperties注解的使用与@Value的使用
  3. Linux kernel 3.10内核源码分析--进程退出exit_code
  4. 关于用 ABAP 代码手动触发 SAP CRM organization Model 自动决定的研究
  5. 使用 C# 代码实现拓扑排序
  6. 通过Blender将PMX模型转为FBX导入Unity
  7. 他受他爸影响,他爸受数学家影响,最终造出了自动旋转的房子!
  8. CentOS 6.2编译安装Nginx1.2.0+MySQL5.5.25+PHP5.3.13
  9. 九度OJ 1207 质因数的个数
  10. 多线程编程(1) - 认识等待函数 WaitForSingleObject
  11. 简单 常用的git命令
  12. apache 服务器修改网站默认首页
  13. 4775电子书免费链接
  14. 埃默里大学计算机值得读吗,埃默里大学计算机科学-生物统计学硕士研究生怎么样?好不好...
  15. 推荐一个简单好用的HTML编辑器
  16. CVPR 2019 论文最新汇总(按方向划分,0611 更新中)
  17. 【JavaWeb】JQuery实现广告显示和隐藏动画效果
  18. mdx格式的词典用什么软件打开_分享 | 手机词典推荐—欧陆词典(涵盖牛津、朗文等14部权威英语辞典)...
  19. 微服务网关和服务注册中心
  20. SEO的工作内容是什么?

热门文章

  1. Three.js 解决纹理渲染后模型为黑色
  2. 随机算法之最小割问题
  3. java异步调用外部接口
  4. 达梦查询计算百分比数据为零
  5. C4 模型 - 可视化架构设计
  6. 面试:前端需要注意哪些SEO
  7. 管易云·奇门对接打通金蝶云星空历史订单查询接口与销售出库新增接口
  8. python 立体图 交叉 平面_如何绘制相交平面?
  9. C#值类型-引用类型
  10. 劳动保障部-目前已颁布的国家职业标准名称