哈夫曼编码,是一种可变字长编码(VLC)的高效算法。该算法是Huffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长度最短的码字,有时称之为最佳编码。

相比定长编码来说,这种编码实现的压缩率(衡量压缩算法效率的重要指标)非常高,也就是说,哈夫曼编码比定长编码占用更少的存储空间。

假设我们要对某个字母表创建一套二进制前缀码,那么我们一般都会讲字母表中的字符与二进制的叶子联系起来,树中所有的左向边都为0,右向边都为1.可以通过记录根到字符叶子的简单路径上的标记来获得一个字符的代码字。这样任何一棵这样的树都可以生成一套前缀码。但是我们都知道即使在英文单词中,每个字母出现的概率都是不同的,如果仅仅是放到二叉树中,对于一些高频字符很可能需要更长的代码串来表示,这是非常不友好的。

一个方法就是通过根据字符出现的概率,尽可能将短位串分配给高频字符,长位串分配给低频字符。这里就用到了贪婪思想。

思路:

1. 初始化n个单节点的数,表上字母表中的字符,并将其概率记录,用来表示权重。

2. 找出两颗权重最小的树(对于权重都相同的树,任选其一),将它们作为新树中的左右子树,并将权值之和记录到新的树根中。迭代这一步操作,直到剩下一棵单独的树。

以下面的例子来描述哈夫曼树的构造过程:

字符 A B C D _
出现概率 0.35 0.1 0.2 0.2 0.15

由上面的过程我们得到了下面的代码字:

字符 A B C D _
出现概率 0.35 0.1 0.2 0.2 0.15
代码字 11 100 00 01

101

Input:

5

A B C D _

35 10 20 20 15

Output:

A : 11

B : 100

C : 00

D : 01

_ : 101

完整代码如下:

