1.什么是赫夫曼树:

给定N个权值作为N个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。

2.示意图

3.名词概念:

路径和路径长度

在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径。通路中分支的数目称为路径长度。若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1。

结点的权及带权路径长度

若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。

树的带权路径长度

树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为WPL。

权值越大的结点距离根结点越近的二叉树才是最优二叉树

wpl最小的就是赫夫曼树

4.需求:

给定一个数列{13,7,8,29,6,1}要求转成一颗赫夫曼树。

5.思路分析:

  1. 从小到大进行排序,每个数据都是一个节点,每个结点可以看成是一颗简单的二叉树
  2. 取出根结点最小的两颗二叉树
  3. 组成一颗新的二叉树,该新的二叉树根结点权值是前面两颗二叉树节点权值之和。
  4. 将这颗新的二叉树以根结点的权值大小再次排序,不断重复以上步骤,直到数列中所有的数据被处理,即可得到一颗赫夫曼树

6.代码实现:

package huffman;/*** @author WuChenGuang*/
public class Node implements Comparable<Node> {public int value;public Node left;public Node right;public Node(int value) {this.value = value;}@Overridepublic int compareTo(Node node) {return this.value - node.value;}/*** 前序遍历*/public void preSelect() {System.out.println(this);if (this.left != null) {this.left.preSelect();}if (this.right != null) {this.right.preSelect();}}@Overridepublic String toString() {return "Node{" +"value=" + value +'}';}
}
package huffman;/*** @author WuChenGuang*/
public class NodeCode implements Comparable<NodeCode> {/*** 用来描述文字(字幕)十进制数*/public Byte data;public int weight;public NodeCode left;public NodeCode right;public NodeCode(Byte data, int weight) {this.data = data;this.weight = weight;}public NodeCode(int weight) {this.weight = weight;}@Overridepublic int compareTo(NodeCode o) {return this.weight - o.weight;}@Overridepublic String toString() {return "NodeCode{" +"data=" + data +", weight=" + weight +'}';}/*** 前序遍历*/public void preSelect() {System.out.println(this);if (this.left != null) {this.left.preSelect();}if (this.right != null) {this.right.preSelect();}}
}
package huffman;import java.util.*;/*** @author WuChenGuang*/
public class HuffmanCodes {/*** 1、需要统计字母所出现的次数* 2、创建赫夫曼树* 3、获取赫夫曼编码* 4、数据压缩*/private static final Map<Byte, String> HUFFMAN_CODE = new HashMap<>();private static final StringBuilder STRING_BUILDER = new StringBuilder();public static void main(String[] args) {String string = "I'm WuChenGuang. What's your name?";byte[] bytes = string.getBytes();List<NodeCode> nodeWeight = getNodeWeight(bytes);NodeCode root = createHuffmanTree(nodeWeight);Map<Byte, String> huffmanCodes = createHuffmanCodes(root);System.out.println("生成的赫夫曼编号:" + huffmanCodes);byte[] zip = zip(bytes, huffmanCodes);System.out.println("压缩后的数组:" + Arrays.toString(zip));byte[] decode = decode(HUFFMAN_CODE, zip);System.out.println(new String(decode));}public static byte[] decode(Map<Byte, String> huffmanCode, byte[] huffmanBytes) {StringBuilder stringBuilder = new StringBuilder();for (int i = 0; i < huffmanBytes.length; i++) {byte b = huffmanBytes[i];boolean flg = (i == huffmanBytes.length - 1);stringBuilder.append(byteToString(!flg, b));}Map<String, Byte> map = new HashMap<>();for (Map.Entry<Byte, String> entry : huffmanCode.entrySet()) {map.put(entry.getValue(), entry.getKey());}List<Byte> bytes = new ArrayList<>();for (int i = 0; i < stringBuilder.length(); ) {int count = 1;boolean flg = true;Byte b;while (flg) {String key = stringBuilder.substring(i, i + count);b = map.get(key);if (b == null) {count++;} else {flg = false;bytes.add(b);}}i += count;}byte[] buff = new byte[bytes.size()];for (int i = 0; i < buff.length; i++) {buff[i] = bytes.get(i);}return buff;}/*** 把文本-->二进制数组 ---->赫夫曼编码 二进制字符串 ----> 压缩数组* 如何把数据进行解压* [-52, -72, 5, 110, -73, -94, -81, -16, 61, -42, -107, 124, 100,78 , 0]*/public static String byteToString(boolean isRepair, byte b) {/*b: 占 8个二进制位int: 占32个二进制位正数时需要补高8位,负数的时候不需要补*/int temp = b;if (isRepair) {temp |= 256;}String string = Integer.toBinaryString(temp);if (isRepair) {return string.substring(string.length() - 8);} else {return string;}}/*** 统计字符串所出现的次数* 返回集合  [NodeCode{data=32,weight=4},NodeCode{data=33,weight=5}]*/public static List<NodeCode> getNodeWeight(byte[] bytes) {List<NodeCode> nodeCodes = new ArrayList<>();// 每一个byte出现的次数,使用一个map集合    key=byte,value=weightMap<Byte, Integer> counts = new HashMap<>();for (byte aByte : bytes) {Integer count = counts.get(aByte);if (count == null) {counts.put(aByte, 1);} else {counts.put(aByte, count + 1);}}/*把每一个map对象转Node对象,存放在集合中*/for (Map.Entry<Byte, Integer> entry : counts.entrySet()) {nodeCodes.add(new NodeCode(entry.getKey(), entry.getValue()));}return nodeCodes;}/*** 创建赫夫曼树*/public static NodeCode createHuffmanTree(List<NodeCode> nodeCodes) {/*循环处理*/while (nodeCodes.size() > 1) {// 排序  从小到大Collections.sort(nodeCodes);// 找到最小的两个元素(节点)NodeCode leftNode = nodeCodes.get(0);NodeCode rightNode = nodeCodes.get(1);// 两个最小节点weight相加,生成一个新的节点NodeCode root = new NodeCode(leftNode.weight + rightNode.weight);// 将新的节点作为父节点,构成一个新的二叉树root.left = leftNode;root.right = rightNode;nodeCodes.remove(leftNode);nodeCodes.remove(rightNode);nodeCodes.add(root);}return nodeCodes.get(0);}/*** 获取赫夫曼编码* 1. 往左取0 ,往右取1* a:101* b:01000* <p>* 完整赫夫曼编码  10101000* StringBuilder codes :用来拼接完整的赫夫曼编码* Map 用来存储叶子结点路径 key=32  value 101        (32,101),(33,01000)*/public static void getHuffmanCode(NodeCode nodeCode, String code, StringBuilder stringBuilder) {StringBuilder newString = new StringBuilder(stringBuilder);newString.append(code);if (nodeCode != null) {if (nodeCode.data == null) {//向左递归getHuffmanCode(nodeCode.left, "0", newString);//向右递归getHuffmanCode(nodeCode.right, "1", newString);} else {HUFFMAN_CODE.put(nodeCode.data, newString.toString());}}}/*** 设置统一入口*/public static Map<Byte, String> createHuffmanCodes(NodeCode root) {if (root == null) {return null;}// 处理左子树getHuffmanCode(root.left, "0", STRING_BUILDER);// 处理右子树getHuffmanCode(root.right, "1", STRING_BUILDER);return HUFFMAN_CODE;}/*** 数据压缩*/public static byte[] zip(byte[] bytes, Map<Byte, String> huffmanCode) {// 用来拼接所有叶子节点路径StringBuilder stringBuilder = new StringBuilder();for (byte b : bytes) {stringBuilder.append(huffmanCode.get(b));}System.out.println(stringBuilder.toString());int length;if (stringBuilder.length() % 8 == 0) {length = stringBuilder.length() / 8;} else {length = stringBuilder.length() / 8 + 1;}// 压缩数据的数组byte[] huffmanCodeBytes = new byte[length];int index = 0;for (int i = 0; i < stringBuilder.length(); i += 8) {String str;if (i + 8 > stringBuilder.length()) {str = stringBuilder.substring(i);} else {str = stringBuilder.substring(i, i + 8);}huffmanCodeBytes[index] = (byte) Integer.parseInt(str, 2);index++;}return huffmanCodeBytes;}}
package huffman;import java.util.ArrayList;
import java.util.Collections;
import java.util.List;/*** @author WuChenGuang*/
public class HuffmanTree {public static void main(String[] args) {int[] array = {13, 7, 8, 29, 6, 1};Node root = createHuffmanTree(array);preSelect(root);}/*** 把数列转赫夫曼树*/public static Node createHuffmanTree(int[] array) {/*1、遍历数组2、将每一个元素构成一个节点Node3、将Node放入到一个集合中并且已经是排序的,从小到大*/List<Node> nodes = new ArrayList<>();// 将元素转为Node对象for (int i : array) {nodes.add(new Node(i));}/*1.排序 从小到大2.取出最小的两个数    从集合   index:0  index:1Node newRoot = new Node(index:0+index:1)newRoot.left = index:0newRoot.right = index:1;nodes.remove(index:0);nodes.remove(index:1);nodes.add(newRoot);*/while (nodes.size() > 1) {// 排序  从小到大Collections.sort(nodes);System.out.println("集合中的元素: " + nodes);Node leftNode = nodes.get(0);Node rightNode = nodes.get(1);// 创建的新的结点Node root = new Node(leftNode.value + rightNode.value);root.left = leftNode;root.right = rightNode;nodes.remove(leftNode);nodes.remove(rightNode);//添加新的节点nodes.add(root);}return nodes.get(0);}/*** 前序遍历*/public static void preSelect(Node root) {if (root != null) {root.preSelect();} else {System.out.println("空树,无数据...");}}}

运行结果:

树结构之--赫夫曼树相关推荐

