基于最小优先级队列构造哈夫曼树 Java
2016-03-19 16:18
417 查看
哈夫曼编码是一种前缀编码,也就是说,它编码的字符,任何一个字符的编码都不是另一个字符的前缀,这使得对哈夫曼编码进行解码变得容易。而使得哈夫曼编码是前缀编码的关键就是哈夫曼树。哈夫曼树也正是本文要说的。哈夫曼树是一颗二叉树,在这棵树上,从父节点到左孩子节点的边被标为0,从父节点到右孩子节点的边被标为1,所有字符被编码为一个从根结点到叶子节点的路径上的所有01构成的位串,这保证了哈夫曼编码是前缀编码的性质,并且由此可知,离根越远的节点,编码需要的位数就越多。构造哈夫曼树的算法是一个贪心算法:
(1)首先对所有字符进行次数统计;
(2)取出其中最小的两个字符,作为一个新节点的左右孩子,新节点的次数就是其左右孩子节点的次数之后,然后把新节点插入原先有序的字符集中;
(3)重复第二步,直到最后只有一个元素为止。
由算法可知,那些出现次数少的字符,编码需要的位数少,那些出现次数多的字符,编码需要的位数多。因为编码所有字符需要的位数等于:
∑ni=1\sum_{i=1}^n字符i * 字符i的次数
所以,这样能保证编码编码所有字符需要的位数尽量少。而每次选择次数最少的字符(这些字符的节点离根结点最远)正是算法的贪心所在。
由算法还知道,我们需要不断地获得所有字符串中出现次数最少的,并把由抽取出来的节点合成的新节点放回去,这些特点决定该算法很适合用最小优先级队列来实现,优先级就是字符出现的次数。下图是算法导论中给出的构建哈夫曼树的伪代码:
![](http://img.blog.csdn.net/20160319160141841)
其中,C是待编码的字符集,Q是最小优先级队列。
对应的Java代码如下:
其中的Data类和Node类源码如下:
哈夫曼编码解码算法的完整实现的github地址如下:
https://github.com/l294265421/algorithms-huffman.git
(1)首先对所有字符进行次数统计;
(2)取出其中最小的两个字符,作为一个新节点的左右孩子,新节点的次数就是其左右孩子节点的次数之后,然后把新节点插入原先有序的字符集中;
(3)重复第二步,直到最后只有一个元素为止。
由算法可知,那些出现次数少的字符,编码需要的位数少,那些出现次数多的字符,编码需要的位数多。因为编码所有字符需要的位数等于:
∑ni=1\sum_{i=1}^n字符i * 字符i的次数
所以,这样能保证编码编码所有字符需要的位数尽量少。而每次选择次数最少的字符(这些字符的节点离根结点最远)正是算法的贪心所在。
由算法还知道,我们需要不断地获得所有字符串中出现次数最少的,并把由抽取出来的节点合成的新节点放回去,这些特点决定该算法很适合用最小优先级队列来实现,优先级就是字符出现的次数。下图是算法导论中给出的构建哈夫曼树的伪代码:
其中,C是待编码的字符集,Q是最小优先级队列。
对应的Java代码如下:
protected Node createTree(ArrayList<Node> letterList) { int n = letterList.size(); Node[] a = new Node ; letterList.toArray(a); MinPriorityQueue<Node> helper = new MinPriorityQueue<Node>(a, n); // 需要n-1步 for(int i = 1; i <= n - 1; i++) { Node left = helper.heapExtractMin(); Node right = helper.heapExtractMin(); Data data = new Data(); data.setFrequency(left.getData().getFrequency() + right.getData().getFrequency()); Node parent = new Node(); parent.setData(data); parent.setLeftChild(left); parent.setRightChild(right); helper.minHeapInsert(parent); } return helper.heapExtractMin(); }
其中的Data类和Node类源码如下:
public class Data implements Comparable<Data>{ private char c = 0; private int frequency = 0; public char getC() { return c; } public void setC(char c) { this.c = c; } public int getFrequency() { return frequency; } public void setFrequency(int frequency) { this.frequency = frequency; } @Override public String toString() { return "Data [c=" + c + ", frequency=" + frequency + "]"; } @Override public int compareTo(Data o) { if (this.frequency < o.getFrequency()) { return -1; } else if (this.frequency > o.getFrequency()) { return 1; } else { return 0; } } }
package com.liyuncong.algorithms.algorithms_huffman; public class Node implements Comparable<Node>{ private Node leftChild = null; private Data data = null; private Node rightChild = null; public Node getLeftChild() { return leftChild; } public void setLeftChild(Node leftChild) { this.leftChild = leftChild; } public Data getData() { return data; } public void setData(Data data) { this.data = data; } public Node getRightChild() { return rightChild; } public void setRightChild(Node rightChild) { this.rightChild = rightChild; } @Override public String toString() { return "Node [leftChild=" + leftChild + ", data=" + data + ", rightChild=" + rightChild + "]"; } @Override public int compareTo(Node o) { return this.data.compareTo(o.getData()); } }
哈夫曼编码解码算法的完整实现的github地址如下:
https://github.com/l294265421/algorithms-huffman.git
相关文章推荐
- java学习之在myclipse中利用jdbc连接数据库
- Java中private , public , protected 几个关键字
- java中的System.copyof()与Array.copyof()区别
- [1]java:你真的懂你的第一个Hello World程序吗
- 使用MyEclipse创建Maven项目出现的错误及解决方法
- java并发基础之The volatile keyword
- Java时间转换成ISO8601格林威治天文台的标准时间
- Eclipse开发STM32出现找不到函数的情况的解决方法
- [心得]Java开发中的小心得
- Java并发编程:Lock
- 深入理解Java之集合框架
- Spring Security 引用数据库管理用户权限-----login.jsp 提示"用户名或密码错误"
- 跟我学Spring3(8.2):对ORM的支持之集成Hibernate3
- Java线程池的测试和分析
- Eclipse加入PHP插件并支持PHP自动提示
- [MAVEN]一、maven入门之软件的下载及配置到Eclipse中
- Eclipse真机测试注意事项
- spring入门(12)-spring与hibernate整合完成增删改查的操作(继承HibernateDaoSupport调用hibernateTemplate类)
- spring入门(11)-spring与hibernate整合完成增删改查的操作(封装HibernateTemplate模版类对象)
- java中编码