目录

一、Huffman树(最优二叉树)

1、定义

2、构造

构造哈夫曼树的算法

哈夫曼树特点

二、Huffman编码


一、Huffman树(最优二叉树)

1、定义

树的带权路径长度,就是树中所有的叶节点的权值乘上其到根节点的路径长度。

在含有n 个带权叶结点的二叉树中,其中带权路径长度(WPL)最小的二叉树称为哈夫曼树, 也称最优二叉树。如图,c树的WPL=35最小,经验证其为哈夫曼树。

2、构造

构造哈夫曼树的算法

(给定n 个权值分别为wi的结点)

1)将这n个结点分别作为n棵仅含一个结点的二叉树,构成森林F。

2)构造一个新结点,从 F 中选取两棵根结点权值最小的树作为新结点的左、右子树,并且将新结点的权值置为左、右子树上根结点的权值之和。

3)从 F 中删除刚才选出的两棵树,同时将新得到的树加入F中。

4)重复步骤2)和 3), 直至F中只剩下一棵树为止。

//哈夫曼
class Node implements Comparable<Node> {Byte data;int weight;Node left;Node right;public Node(Byte data, int weight) {this.data = data;this.weight = weight;}@Overridepublic int compareTo(Node o) {return this.weight - o.weight;}@Overridepublic String toString() {return "Node  [ data = " + data + "weight = " + weight + " ]";}//遍历public void preOrder() {System.out.println(this);if (this.left != null) {this.left.preOrder();}if (this.right != null) {this.right.preOrder();}}
}
private static Node createHuffmanTree(List<Node> nodes) {/***@MethodName createHuffmanTree*@Description TODO 创建哈夫曼树*@Author SSRS*@Date 2020-10-31 13:21*@Param [nodes]*@ReturnType Java_note.Algorithm.HuffmanCode.Node*/while (nodes.size() > 1) {//排序Collections.sort(nodes);//取最小两个二叉树Node leftNode = nodes.get(0);Node rightNode = nodes.get(1);//创建新的二叉树(他的根节点没有data,只有权值)Node parent = new Node(null, leftNode.weight + rightNode.weight);parent.left = leftNode;parent.right = rightNode;//删除已用结点nodes.remove(leftNode);nodes.remove(rightNode);//加入新节点nodes.add(parent);}return nodes.get(0);
}

哈夫曼树特点

1)每个初始结点最终都成为叶结点,且权值越小的结点到根结点的路径长度越大。

2)构造过程中共新建了n-1个结点 (双分支结点),因此哈夫曼树的结点总数为2n- 1 。

3)每次构造都选择 2 棵树作为新结点的孩子,因此哈夫曼树中不存在度为1 的结点。

例如,权值{7, 5, 2, 4}的哈夫曼树的构造过程如图所示。

二、Huffman编码

在数据通信中,若对每个字符用相等长度的二进制位表示,称这种编码方式为固定长度编码。 若允许对不同字符用不等长的二进制位表示,则这种编码方式称为可变长度编码

可变长度编码 比固定长度编码要好得多,其特点是对频率高的字符赋以短编码,而对频率较低的字符则赋以较长一些的编码,从而可以使字符的平均编码长度减短,起到压缩数据的效果。哈夫曼编码是一种被广泛应用而且非常有效的数据压缩编码。

若没有一个编码是另一个编码的前缀,则称这样的编码为前缀编码。哈夫曼编码是前缀编码。

