计算机A想要给计算机B发送一串字符信息,需要将字符转成二进制编码才能发送,我们要知道在数据传输过程中,二进制数据越长不仅影响传输效率,而且出错率更高,所以我们需要用更短的二进制字符串来表示相同的字符信息。由于每个字符出现的频率是不一定相同的,所以我们应该要让字符出现频率越高的字符的编码越短,这样才能保证我们在发送的二进制数据最短,这就用到了我们今天要学的Huffman编码
要实现Huffman编码,我们首先得构建哈夫曼树,先了解几个相关概念:

  • 路径:在一棵树中,一个结点到另一个结点之间所经过的结点序列;
  • 路径长度:一条路径中,所经过的边数。如路径包含i个几点,路径长度为i-1,用lll表示;
  • 结点的权:给每个结点赋予的值,用www表示
  • 结点的带权路径长度:从根结点到当前结点的 路径长度*该结点的权值。
  • 树的带权路径长度:每个叶子结点的带权路径长度和:WPL=∑i=1nwiliWPL=\sum\limits_{i=1}^nw_il_iWPL=i=1∑n​wi​li​

哈夫曼树:在含有n个带权叶结点的二叉树中,其中带权路径长度(WPL)最小的二叉树。

根据WPL的定义,我们要构建一棵哈夫曼树,就应该让权值越小的结点离根结点越远。

  1. 从待合并结点中找到两个权值最小的结点,生成一个新节点,使找到的两个结点成为该节点的孩子结点,并使该结点的权值为找到的两个结点权值之和,然后将其纳入待合并结点;
  2. 重复执行1,直到只剩一个结点。


对应我们刚才提到的需求,要发送的字符就是需要待合并的结点,每个字符在消息中出现的频率就是该结点对应的频率,处理步骤:

  1. 读入信息,并记录每个字符在信息中出现的次数;
  2. 根据次数,建立哈夫曼树。

代码:

