huffman编码及解码实现
来源:互联网 发布:mac系统绘画软件 编辑:程序博客网 时间:2024/05/04 21:59
Huffman编码就是利用每个字符出现频率的不一致,用长短不一的0、1字节来表示不同的字符以减少总数据大小。 假设我们有一包含10000个字符的文件,这些字 符仅由6个不同的字符组成,就设这6个字符分别为“abcdef”,下面的表给出了 这6个字符在整个文件中的占比,和两种不同的编码方式。
上例中固定长度的编码方式最少需要三位。那么整个文件的长度大小为300,000 bits,而对于可变长度的编码方式其使用大小为:
(45 * 1 + 13 * 3 + 12 * 3 + 16 * 3 + 9 * 4 + 5 * 4) · 1,000 = 224,000 bits
使用第二种编码方式能比第一种方式节约大约25%的空间。上述变长编码的方式实 际上是一种名为前缀编码的编码方式。
赫夫曼编码是指赫夫曼提供的一种构建最优前缀编码的方法。其方法是总选取权 重最小的两个结点x和y合并成一个结点z,并用z代替它们,再从中选出两 个权重最小的结点。如是反复。图解:
网页 www.cs.nyu.edu/~melamed/courses/102/lectures/huffman.ppt 提供了更清楚的过程。
从上图中我们知道,我们需要创建二叉树来实现Huffman编码。因此,我们需要定义节点 Node 类。
//Huffman trie nodeclass Node{ char ch; int freq; Node left, right; Node(char ch, int freq, Node left, Node right) { this.ch = ch; this.freq = freq; this.left = left; this.right = right; } // is the node a leaf node? boolean isLeaf() { assert (left == null && right == null) || (left != null && right != null); return (left == null && right == null); }}
有了表示Node的类,我们需要得到每个字符出现的频率。这里,我们用一个大小为256的int数组来保存每个字符出现的频率。然后根据每个字符和它的频率创建Node对象,并把它保存到Priority Queue里。这样,我们就可以根据节点的频率来创建二叉树了。
二叉树创建完毕,我们就可以把每一个字符所对应的编码找出来。
public String[] compress(String in) { char[] input = in.toCharArray(); // get the frequency counts int[] freq = new int[R]; for (int i = 0; i < input.length; i++) freq[input[i]]++; // initialze priority queuePriorityQueue<Node> pq = new PriorityQueue<Node>(11, new Comparator<Node>() { public int compare(Node n1, Node n2) { return n1.freq - n2.freq; } }); // insert the node into priority queue for (char i = 0; i < R; i++) if (freq[i] > 0) pq.add(new Node(i, freq[i], null, null)); // merge two smallest trees while (pq.size() > 1) { Node left = pq.poll(); Node right = pq.poll(); Node parent = new Node('\0', left.freq + right.freq, left, right); pq.add(parent); } Node root = pq.poll(); // build code table String[] table = new String[R]; buildCode(table, root, ""); return table;}
// make a lookup table from symbols and their encodingspublic void buildCode(String[] st, Node x, String s) { if (!x.isLeaf()) { buildCode(st, x.left, s + '0'); buildCode(st, x.right, s + '1'); } else { st[x.ch] = s; }}
一旦得到了查询表,我们就可以把原始字符串进行编码了。那么,如何对编码进行解码呢?
要对编码进行解码,我们需要利用编码时生成的二叉树。首先我们先从root节点开始,如果编码为0,我们从左走,否则向右走,当遇到叶子节点,我们就把所对应的字符输出来就可以了, 然后再次回到根节点。
public void decode(Node root, Node node, String encoding, StringBuilder sb) {if (encoding.equals("")) return;if (encoding.charAt(0) == '0') {node = node.left;} else {node = node.right;}if (node.isLeaf()) {sb.append(node.ch);node = root; }decode(root, node, encoding.substring(1), sb);}
参考:http://algs4.cs.princeton.edu/55compression/Huffman.java.htmlhttp://www.roading.org
- huffman编码及解码实现
- Haskell实现Huffman编码解码
- C#实现Huffman编码和解码
- Huffman编码与解码的实现
- Huffman编码与解码_C语言实现
- Java实现-Huffman编码与解码
- huffman编码与解码
- huffman编码与解码
- Huffman编码解码
- Huffman编码与解码
- Huffman编码解码
- huffman编码与解码
- 怎么实现huffman(哈夫曼编码)以及解码
- Huffman树实现与应用(编码解码压缩解压缩)
- 利用Huffman树进行文本编码解码的实现
- huffman编码解码与huffman树
- Huffman树及编码C++实现
- Huffman树及编码的实现
- 获取进程路径
- cocos2d-x游戏实例 《简单棋》入门尝试(五) 玩家控制效果的实现
- how to install xenomai(and some comments)
- 【D3D11游戏编程】学习笔记二十一:Cube Mapping及其应用之一:天空盒的实现
- Secret of the JavaScript Ninja 学习笔记 - 1
- huffman编码及解码实现
- leetcode 71: Substring with Concatenation of All Words
- 微软认证考试70-461 Work with Data 数据处理 --27%比重--(5.5)
- ehcahce 的页面缓存 配置简单
- LeetCode3:Longest Substring Without Repeating Characters
- java 字符串 转数组 Java – How to convert String into Array
- C#中ref和out的使用小结
- ZOJ 2099 Frame PolygonalLine
- 谷歌如何通过安卓赚钱