class HuffmanCode {public static void main(String[] args) {String str = "I like like like java Do you like a java";byte[] strBytes = str.getBytes();System.out.println(str + "的原长度是" + strBytes.length);HuffmanCode huffmanCode = new HuffmanCode();System.out.println("转成哈夫曼编码为:");String huffmanstr = huffmanCode.createHuffmanCode(strBytes);System.out.println(huffmanstr);System.out.println("其长度为:" + huffmanstr.getBytes().length);byte[] bytes = huffmanCode.zipbytes(strBytes);System.out.println("压缩后的结果是:" + Arrays.toString(bytes));System.out.println("其长度为:" + bytes.length);System.out.println("解压缩:" + new String(huffmanCode.rezip(bytes)));}private static List<Node> getNodes(byte[] bytes) {/***@MethodName getNodes*@Description TODO 获得构建哈夫曼树的Node*@Author SSRS*@Date 2020-10-31 13:07*@Param [bytes]*@ReturnType java.util.List<Java_note.Algorithm.HuffmanCode.Node>*/ArrayList<Node> nodes = new ArrayList<Node>();//要返回的nodes集合Map<Byte, Integer> counts = new HashMap<>();//统计每一个byte出现的次数for (byte b : bytes) {Integer count = counts.get(b);if (count == null) {counts.put(b, 1);} else {counts.put(b, count + 1);}}//把每一个键值对转换成Node对象,并加入nodes集合for (Map.Entry<Byte, Integer> each : counts.entrySet()) {nodes.add(new Node(each.getKey(), each.getValue()));}return nodes;}private static Node createHuffmanTree(List<Node> nodes) {/***@MethodName createHuffmanTree*@Description TODO 创建哈夫曼树*@Author SSRS*@Date 2020-10-31 13:21*@Param [nodes]*@ReturnType Java_note.Algorithm.HuffmanCode.Node*/while (nodes.size() > 1) {//排序Collections.sort(nodes);//取最小两个二叉树Node leftNode = nodes.get(0);Node rightNode = nodes.get(1);//创建新的二叉树(他的根节点没有data,只有权值)Node parent = new Node(null, leftNode.weight + rightNode.weight);parent.left = leftNode;parent.right = rightNode;//删除已用结点nodes.remove(leftNode);nodes.remove(rightNode);//加入新节点nodes.add(parent);}return nodes.get(0);}static Map<Byte, String> codes = new HashMap<Byte, String>();private static Map<Byte, String> getCodes(Map<Byte, String> codes, Node node, String code, StringBuilder stringBuilder) {StringBuilder stringBuilder1 = new StringBuilder(stringBuilder);stringBuilder1.append(code);if (node != null) {if (node.data == null) {getCodes(codes, node.left, "0", stringBuilder1);getCodes(codes, node.right, "1", stringBuilder1);} else {codes.put(node.data, stringBuilder1.toString());}}return codes;}private static byte[] bytesArrays(String string) {int len;//bytes数组长度if (string.length() % 8 == 0) {len = string.length() / 8;} else {len = string.length() / 8 + 1;}int index = 0;//bytes角标byte[] huffmanCodeBytes = new byte[len];for (int i = 0; i < string.length(); i += 8) {String strTemp;if (i + 8 > string.length()) {strTemp = string.substring(i);} else {strTemp = string.substring(i, i + 8);}//转换huffmanCodeBytes[index] = (byte) Integer.parseInt(strTemp, 2);index++;}return huffmanCodeBytes;}public static String createHuffmanCode(byte[] bytes) {/***@MethodName createHuffmanCode*@Description TODO 得到哈夫曼转码*@Author SSRS*@Date 2020-10-31 20:15*@Param [bytes]*@ReturnType java.lang.String*/Node root = createHuffmanTree(getNodes(bytes));StringBuilder stringBuilder = new StringBuilder();getCodes(codes, root, "", stringBuilder);String str = "";for (Byte each : bytes) {str += codes.get(each);}return str;}public byte[] zipbytes(byte[] bytes) {return bytesArrays(createHuffmanCode(bytes));}//解压缩private String byteToBitString(boolean flag, byte b) {/***@MethodName byteToBitString*@Description TODO 将一个byte转成二进制字符串*@Author SSRS*@Date 2020-10-31 20:56*@Param [flag 正数为true要补高位, b]*@ReturnType java.lang.String*/int temp = b;//转int//如果是正数还要补高位if (flag) {temp |= 256;//按位与 256 是 1 0000 0000 | 0000 0001=》1 0000 0001}String str = Integer.toBinaryString(temp);//返回的是二进制的补码if (flag) {return str.substring(str.length() - 8);} else {return str;}}public byte[] rezip(byte[] huffmanbytes) {StringBuilder stringBuilder = new StringBuilder();//储存二进制字符串//全部转成二进制字符串for (int i = 0; i < huffmanbytes.length; i++) {//如果是最后一个可能不满8位就转码的那个就不用补高位无论正负,因此要判断boolean flag = (i == huffmanbytes.length - 1);stringBuilder.append(byteToBitString(!flag, huffmanbytes[i]));}//把哈夫曼编码表反向Map<String, Byte> map = new HashMap<String, Byte>();for (Map.Entry<Byte, String> each : codes.entrySet()) {map.put(each.getValue(), each.getKey());}List<Byte> list = new ArrayList();//解压缩后的语句的储存位置for (int i = 0; i < stringBuilder.length(); ) {int count = 1;//计数,计每一个字符的二进制字符位数boolean flag = true;Byte b = null;//找字符对应哈夫曼编码while (flag) {String key = stringBuilder.substring(i, i + count);b = map.get(key);if (b == null) {count++;} else {//匹配成功flag = false;}}list.add(b);i = i + count;}byte b[] = new byte[list.size()];for (int i = 0; i < b.length; i++) {b[i] = list.get(i);}return b;}public void preOrder(Node root) {if (root != null) {root.preOrder();} else {System.out.println("二叉树为空。");}}
}

本文所有概念性描述及图示均来自王道考研数据结构一书

哈夫曼树(Huffman Tree)及哈夫曼编码(Huffman Coding)相关推荐

  1. 【数据结构与算法】-哈夫曼树(Huffman Tree)与哈夫曼编码