  1. 数据结构(十五)— 树结构之赫夫曼树及其应用

    现在我们都是讲究效率的社会,什么都要求速度, 在不能出错的情况下,做任何事情都讲究越快越好.在计算机和互联网技术中,文本压缩就是一个非常重要的技术. 玩电脑的人几乎都会应用压缩和解压缩软件来处理文档. ...

  2. 最优二叉树(赫夫曼树)

    赫夫曼树的介绍(写的不好地方大佬请指教) 最优二叉树又称哈夫曼树,是带权路径最短的二叉树.根据节点的个数,权值的不同,最优二叉树的形状也不同. 图 6-34 是 3 棵最优二叉树的例子,它们共同的特点 ...

  3. java振动数据压缩_【数据结构-Java】最佳实践-数据压缩(使用赫夫曼树)

    一.需求 将给出的一段文本,比如 "i like like like java do you like a java" , 根据前面的讲的赫夫曼编码原理,对其进行数据压缩处理 二. ...

  4. 赫夫曼编码(基于赫夫曼树的实现)

    上一篇文章中我们探讨了赫夫曼树的基本原理和构造方式,而赫夫曼编码可以很有效地压缩数据(通常可以节约20%-90%的空间,具体压缩率依赖于数据的特性). 名词:定长编码,边长编码,前缀码(装B用的) 定 ...

