哈夫曼树构造以及代码实现

  • 什么是哈夫曼树
  • 理解哈夫曼树
  • 哈夫曼树的构造
  • 哈夫曼树构造-代码实现

什么是哈夫曼树

构造一颗二叉树,该树的带权路径长度达到最小,称为最优二叉树,也称为哈夫曼树(Huffman Tree)

注:带权路径长度就是下文提到的树的编码长度

理解哈夫曼树

为了更深理解哈夫曼树的由来,我们先来举个例子一步一步引入哈弗曼树是如何解决编码问题的

假设有一串字符,包含abcdefg这几个字符,每个字符出现的频次不同,如图:

先来思考一下,给定一段字符串,如何对字符串进行编码可以使得字符串的编码存储空间最少?

假如一段文本中,有58个字符,那么,
用ASCII编码:58 x 8 = 464位
用等长3位编码:58 x 3 = 174位
用不等长编码:出现频次高的字符用的编码短些,出现频次低的编码长些

那么我们重新计算一下编码长度,如下图:

10x3+15x2+12x2+3x5+4x4+13x2+1x5=146位,算完以后,是不是占用存储空间小了很多,但这还不是最小的,那么有什么办法可以使得字符编码的存储空间最小呢?答:二叉树

二叉树进行编码
将二叉树的左右分支设置为0和1,可以将频次高低不同的字符进行字符编码,如图,是4个频次最高的字符

经过字符重新编码以后,
b 编码 0
f 编码 1
c 编码 10
a 编码 11

思考:不等长编码容易出现什么问题?
举例:1011是什么字符串的编码呢?
如图,1011可以代表以下这几种字符组合的可能,容易出现二义性,

那么,如何避免二义性?
答:字符只在叶子节点上就不会有二义性,如图:


这样10只能是f,11只能是b,具有唯一性

那么问题来了,我们怎么解决不等长问题的空间存储最小呢?终于说到哈夫曼树了

哈夫曼树的构造

  • 每次把权值最小的两棵二叉树合并;
  • 左节点权值比右节点小

构造步骤如图:




看步骤(6)中就是最终构造的哈夫曼树了,所有节点都在叶子节点上,
也是带权路径长度最小的了,用每个节点的值和距离根节点的深度相乘再将值加起来,就是我们上文例子中算出来的值10x3+15x2+12x2+3x5+4x4+13x2+1x5=146位

哈夫曼树构造-代码实现

/*** 哈夫曼树*/public class HuffmanTree {//节点public static class Node<E> {E data; //数据int weight; //权重Node leftChild; //左子节点Node rightChild;//右子节点public Node(E data, int weight) {super();this.data = data;this.weight = weight;}public String toString() {return "Node[" + weight + ",data=" + data + "]";}}public static void main(String[] args) {List<Node> nodes = new ArrayList<Node>();//把节点加入至list中nodes.add(new Node("a", 10));nodes.add(new Node("b", 15));nodes.add(new Node("c", 12));nodes.add(new Node("d", 3));nodes.add(new Node("e", 4));nodes.add(new Node("f", 13));nodes.add(new Node("g", 1));//进行哈夫曼树的构造Node root = HuffmanTree.createTree(nodes);//打印哈夫曼树printTree(root);}/*** 构造哈夫曼树** @param nodes*            节点集合* @return 构造出来的哈夫曼树的根节点*/private static Node createTree(List<Node> nodes) {//如果节点node列表中海油2个和2个以上的节点while(nodes.size()>1){//什么是最小的,list表进行排序,增序的方式, 0,1,sort(nodes);//排序方式是增序的Node left = nodes.get(0);//权重最小的Node right = nodes.get(1);//权重第二小的//生成一个新的节点(父节点),父节点的权重为两个子节点的之和Node parent = new Node(null,left.weight+right.weight);//树的连接,让子节点与父节点进行连接parent.leftChild = left;parent.rightChild = right;nodes.remove(0);//删除最小的nodes.remove(0);//删除第二小的。nodes.add(parent);}return nodes.get(0); //返回根节点}/*** 冒泡排序,用于对节点进行排序(增序排序)** @param nodes*/public static void sort(List<Node> nodes) {if (nodes.size() <= 1)return ;/*循环数组长度的次数*/for (int i = 0; i < nodes.size(); i++){/*从第0个元素开始,依次和后面的元素进行比较* j < array.length - 1 - i表示第[array.length - 1 - i]* 个元素已经冒泡到了合适的位置,无需进行比较,可以减少比较次数*/for (int j = 0; j < nodes.size() - 1 - i; j++){/*如果第j个节点比后面的第j+1节点权重大,交换两者的位置*/if (nodes.get(j + 1).weight < nodes.get(j).weight) {Node temp = nodes.get(j + 1);nodes.set(j+1,nodes.get(j));nodes.set(j,temp);}}}return ;}/** 递归打印哈夫曼树(先左子树,后右子树打印)*/public static void printTree(Node root) {System.out.println(root.toString());if(root.leftChild !=null){System.out.print("left:");printTree(root.leftChild);}if(root.rightChild !=null){System.out.print("right:");printTree(root.rightChild);}}
}

