1、五、实验原理1. 压缩/解压缩流程压缩流程:读取扫描文本文件统计字符频率生成码字保存压缩文件解压缩流程:读取扫描压缩文件提取字符频率生成码树保存文本文件2. Huffman编码算法(略)3. 文件操作和位运算(略)六、Huffman 算法的8种不同实现方式 1. huffman_a 使用链表结构生成Huffman树的算法,这是最基本的实现方法,效率最低。2. huffman_b 使用数据结构(严蔚敏,吴伟民,1997,C语言版)中给出的算法,将二叉树存放在连续空间里(静态链表),空间的每个结点内仍有左子树、右子树、双亲等指针。3. huffman_c 使用Canonical Huffman编码
2、,同时对huffman_b的存储结构进行改造,将二叉树存放在连续空间tree里,空间的每个结点类型都和结点权值的数据类型相同,空间大小为2*num,tree0未用,tree1.num是每个元素的权值,生成Huffman后,tree1.2*num-1中是双亲结点索引。 4. huffman_d 在huffman_c的基础上,增加预先排序的功能先用QuickSort算法对所有元素的权值从小到大排序,这样,排序后最前面的两个元素就是最小的一对元素了。我们可以直接将它们挑出来,组合成一个子树。然后再子树的权值用折半插入法插到已排序的元素表中, 保证所有结点有序。为了保证初始元素的顺序不变,我们另外使用
3、了一个索引数组,所有排序中的交换操作都是在索引数组中进行的。 5. huffman_e 在huffman_d的基础上,将索引数组放在tree的内部。为编码方便,将元素权值放在treenum.2*num-1处。将tree0.num-1作为索引数组。排序改为从大到小。对索引数组排序后,每次从最后选出2个最小值,相加后的结点权值放在索引数组最后,结点索引放在索引数组中倒数第2个位置,然后索引数组大小减1,并将最后一个索引值插入到前面的有序表中,保证索引数组仍然有序。 6. huffman_f 在huffman_e的基础上,将排序改为利用堆排序原理选择最小的两个权值。也即,将所有元素的权值组织成堆后,
4、每次堆内的根结点就是最小值了。每取出一个根结点后,就把堆尾元素调到根结点重建堆。取出两个最小值合并成一个子树后,再把子树作为叶子结点放到堆中,并让其上升到合适的位置,保持堆性质不变。因为每次不必完成整个排序过程,而只是组织成堆,因此,这种方法要比使用快速排序更快。上述算法参考了mg-1.2.1中Huffman编码的实现,见http:/www.cs.mu.oz.au/mg/ 7. huffman_g 当元素权值已经有序时,可以使用A. Moffat和J. Katajainen设计的在权值数组内部构建Huffman的方法。A. Moffat和J. Katajainen对该算法的描述见http:/w
5、ww.cs.mu.oz.au/alistair/abstracts/inplace.html 8. huffman_h 在huffman_f的基础上,增加限制码长的功能。限制码长的算法参考了zlib-1.1.4中构造限制码长的Huffman编码的源代码。zlib的源代码见http:/www.gzip.org/zlib/,其中限制长度的算法在tree.c的gen_bitlen()函数中。七Huffman 的java 实现:界面类public class ComFileFrame public static void main(String args) ComFileFrame cff = new
6、 ComFileFrame(); cff.showUI(); public void showUI() javax.swing.JFrame frame = new javax.swing.JFrame(); frame.setSize(200, 100); frame.setLocationRelativeTo(null); frame.setTitle(own压缩软件); frame.setLayout(new java.awt.FlowLayout(); frame.setDefaultCloseOperation(3); frame.setResizable(false); javax
7、.swing.JButton comf = new javax.swing.JButton(压缩 javax.swing.JButton decomf = new javax.swing.JButton(解压缩 MouseListenerImpl mli = new MouseListenerImpl(); comf.addMouseListener(mli); decomf.addMouseListener(mli); javax.swing.JLabel label = new javax.swing.JLabel(Copyright Chenjunqing label.addMouseL
8、istener(mli); frame.add(comf); frame.add(decomf); frame.add(label); frame.setVisible(true); 鼠标监听器类package java.Huffman;import java.awt.event.MouseEvent;import java.awt.event.MouseListener;import javax.swing.JButton;import javax.swing.JLabel;public class MouseListenerImpl implements MouseListener pub
9、lic void mouseClicked(MouseEvent e) Object obj = e.getSource();/得到鼠标单击的对象 if(obj instanceof JButton)/判断鼠标是否单击是按钮 JButton b = (JButton) obj; String title = b.getActionCommand();/得到按钮的名称 javax.swing.JFileChooser chooser = new javax.swing.JFileChooser();/创建一个filechooser,用来获取路径 if(title=)/判断单击的是哪个按钮 cho
10、oser.setFileSelectionMode(javax.swing.JFileChooser.FILES_ONLY);/压缩时只允许压缩文件 int t = chooser.showDialog(null, if(t = javax.swing.JFileChooser.APPROVE_OPTION) String source = chooser.getSelectedFile().getAbsolutePath();/得到源文件的路径/ System.out.println(source is :+source);/ for test String destination = so
11、urce+.own;/根据源文件路径产生新文件的路径destination is:+destination); Compress comFile = new Compress(); try long start = System.currentTimeMillis(); comFpressFile(source, destination); long end = System.currentTimeMillis(); long time = end -start; javax.swing.JOptionPane.showMessageDialog(null, 压缩完成!n+压缩用时:+time
12、+ms catch (Exception e1) e1.printStackTrace(); else if(title=) if(source.endsWith(own) String temp = source.substring(0,source.length()-4); int s = temp.lastIndexOf( String destination = temp.substring(0,s+1)+解压 +temp.substring(s+1,temp.length();/ System.out.println( Compress decomFile = new Compres
13、s(); try long start = System.currentTimeMillis(); decomFile.decompressFile(source, destination); long end = System.currentTimeMillis(); long time = end -start; javax.swing.JOptionPane.showMessageDialog(null, 解压完成!解压用时: catch (Exception e1) e1.printStackTrace(); else 请选择由本软件压缩的文件 else if(obj instance
14、of JLabel) javax.swing.JOptionPane.showMessageDialog(null, 本软件压缩的文件拓展名为own! Override public void mousePressed(MouseEvent e) / TODO Auto-generated method stub public void mouseReleased(MouseEvent e) public void mouseEntered(MouseEvent e) public void mouseExited(MouseEvent e) 压缩与解压缩方法类import java.io.D
15、ataInputStream;import java.io.DataOutputStream;import java.io.FileInputStream;import java.io.FileOutputStream;import java.util.ArrayList;import java.util.HashMap;/* * 利用Huffman编码进行压缩 * * author Chenjunqing */public class Compress public static void main(String args) throws Exception Compress cps = n
16、ew Compress(); / HashMap map = / cps.countFile(d:我的文档桌面Test.javaByte, String code = cps.getFileCode(map); / java.util.Set set = code.keySet(); / java.util.Iterator iter = set.iterator(); / while (iter.hasNext() / Byte key = iter.next(); / String value = code.get(key); / System.out.println(key + t +
17、value); / long start = System.currentTimeMillis(); pressFile(我的文档桌面005.png, 我的文档桌面005.own/ 压缩文件 cps.decompressFile(我的文档桌面解压005.png/ 解压文件 long end = System.currentTimeMillis(); System.out.println(Time of Running is: + (end - start) + /* * 对一个文件进行字节的统计 * param path * :文件的路径 * return:返回一个Map public Has
18、hMap countFile(String path) throws Exception HashMap map = new HashMap(); FileInputStream fis = new FileInputStream(path); DataInputStream dis = new DataInputStream(fis);/ 创建文件输入流对象,按照数据类型读取。 int t = -1; while (t = dis.read() != -1) Byte key = (byte) t; if (map.containsKey(key) Integer value = map.g
19、et(key); value+; map.put(key, value); else map.put(key, 1); dis.close(); / /测试代码 / int total = 0; set1 = map.keySet(); iter1 = set1.iterator(); / while (iter1.hasNext() / Byte key = iter1.next(); / int value = map.get(key); / total +; / System.out.println(total); return map; * 得到一个HashMap的Huffman编码
20、* param map要转化的HashMap返回一个HashMap,Byte是字节,String是其对应的Huffman编码。 getFileCode(HashMap map) java.util.Set set = map.keySet();/ 将MAP的key放到一个Set集合 java.util.Iterator/ Set向迭代器中放值 ArrayList huff = new ArrayList / 将字符出现的次数作为权值(data),字符作为标志(Sign),把数据转化为节点,存入一个队列中 while (iter.hasNext() Byte key = iter.next();
21、 Integer num = map.get(key); TreeNode temp = new TreeNode(num); temp.setSign(key); huff.add(temp); HuffmanTree hfmTree = new HuffmanTree(); / 将队列转化为相应的Huffman树,返回树的根节点 TreeNode root = hfmTree.ArrayToHuffman(huff); / hfmTree.printTree(root);/ 打印huffman树 code = hfmTree.getHuffmanCode(root);/ 得到huffman
22、编码,结果保存在Map / / 测试代码 set1 = code.keySet(); / total+; return code; * 得到源文件的压缩文件的方法 * param code由源文件得到的存储有其中每个字节及其对应Huffman编码的HashMap。 * param source源文件的路径 * param destination压缩文件存储的路径 public void compressFile(String source, String destination) throws Exception FileInputStream fis = new FileInputStream(source); FileOutputStream fos = new FileOutputStream(destination); DataOutputStream dos = new DataOutputStream(fos); String data = / 用来暂存编码的过度变量 map = this.countFile(source); code = this.getFileCode(map
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1