import java.util.Scanner;
public class Main {//建立数的节点类static class Node{int weight;//频数int parent;int leftChild;int rightChild;public Node(int weight, int parent, int leftChild, int rightChild){this.weight = weight;this.parent = parent;this.leftChild = leftChild;this.rightChild = rightChild;}void setWeight(int weight){this.weight = weight;}void setParent(int parent){this.parent = parent;}void setLeftChild(int leftChild){this.leftChild = leftChild;}void setRightChild(int rightChild){this.rightChild = rightChild;}int getWeight(){return weight;}int getParent(){return parent;}int getLeftChild(){return leftChild;}int getRightChild(){return rightChild;}}//新建哈夫曼编码static class NodeCode {String character;String code;NodeCode(String character, String code) {this.character = character;this.code = code;}NodeCode(String code) {this.code = code;}void setCharacter(String character) {this.character = character;}void setCode(String code) {this.code = code;}String getCharacter() {return character;}String getCode() {return code;}}//初始化一个哈弗曼树public static void initHuffmanTree(Node[] huffmanTree, int m){for(int i = 0; i < m; i++){huffmanTree[i] = new Node(0, -1, -1, -1);}}//初始化编码public static void initHuffmanCode(NodeCode[] huffmanCode, int n){for(int i = 0; i < n; i++){huffmanCode[i] = new NodeCode("","");}}//获取huffmanCode的符号public static void getHuffmanCode(NodeCode[] huffmanCode, int n){Scanner input = new Scanner(System.in);for(int i = 0; i < n; i++){String temp = input.next();huffmanCode[i] = new NodeCode(temp,"");}}//获取频率public static void getHuffmanWeight(Node[] huffmanTree , int n){Scanner input = new Scanner(System.in);for(int i = 0; i < n;i ++){int temp = input.nextInt();huffmanTree[i] = new Node(temp, -1, -1, -1);}}//选取两个较小的结点public static int[] selectMin(Node[] huffmanTree ,int n) {int min[] = new int[2];class TempNode {int newWeight;//存储权int place;//存储该结点所在的位置TempNode(int newWeight, int place){this.newWeight = newWeight;this.place = place;}void setNewWeight(int newWeight){this.newWeight = newWeight;}void setPlace(int place){this.place = place;}int getNewWeight(){return newWeight;}int getPlace(){return place;}}TempNode[] tempTree = new TempNode[n];//将huffmanTree中没有双亲的结点存储到tempTree中int i=0,j=0;for(i = 0; i < n; i++) {if(huffmanTree[i].getParent() == -1 && huffmanTree[i].getWeight()!=0) {tempTree[j] = new TempNode(huffmanTree[i].getWeight(),i);j++;}}int m1,m2;m1 = m2 = 0;for(i = 0; i < j; i++) {if(tempTree[i].getNewWeight() < tempTree[m1].getNewWeight())//此处不让取到相等,是因为结点中有相同权值的时候,m1取最前的m1 = i;}for(i = 0; i < j; i++) {if(m1 == m2)m2++;//当m1在第一个位置的时候,m2向后移一位if(tempTree[i].getNewWeight() <= tempTree[m2].getNewWeight() && i != m1)//此处取到相等,是让在结点中有相同的权值的时候,//m2取最后的那个。m2 = i;}min[0] = tempTree[m1].getPlace();min[1] = tempTree[m2].getPlace();return min;}//创建哈弗曼树public static void createHaffmanTree(Node[] huffmanTree,int n){if(n <= 1)System.out.println("Parameter Error!");int m = 2 * n - 1;//initHuffmanTree(huffmanTree,m);for(int i = n; i < m; i++) {int[] min = selectMin(huffmanTree, i);int min1 = min[0];int min2 = min[1];huffmanTree[min1].setParent(i);huffmanTree[min2].setParent(i);huffmanTree[i].setLeftChild(min1);huffmanTree[i].setRightChild(min2);huffmanTree[i].setWeight(huffmanTree[min1].getWeight() + huffmanTree[min2].getWeight());}}//创建哈夫曼编码public static void createHaffmanCode(Node[] huffmanTree,NodeCode[] huffmanCode,int n){Scanner input = new Scanner(System.in);char[] code = new char[10];int start;int c;int parent;int temp;code[n-1] = '0';for(int i = 0; i < n; i++){StringBuffer stringBuffer = new StringBuffer();start = n-1;c = i;while((parent=huffmanTree[c].getParent()) >= 0){start--;code[start] = ((huffmanTree[parent].getLeftChild() == c) ? '0' : '1');c = parent;}for(;start < n-1; start++){stringBuffer.append(code[start]);}huffmanCode[i].setCode(stringBuffer.toString());}}//输出public static void ouputHaffmanCode(NodeCode[] huffmanCode,int n){for(int i = 0; i < n; i++){System.out.println(huffmanCode[i].getCharacter() + " : " + huffmanCode[i].getCode());}}//主函数public static void main(String[] args){Scanner input = new Scanner(System.in);int n;int m;n = input.nextInt();m = 2*n-1;Node[] huffmanTree = new Node[m];NodeCode[] huffmanCode = new NodeCode[n];//初始化initHuffmanTree(huffmanTree, m);initHuffmanCode(huffmanCode, n);//获取符号getHuffmanCode(huffmanCode, n);//获取概率getHuffmanWeight(huffmanTree, n);//创建哈夫曼树createHaffmanTree(huffmanTree, n);//创建哈夫曼编码createHaffmanCode(huffmanTree, huffmanCode, n);//输出ouputHaffmanCode(huffmanCode, n);}
}

注意:输出哈夫曼树和输出哈夫曼编码时不同的操作。