  5. 赫夫曼树(哈夫曼树)

    赫夫曼树->赫夫曼编码 在数据膨胀.信息爆炸的今天,数据压缩的意义不言而喻. 一个字节8位 赫夫曼编码压缩-无损压缩 可以看成成绩的排布.成绩是70-90之间占有70%,所以以下两个数据结构优化 ...

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

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

  7. php 二叉树 与赫夫曼树

    在学习图之前,中间休息了两天,感觉二叉树需要消化一下.所以中间去温习了下sql,推荐一本工具书<程序员的SQL金典>看名字不像一本好书,但是作为一个不错的SQL工具书还是可以小小备忘一下. ...

  8. 【赫夫曼树详解】赫夫曼树简介及java代码实现-数据结构07

    赫夫曼树(最优二叉树) 1. 简介 定义: 赫夫曼树是n个带权叶子结点构成的所有二叉树中,带权路径长度(WPL)最小的二叉树. 叶子结点的带权路径: 叶子结点权值*到根节点的路径长度(叶结点的层数) ...

  9. 算法系列之赫夫曼树的精解【构造流程及原理分析】

    赫夫曼树又称为最优树.最优二叉树 赫夫曼树百度百科 https://baike.baidu.com/item/%E5%93%88%E5%A4%AB%E6%9B%BC%E6%A0%91/2305769? ...

最新文章

  1. 【MyBatis学习01】宏观上把握MyBatis框架
  2. merge r语言daframe_R语言读取多个excel文件后合并:rbind/merge/cmd合并
  3. 鸿蒙系统明年上市巧,鸿蒙系统官网下载-鸿蒙系统官网下载手机版 v2.0下载-955游戏网...
  4. 二分查找/折半查找算法
  5. C++之类与对象(2)
  6. sql通用防注入程序php,sql通用防注入系统_PHP教程
  7. 03bash特性详解
  8. three.js使用OrbitControls.js控制几何体旋转、平移、缩放
  9. python脚本:检测字符串标识符
  10. office 打开wps乱_Word 打开WPS文档成乱码的解决方法
  11. 一个amp;quot;现象级amp;quot;大数据公司的蜕变
  12. 快快云安全,网站被劫持怎么办
  13. 计算机d盘可以格式化吗,能将电脑的D盘直接格式化了吗
  14. 3D扫描建模技术应该如何学习?来来来,看这里!
  15. 学习 Lisp 语言的相关书籍
  16. VC++深入详解学习笔记
  17. SQL Server 数据库之嵌套查询
  18. autocad网络服务器如何安装许可证,使用网络许可选项文件的步骤
  19. kaggle | 入门教程
  20. 中国无管道通风柜市场趋势报告、技术动态创新及市场预测

热门文章

  1. 重新将2016年诗词曲赋自选集制作成电子书
  2. 数字信号处理 --- 周期信号的三角函数表示 一(三角函数的性质和三角波的合成)
  3. 在微型计算机中l o是指,微机中的I/O设备是指_______。
  4. 加密社交通讯市场,为何一夜爆火?
  5. robot光线机器人安卓版_anki vector robot机器人下载-vector robot机器人app1.3.1 安卓版-东坡下载...
  6. 谷牛期权隐含波动率上升
  7. 世界是平的,都是骗人的
  8. Android 连接蓝牙扫码器 无输入框
  9. linux下的mnt/hgfs/的共享目录无法出现的解决方案
  10. 推荐阅读书籍《大象---thinking in UML》