哈夫曼树构造以及代码实现相关推荐

  1. c语言哈夫曼树构造代码

    c语言哈夫曼树构造代码 博主就很掘的一个人,最近学哈夫曼树,想着用指针去实现,觉得用指针实现,内存消耗会更少,写到后面发现越来与麻烦,且内存开销并没有减少,于是还是使用结构体数组中规中矩的去实现哈夫曼 ...

  2. 哈夫曼树构造哈夫曼编码

    在传输文字时,经常要将文字转换成二进制字符串.所以我们希望编码最短,但是又想保证它的唯一性.哈夫曼树具有最小带权路径长度,用来实现编码就可以编码最短,所以用哈夫曼树来构造编码.而前缀编码就可以保证在解 ...

  3. 算法学习笔记10——应用哈夫曼树构造最短的不等长编码方案

    内容: (1)设需要编码的字符集为{d1, d2, -, dn},它们出现的频率为{w1, w2, -, wn},应用哈夫曼树构造最短的不等长编码方案. 提示: 哈夫曼树(Huffman Tree), ...

  4. 最小堆实现哈夫曼树构造

    0. 序 本以为用最小堆实现个哈夫曼树是个简单的事情,结果一不小心就花了好几个小时才写完...实现过程中主要有三个方面的问题没注意,导致花了很多时间进行调试. 一是多重指针malloc分配时要多加注意 ...

  5. 哈夫曼树构造算法的正确性证明

    哈夫曼树构造 1.哈夫曼树的定义 给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman tree). 2.哈夫曼树的构造 假 ...

  6. 【Lua】哈夫曼树构造算法的分析与实现

    哈夫曼树构造算法分析 1.哈夫曼树中权重越大的叶子离根越近,采用贪心算法构造哈夫曼树,首先选中权重值小的叶子结点进行构造 2.步骤 构造森林全是根:根据n个给定结点的权重值{W1, W2-Wn}构成 ...

  7. C语言:哈夫曼树构造及编码(核心代码每一行都有注释)

    一.[实验目的及要求] 理解Huffman树的概念及其存储结构: 熟悉Huffman树的构造: 掌握Huffman树的编码方法. 二.[实验内容] 1.代码实现Huffman编码 2.请统计每个字符出 ...

  8. 数据结构 C 代码 6.2: 哈夫曼树 (学生提供代码)

    总有能力强的学生, 两个小时就可以完成我当年本科毕业设计的核心代码. 任务描述: 从文件中读文本; 统计字符频次, 并建立字母表; 构造 Huffman 树; 将文本编码; 解码. 1. 涂然的版本 ...

  9. 哈夫曼树构造算法的实现

    先考虑如何存储:既可以链式也可以顺序,但顺序存储结构(数组)简单点 这里用一维结构数组,结构数组是因为我们要保存的结点的值比较多,先看结点的类型定义 那几个值?每一个都要知道他的权值weight是多少 ...

最新文章

  1. oracle如何添加非空约束,oracle 怎么用sql删除非空约束?
  2. 系统架构师-基础到企业应用架构-表现层
  3. 黑箱方法 支持向量机①
  4. linux monitor模式,ubuntu14.04 安装linux-802.11n csitool Monitor模式
  5. Vue中父组件调用子组件的方法
  6. “约见”面试官系列之常见面试题第十五篇之jsonp(建议收藏)
  7. Python Text I/O
  8. 13.无名管道通讯编程
  9. Eclipse启动Tomcat时45秒超时的解决方法
  10. Zookeeper概念介绍
  11. Immutable 操作在 React 中的实践
  12. spring事务失效场景三:内部方法调用
  13. 【转载】读透《哥德尔、艾舍尔、巴赫:集异璧之大成》
  14. vba 抓取php网页,用VBA操作网页并抓取数据
  15. 一文搞懂什么是禁忌搜索算法Tabu Search【附应用举例】
  16. Linux数据结构之radix-tree
  17. c语言将大小写字母互换,C语言编程:大小写互换
  18. 沃趣赵晨 | 从技术岗位到产品经理:漫谈IT产品经理的生存之道
  19. jacob根据word模板生成文
  20. echarts 省市区联动地图

热门文章

  1. 学习笔记0326----vim编辑器的使用
  2. 一文读懂:十大DNA甲基化研究核心问题
  3. Android逆向 微信小游戏破解(一):我要当皇上满级修改
  4. Javascript 实现[网红] 时间轮盘
  5. Android 13 内置搜狗输入并设置默认输入法
  6. LINUX C编程中_REENTRANT宏的作用
  7. 19 南京区域赛 F. Paper Grading
  8. 【Linux】ubuntu使用aptitude命令替换apt-get
  9. python定义字符串数组初始化_字符数组及其定义和初始化,C语言字符数组详解...
  10. SMT的基本知识简介