贪婪算法在解决哈夫曼树及编码问题中的应用相关推荐

  1. 20172305 2018-2019-1 蓝墨云班课实验--哈夫曼树的编码

    20172305 2018-2019-1 蓝墨云班课实验--哈夫曼树的编码 实验要求 设有字符集:S={a,b,c,d,e,f,g,h,i,j,k,l,m,n.o.p.q,r,s,t,u,v,w,x, ...

  2. 优先级队列实现哈夫曼树的编码和译码

    //优先级队列实现的哈夫曼树的编码和译码 #include<iostream> #include<queue> #include<string> using nam ...

  3. 让人头疼的哈夫曼树与编码

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

  4. 20172328--蓝墨云班课实验--哈夫曼树的编码

    哈夫曼编码测试 任务详情 设有字符集:S={a,b,c,d,e,f,g,h,i,j,k,l,m,n.o.p.q,r,s,t,u,v,w,x,y,z}. 给定一个包含26个英文字母的文件,统计每个字符出 ...

  5. 哈夫曼树建树编码解码

    提示:昼短苦夜长,何不秉烛游! 文章目录 一.哈夫曼解析 1.手写哈夫曼树 2.为什么这样构成哈夫曼树? 路径 路径长度: 带权路径长度 树的最带权路径长度 哈夫曼树 二.构建哈夫曼树 三.哈夫曼树编 ...

  6. c语言赫夫曼树的编码与译码,哈夫曼树与编码译码实现

    一.哈弗曼树的基本概念. 哈夫曼树,又称最优树,是一类带权路径长度最短的树.下面有几个概念: (1)路径. 树中一个结点到另一个结点之间的分支构成这两个结点之间的路径. (2)路径长度. 路径上的分枝 ...

  7. java哈夫曼树编码_哈夫曼树的编码实验

    Java哈夫曼编码实验--哈夫曼树的建立,编码与解码 建树,造树,编码,解码 一.哈夫曼树编码介绍 1.哈夫曼树: (1)定义:假设有n个权值{w1, w2, ..., wn},试构造一棵含有n个叶子 ...

  8. 数据结构(六)霍夫曼树与编码

    1.算法流程 (1)构建霍夫曼树:自底向上 根据统计频率构建霍夫曼树: A.把所有的节点扔进排序队列queue中: B.从queue选择选择前面两个最小的元素a.b,把最小的树a作为左节点,把最小的b ...

  9. 【数据结构】赫夫曼树与编码

    赫夫曼树与赫夫曼编码 前言 赫夫曼树 存储结构 初始化树 构建树 赫夫曼编码 初始化编码 构建编码 前言 (概念) 路径:从一个节点到另一个节点的分支 路径长度:从一个节点到另一个节点的分支总数 节点 ...

最新文章

  1. 低锁单例模式D语言实现
  2. Failed to load resource: net::ERR_INSECURE_RESPONSE 问题解决记录
  3. java ee 博客园_JAVAEE 介绍
  4. 4.11-固件映像包 (FIP)
  5. python无法打开 firefox浏览器_【求助】pycharm不能打开火狐浏览器
  6. java基础---Calendar类
  7. ios UITableView默认选中第一行
  8. Python 网络数据采集
  9. mfc 子窗体 按钮不触发_python项目实战:pyQT5 实现窗体之间传值
  10. eigen 编译_四足机器人优化方法:Webots下Eigen与qpOASES非线性优化库环境搭建
  11. delphi 远程mysql_Delphi远程连接Mysql的实现方法
  12. Visual Studio使用ILDasm反汇编工具查看托管模块
  13. 草图大师SketchUp 2022 安装教程
  14. 微信支付宝扫码支付相关接口
  15. join and list删除 and set集合 and 深浅拷贝
  16. 初次跑CNN进行掌纹识别遇到的问题
  17. 实验三 mysql数据库与表的创建_实验二 数据库和表的创建与管理
  18. react antd Table 表格 td超出自动换行
  19. 删除矮人Dos目录argh
  20. 当IM和同学录走到一起

热门文章

  1. djano 字段不重复_Java 14 发布了,不使用quot;classquot;也能定义类了?还顺手要干掉Lombok!...
  2. mysql 多个实例 备份_Linux下安装Mysql多实例作为数据备份服务器实现多主到一从多实例的备份...
  3. 高级语言的编译过程和解释过程_进来了解一下C语言真正的编译过程看你掌握了吗?...
  4. linux ip隧道技术,linux之IP隧道配置
  5. debian 安装php gd2,如何在Debian Linux中为PHP安装Ioncube
  6. Java字符串性能优化
  7. MySQL 修改视图
  8. 安卓 linux找回内置存储,Android手机自带内部存储路径的获取
  9. 李航《统计学习方法》之HMM隐马尔可夫模型
  10. python编程理论_Python并发编程理论篇,来看看