package day15;import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.stream.Collectors;public class Huffman {/*** An inner class for Huffman nodes.* */class HuffmanNode {/*** The char. Only valid for leaf nodes.*/char character;/*** Weight. It can also be double.*/int weight;/*** The left child.*/HuffmanNode leftChild;/*** The right child.*/HuffmanNode rightChild;/*** ********************** The first constructor.* ***********************/public HuffmanNode(char paraCharacter, int paraWeight, HuffmanNode paraLeftChild, HuffmanNode paraRightChild) {character = paraCharacter;weight = paraWeight;leftChild = paraLeftChild;rightChild = paraRightChild;}// Of HuffmanNode/*** To string.*/public String toString() {String resultString = "";return resultString;}// Of toSting}// Of class HuffmanNode/*** The number of characters. 256 for ASCII*/public static final int NUM_CHARS = 256;/*** The input text. It is stored in a string for simplicity.*/String inputText;/*** The length of alphabet,also the number of leaves.*/int alphabetLength;/*** The alphabet.*/char[] alphabet;/*** The count of chars. The length is 2*alphabetLength -1 to include non-leaf* nodes.*/int[] charCounts;/*** The mapping of chars to the indices in the alphabet.*/int[] charMapping;/*** Codes for each char in the alphabet. It should have the same length as* alphabet.*/String[] huffmanCodes;/*** All nodes. The last node is the root.*/HuffmanNode[] nodes;/*** ********************** The first constructor.* * @param paraFilename The text filename.***********************/public Huffman(String paraFilename) {charMapping = new int[NUM_CHARS];readText(paraFilename);}// Of the fist constructor/*** ********************** @Title: readText* @Description: TODO(Read text.)** @param paraFilename The filename.***********************/public void readText(String paraFilename) {try {inputText = Files.newBufferedReader(Paths.get(paraFilename), StandardCharsets.UTF_8).lines().collect(Collectors.joining("\n"));} catch (Exception ee) {System.out.println(ee);System.exit(0);} // Of trySystem.out.println("The text is:\r\n" + inputText);}// Of readText/*** ********************** @Title: constructAlphabet* @Description: TODO(Construct the alphabet. The results are stored in the*               member variables charMapping and alphabet)************************/public void constructAlphabet() {// Initialize.Arrays.fill(charMapping, -1);// The count for each char. At most NUM_VHARS chars.int[] tempCharCounts = new int[NUM_CHARS];// The index of the char in the ASCII charset.int tempCharIndex;// Step 1. Scan the string to obtain the counts.char tempChar;for (int i = 0; i < inputText.length(); i++) {tempChar = inputText.charAt(i);tempCharIndex = (int) tempChar;System.out.println("" + tempCharIndex + " ");tempCharCounts[tempCharIndex]++;} // Of for i// Step 2. Scan to determine the size of the alphabet.alphabetLength = 0;for (int i = 0; i < 255; i++) {if (tempCharCounts[i] > 0) {alphabetLength++;} // Of if} // Of for i// Step 3. Compress to the alphabetalphabet = new char[alphabetLength];charCounts = new int[2 * alphabetLength - 1];int tempCounter = 0;for (int i = 0; i < NUM_CHARS; i++) {if (tempCharCounts[i] > 0) {alphabet[tempCounter] = (char) i;charCounts[tempCounter] = tempCharCounts[i];charMapping[i] = tempCounter;tempCounter++;} // Of if} // Of for iSystem.out.println("The alphabet is: " + Arrays.toString(alphabet));System.out.println("Their counts are: " + Arrays.toString(charCounts));System.out.println("The char mappings are: " + Arrays.toString(charMapping));}// Of constructAlphabetpublic void constructTree() {// Step 1. Allocate space.nodes = new HuffmanNode[alphabetLength * 2 - 1];boolean[] tempProcessed = new boolean[alphabetLength * 2 - 1];// Step 2. Initialize leaves.for (int i = 0; i < alphabetLength; i++) {nodes[i] = new HuffmanNode(alphabet[i], charCounts[i], null, null);} // Of for i// Step 3. Construct the tree.int tempLeft, tempRight, tempMinimal;for (int i = alphabetLength; i < 2 * alphabetLength - 1; i++) {// Step 3.1 Select the first minimal as the left child.tempLeft = -1;tempMinimal = Integer.MAX_VALUE;for (int j = 0; j < i; j++) {if (tempProcessed[j]) {continue;} // Of ifif (tempMinimal > charCounts[j]) {tempMinimal = charCounts[j];tempLeft = j;} // Of if} // Of for jtempProcessed[tempLeft] = true;// Step 3.2 Select the second minimal as the right child.tempRight = -1;tempMinimal = Integer.MAX_VALUE;for (int j = 0; j < i; j++) {if (tempProcessed[j]) {continue;} // Of ifif (tempMinimal > charCounts[j]) {tempMinimal = charCounts[j];tempRight = j;} // Of if} // Of for jtempProcessed[tempRight] = true;System.out.println("Selecting " + i + " are " + tempLeft + " and " + tempRight);// Step 3.3 Construct the new node.charCounts[i] = charCounts[tempLeft] + charCounts[tempRight];nodes[i] = new HuffmanNode('*', charCounts[i], nodes[tempLeft], nodes[tempRight]);} // Of for i}// Of constructTree/*** ********************** @Title: getRoot* @Description: TODO(Get the root of the binary tree)** @return The root.***********************/public HuffmanNode getRoot() {return nodes[nodes.length - 1];}// Of getRoot/*** ********************** @Title: preOrderVisit* @Description: TODO(Pre-order visit)** @param paraNode***********************/public void preOrderVisit(HuffmanNode paraNode) {System.out.println("(" + paraNode.character + ", " + paraNode.weight + ")");if (paraNode.leftChild != null) {preOrderVisit(paraNode.leftChild);} // Of ifif (paraNode.rightChild != null) {preOrderVisit(paraNode.rightChild);} // Of if}// Of preOrderVisit/*** ********************** @Title: main* @Description: TODO(The entrance of program.)** @param args Not used now.***********************/public static void main(String args[]) {Huffman tempHuffman = new Huffman("F:/huffmantext-small.txt");tempHuffman.constructAlphabet();tempHuffman.constructTree();HuffmanNode tempRoot = tempHuffman.getRoot();System.out.println("The root is: " + tempRoot);System.out.println("Preorder visit:");tempHuffman.preOrderVisit(tempHuffman.getRoot());}// Of main
}// Of class Huffman

运行结果:

小结:
思路还是好理解的,难点在于代码中了几个数组来表示字符与频数、结点与索引之间的映射关系,数组多了处理的时候容易把自己绕进去,所以写代码的时候可以在旁边记录一下某个函数需要处理哪些数组,包括数组对应的语义是什么,方便思路混乱的时候查阅,当然如果用字典的话,思路会更清晰一些。今天在写这个算法的时候,又重新思考了一遍,浮现了许多奇奇怪怪的想法,对哈夫曼树有了新的理解,哈哈,不错。

Day15——Huffman编码之构建Huffman树相关推荐

  1. python实现huffman编码_Python实现huffman编码

    Huffman树建立,右大左小 如arr = [('a',15),('b',8),('c',6),('e',5),('e',3),('f',1)] Step1:根据values排序,生成:[('a', ...

  2. Huffman树与Huffman编码

    Huffman树与Huffman编码 问题描述 已知某系统在通信联络中只可能出现6种字符,其使用频度如下表所示: 根据Huffman编码原理,为6种字符设计一种Huffman编码方案. 算法分析与设计 ...

  3. huffman java_详解Huffman编码算法之Java实现

    Huffman编码介绍 Huffman编码处理的是字符以及字符对应的二进制的编码配对问题,分为编码和解码,目的是压缩字符对应的二进制数据长度.我们知道字符存贮和传输的时候都是二进制的(计算机只认识0/ ...

  4. huffman编码的程序流程图_Huffman编码实现压缩解压缩

    这是我们的课程中布置的作业.找一些资料将作业完毕,顺便将其写到博客,以后看起来也方便. 原理介绍 什么是Huffman压缩 Huffman( 哈夫曼 ) 算法在上世纪五十年代初提出来了,它是一种无损压 ...

  5. Huffman 编码的实现(C语言)

    Huffman 编码 具体原理及定义请百度,下面直接进行实现.具体实现过程是: 统计若干字符出现的频率,将其按频率(权重)升序存放进队列中,每次从队列中取两个结点合成一颗二叉树,这两个结点的根节点是取 ...

  6. Huffman编码算法之Java实现

    Huffman编码介绍 Huffman编码处理的是字符以及字符对应的二进制的编码配对问题,分为编码和解码,目的是压缩字符对应的二进制数据长度.我们知道字符存贮和传输的时候都是二进制的(计算机只认识0/ ...

  7. 数据结构:Huffman编码/译码系统

    目录 前言 相关说明 相关知识点 代码测试 编码系统 运行结果 运行后生成的文件 译码系统 运行结果​编辑 写入的文件 其他测试 打开输出Huffman树的开关 打开写入元素编码并打印相关的开关 前言 ...

  8. Huffman编码C实现

    赫夫曼树(Huffman Tree),又称最优二叉树,是一类带权路径长度最短的树.假设有n个权值{w1,w2,-,wn},如果构造一棵有n个叶子节点的二叉树,而这n个叶子节点的权值是{w1,w2,-, ...

  9. matlab完成信源编码译码,Huffman编码和译码的MATLAB实现.doc

    Huffman编码和译码的MATLAB实现.doc Huffman编码及译码的MATLAB实现 沈逸峰 (上海师范大学 信息与机电工程学院,上海 200333) 摘要:本论文首先介绍了Huffman编 ...

  10. Huffman编码文件压缩

    [问题描述] 编写一程序采用Huffman编码对一个正文文件进行压缩.具体压缩方法如下: 对正文文件中字符(换行字符''除外,不统计)按出现次数(即频率)进行统计 依据字符频率生成相应的Huffman ...

最新文章

  1. Python生物信息学⑥绘制热图及火山图
  2. pandas使用query函数查询指定日期索引之间对应的dataframe数据行(select rows date index between a certain date interval)
  3. SDE要素类导出为shp格式文件
  4. C# 关于委托和事件的妙文:通过一个例子详细介绍委托和事件的作用;Observer模式简介...
  5. KVM中Virtio网络的演化之路
  6. 山东春考计算机专科学校排名,山东春考本科专科学校有哪些
  7. python安装unittest_python 自动化测试 (一):安装 requests,unittest,HTMLTestRunner
  8. 利用FPGA实现外设通信接口之:利用FPGA实现USB 2.0通信接口
  9. linux 设备驱动程序开发 第3版_Chapter2_The Current Process
  10. nit计算机应用基础是考试大纲,全国计算机应用技术证书考试(NIT)考试大纲(计算机应用基础Windows XP)...
  11. 【渝粤题库】国家开放大学2021春2108刑法学(2)答案
  12. 验证方式二 html标签验证码,Django标签、转义及验证码生成
  13. Mac系统如何修复MAC硬盘权限
  14. 从副总裁做”表哥“说起
  15. 稀疏矩阵-sparse 存储和转换
  16. javamail课设_JavaMail简易教程
  17. 新点互联互通_新点驱动(江苏省互联互通版)
  18. MATLAB小波变换图像处理简单示例
  19. 皆爱高“淑商”女子——时代新词盘点
  20. MySQL ERROR 1709 (HY000)

热门文章

  1. 外卖cps返利定制开发源码平台小程序美团饿了么红包电影票券分销
  2. 计算机工程与应用出版时间,计算机工程与应用
  3. luci html 页面,luci界面修改
  4. 你知道strong和b;i和em的区别吗?
  5. uni-app个人中心页开发
  6. CVPR 2020 《Graph-Structured Referring Expression Reasoning in The Wild》论文笔记
  7. oracle按照拼音排序,ORACLE根据中文拼音首字母排序、取得中文拼音首字母函数
  8. dnsmasq-ipv6测试
  9. 智能管家---1.项目搭建
  10. UE4_虚幻引擎4多人联机基础知识和客户端服务器通信机制详解