    超详细讲解哈夫曼树(Huffman Tree)以及哈夫曼编码的构造原理.方法,并用代码实现. 1哈夫曼树基本概念 路径:从树中一个结点到另一个结点之间的分支构成这两个结点间的路径. 结点的路径长度:两 ...

  2. 数据结构学习记录——哈夫曼树(什么是哈夫曼树、哈夫曼树的定义、哈夫曼树的构造、哈夫曼树的特点、哈夫曼编码)

    目录 什么是哈夫曼树 哈夫曼树的定义 哈夫曼树的构造 图解操作 代码实现 代码解析 哈夫曼树的特点 哈夫曼编码 不等长编码 二叉树用于编码 哈夫曼编码实例 什么是哈夫曼树 我们先举个例子: 要将百分制 ...

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

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

  4. 【算法学习笔记】哈夫曼树的构建和哈夫曼编码的实现代码

    介绍 哈夫曼(Haffman)这种方法的基本思想如下: ①由给定的n个权值{W1,W2,-,Wn}构造n棵只有一个叶子结点的二叉树,从而得到一个二叉树的集合F={T1,T2,-,Tn}. ②在F中选取 ...

  5. 数据结构C#版笔记--啥夫曼树(Huffman Tree)与啥夫曼编码(Huffman Encoding)

    哈夫曼树Huffman tree 又称最优完全二叉树,切入正题之前,先看几个定义 1.路径 Path 简单点讲,路径就是从一个指定节点走到另一个指定节点所经过的分支,比如下图中的红色分支(A-> ...

  6. 哈夫曼树的创建和哈夫曼树编码及解码

    #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #include<string. ...

  7. 哈夫曼树的生成及哈夫曼编码

    首先构造哈夫曼树结构体,初始化哈夫曼树的四个无符号整型域,输入文本,统计各个字符的权值,然后构建哈夫曼树,从根到叶子逆向求哈夫曼树的编码. #include"stdio.h" #i ...

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

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

  9. 哈夫曼树的构建及哈夫曼树编码

    哈夫曼树的构建: 注意:(1).首先把一组数3 5 6 8 9 12 15从小到大排列 (2).选取里面最小2个,顶点出为2个数的和 (3).新产生的顶点在与原先的数字进行比较,在里面选取2个最小的数 ...

  10. 【哈夫曼树】牛客 哈夫曼树

    题目描述 哈夫曼树,第一行输入一个数n,表示叶结点的个数.需要用这些叶结点生成哈夫曼树,根据哈夫曼树的概念,这些结点有权值,即weight,题目需要输出所有结点的值与权值的乘积之和. 输入描述: 输入 ...

最新文章

  1. Tips5:通过 alt+鼠标左键 来完全展开或收缩层级
  2. 《C语言课程设计》一第3章 文 件 类
  3. HTML语言:经典笔记(ZT)
  4. java equals() 函数_java equals()函数与‘==’
  5. ABP入门系列(3)——领域层定义仓储并实现
  6. C#中的套接字编程(一) --转
  7. DataGrid的多行提交
  8. 如何证明CPU的乱序执行(Out-of-order Execution)?
  9. 推荐微信小程序常用的几个UI组
  10. Python——百度识图-相似图片爬虫下载解决方案
  11. Unity获取摄像机的视口区域(透视相机模式)
  12. 搜索引擎使用技巧之高级搜索
  13. 科学计算机统计说明书,科学计算机带哪些功能_科学计算机怎么用_科学计算机使用方法...
  14. 电脑文件自动备份云服务器,电脑文件自动备份云服务器
  15. 三峡学院计算机调剂,2018年重庆三峡学院考研预调剂信息公布
  16. 软件架构设计---软件架构视图
  17. android修改虚拟内存(方法)
  18. LeetCode——1849. 将字符串拆分为递减的连续值(Splitting a String Into Descending Consecutive Val..)[中等]——分析及代码(Java)
  19. 100块钱买100只鸡的故事
  20. 大数据平台安装实验: ZooKeeper、Kafka、Hadoop、Hbase、Hive、Scala、Spark、Storm

热门文章

  1. CSS 样式实现单边阴影
  2. Python爬取网易云音乐评论,反爬算啥啊!
  3. 企业内容管理(ECM)与文档管理的区别及其优势
  4. HTML5期末大作业:餐饮饮食美食主题网站设计——重庆火锅(5页) HTML+CSS+JavaScript 学生DW网页设计作业成品 web课程设计网页规划与设计 web学生网页设计作业源码...
  5. 想知道有哪些缩小视频大小的软件?这几个压缩软件你该知道
  6. 真的!!!两行css代码实现瀑布流,html,css最简单的瀑布流实现方式且没有缺点!...
  7. unity+Cardboard SDK VR开发Cardboard Unity SDK讲解
  8. 理解 Web 3 —— 用户控制的互联网
  9. 转载 锁机制与原子操作 第四篇
  10. 优化算法+神经网络:神经网络自动参数优化