[注:本文仅供学习和参考,拷贝等引起的后果自负!]
Huffman编码的JAVA实现
(这里算法就不给出了,有兴趣的读者可以参考相关书籍,这里只给出JAVA实现的思路,仅供参考,毕竟水平有限)。
该实验降低了复杂度,仅仅研究二元码,不考虑的编码,所以不存在引入虚拟符的问题;同时考虑到需要用到数据结构的知识且为了记录概率和编码Code,修改了Node节点中存放的信息(节点存放key, 左、右节点,概率和编码,具体修改方法见代码部分),在获得Code时,采用了前序遍历的策略。
对于二元Huffman码的编码如何获得,如何编写JAVA代码的流程如下:
1. 定义两个动态数组(ArrayList()类中的方法)来存放所将建立的树tree(这些节点存在着二叉树的关系)、节点node(该数组用来存放节点,这些节点之间不存在关系);
2. 将node中的节点进行sort排序(按照概率),之后选择最小的两个(与此同时生成一个root,也就是它两的根),并将其放入tree中,并将root放入node,中,并且在node中删除原有的两个节点。循环此步骤,直至node的长度为1(意味着概率之和已经为1);
3. 步骤2得到了一个tree,该数组中最后一个就是root,采用前序遍历的方法,对每个节点的Code进行赋值,前序遍历完就意味着码字生成了;
4. 对于tree中节点的key,若其有含义(是要进行编码的随机变量),则将其Code输出,也就是它的Huffman编码。
运行结果:
与预期结果一致;
参考文献
1. THOMAS M. COVER, JOY A. THOMAS. Element of Information Theory. Second Edition.
2. MICHAEL T. GOODRICH, ROBERTO TRMASSIA. Data Structures and Algorithms in Java. Fifth Edition.
参考程序如下。
Node.java
public class Node { private String key; private Node left, right; private double p; private String code; public Node(String key, double p) { this(key, null, null, p); } public Node(String key2, Node left, Node right, double p) { this(key2, left, right, p, ""); } public Node(String key2, Node left, Node right, double p, String code) { this.key = key2; this.left = left; this.right = right; this.p = p; this.code = code; } public String getKey() { return key; } public String getCode() { return code; } public void setKey(String key) { this.key = key; } public void setCode(String code) { this.code = code; } public Node getLeft() { return left; } public void setLeft(Node left) { this.left = left; } public void setPro(double p) { this.p = p; } public Node getRight() { return right; } public double getPro() { return p; } public void setRight(Node right) { this.right = right; } }
Huffman.java
import java.util.*; public class Huffman { public static ArrayList<Node> tree = new ArrayList<Node>();// 用于建立树 public static ArrayList<Node> node = new ArrayList<Node>();// 用于存放最初的点,且这些点之间不存在关系 public static int N;// 取值空间元素的个数 public void sort(ArrayList<Node> node2) {// 排序 Node temp; int num = node2.size(); for (int i = 0; i < num - 1; i++) for (int j = i + 1; j < num; j++) { if (node2.get(i).getPro() > node2.get(j).getPro()) { temp = node2.get(i); node2.set(i, node2.get(j)); node2.set(j, temp); } } } /** 判断输入数据是否出错,概率之和等于1 */ public boolean error(double[] pro) { double num = 0; for (int i = 0; i < N; i++) num = num + pro[i]; if (num != 1) return false; else return true; } /** 访问节点 */ public void visit(Node p) { // System.out.print(p.getKey() + " "); if (p.getLeft() != null) { p.getLeft().setCode(p.getCode().concat("0")); p.getRight().setCode(p.getCode().concat("1")); } } /** 递归实现前序遍历 */ protected void preorder(Node p) { if (p != null) { visit(p); preorder(p.getLeft()); preorder(p.getRight()); } } public static void main(String[] args) { Huffman en = new Huffman(); // 数据的输入 Scanner input = new Scanner(System.in); System.out.print("请输入取值空间X中元素的个数:"); N = input.nextInt(); String[] str = new String[N]; System.out.print("请输入取值空间X中的元素:"); for (int i = 0; i < N; i++) str[i] = input.next();// 输入取值空间的数据 double[] probability = new double[N]; System.out.print("请输入各个元素的概率:"); for (int i = 0; i < N; i++) probability[i] = input.nextDouble();// 输入对应的概率 if (en.error(probability)) { Node[] ye = new Node[N]; for (int i = 0; i < N; i++) { ye[i] = new Node(str[i], probability[i]); node.add(ye[i]); } /** 此过程建立tree */ while (node.size() > 1) { en.sort(node); Node temp1 = node.get(0); Node temp2 = node.get(1);// 将要处理的两个点 Node root = new Node("", temp1, temp2, temp1.getPro() + temp2.getPro()); tree.add(temp1); tree.add(temp2); tree.add(root); node.remove(0); node.remove(0); node.add(root); } } else { System.out.print("输入数据有误!"); } /** 遍历树进行Huffman编码 */ Node root = tree.get(tree.size() - 1); en.preorder(root); Iterator<Node> it1 = tree.iterator(); System.out.println("Huffman编码结果如下:"); /** 迭代器输出结果 */ while (it1.hasNext()) { Node put = it1.next(); if (!put.getKey().equals("")) { System.out.println("X为" + put.getKey() + "时:其Huffman编码:" + put.getCode()); } } } }