- 浏览: 62372 次
- 性别:
- 来自: 福建
最新评论
-
netwelfare:
相比较而言,这篇文章讲解的更深入更详细:异常的深入研究与分析
java中异常机制总结 -
zendly:
参考最新的百度API吧
android实现百度地图定位 -
lixiongzhi_m:
这个估计快两年前的了,百度地图api都更新了不少了。不知道还能 ...
android实现百度地图定位 -
zendly:
学习啦。楼主赞。!!
android实现百度地图定位 -
120970289:
SB,你是李雄志???
初识android开发
哈夫曼压缩总结
实现哈弗曼压缩的步骤:
一.读取文件
保存每一个字符对应的出现次数,该步骤利用数组和字符对应的ACISS值来存储,字符对应的ACISS值作为数组的下标,字符没出现一次,相应下标的数组元素加一。
代码如下:
二.排序
根据相应字符对应的出现次数来排序,该步骤实现利用优先队列,由于后面建树的需要所以存入队列的相应字符实例化的节点对象。
节点属性包括:
1.父节点
2.左子节点、右子节点、父节点
3.节点对应的ACISS值
4.原始的哈夫曼编码
5.补0后的哈夫曼编码(由于写头文件需要,最小单位是一个字节,所以当哈弗吗编码不是8的倍数,就要补0)
6.哈夫曼编码补0的个数(后面再读取头文件的时候要,要还原哈夫曼编码,所以在写头文件时必须写入每个编码对应的补0个数)
三.构建哈弗曼树
将前面排好的序列,每次取出出现次数最少的对应的字符的两个节点对象,(取出两个对象后该队列也就删除了这两个对象),实例化两个节点的父节点,该节点中对应的出现次数是两个子节点的和,并将该父节点加入队列中,(由于优先队列每次删除加入新的元素后都能自动排序,后面只要一直去执行这个步骤就能把哈弗曼树建好了)。
四.获取叶子节点对象的哈弗曼编码
从根节点开始到对应的每一个 叶子节点,以左0右1的规则便可获得每个叶子节点所对应的哈弗曼编码,并利用队列来保存这些节点(由于优先队列中的节点在建树时已经被删除,后面这些很多地方都要用到这些叶子节点,所以要实例化一个队列来保存)
五.向压缩文件中写入
1.头文件的写入
写入信息包括 1.头文件长度
2.每个叶子节点对应的ACISS(源文件的字符)
3.每个叶子节点对应的补0后的哈夫曼编码对应的Byte数,(由几个字节组成)
4.每个叶子节点对应的哈夫曼编码(补0后的哈夫曼编码,补了0字符串长度变长8的倍数,按字节写入)
5.每个叶子节点哈夫曼编码对应的补0个数(便于后面读取头文件编码的还原)
2.源文件信息的写入(这边才真正的实现压缩理) 读取源文件每个字符对应的ACISS,然后遍历存储节点的队列,找出和该ACISS值相等对应下的节点,获取该节点对应的原始哈夫曼编码(未补0的哈夫曼编码),若该编码长度大于等于8,读取前八位按一个字节写入文件,若不足8位,再读取源文件下一个字符对应叶子节点下的哈夫曼编码,加到前面的编码后,再做长度判断。直至把源文件全部写入。
注意点:注意最后读取的源文件尾字符,或者读取的源字符对应的哈夫曼编码和前面编码相连的长度不是8的倍数,就要补0填成8的倍数再写入。记录文件末尾补0个数,并写入文件。(便于后面的文件还原)
压缩原理:由于哈夫曼树的构建获取的每个叶子节点对应的编码有这样的特点:
1.字符在源文件中出现次数多的,对应的哈夫曼编码长度就比较短(比8要少),字符出现次数的对应的字符长度相对就较长一点。但出现比8大的情况比较少。平衡下来整个文件对应的01串便会减短。这样也就实现了源文件的压缩。
2.由于添加了一个头文件,所以这边刚接触时难免有一些困惑,但由于头文件只有一个最多也就0—255都有。所以对相对比较大的文件的压缩这个是毫不影响的。但有些情况这种压缩方法是实现不了压缩的,比如说一个字符的文件,源文件一个字节,按我这种做法压缩后的文件变成了6个字节。
当然这种情况在压缩中是不值一提的,我们之所以要实现压缩是用来压缩大文件的,小文件压它干嘛,你说是吧?
由于java中没有提供二进制写入的方法,所以要将每一个字节对应的哈弗曼编码转换成字节才能写入,一个字节八个位,但并不是所有字符对应的哈弗曼编码都刚刚好是八的整数倍,所以必须给每个字符对象的哈弗曼编码补0使其变成8的整数倍,这样就能用字节的形式往文件中写入。每次都要计入相应每个字符补0的个数,方便解压之用。
以上五个步骤就实现了哈夫曼压缩。
解压
解压就是一个逆过程,怎么向压缩文件写东西就怎么从压缩文件读取东西还原后写入解压文件。
步骤:
1.读取头文件信息,(我们之前写入一开始就写入了文件头的长度,所以我们读出的第一个也就是文件头的长度,这个是非常重要的一个数据,我们可以知道头文件在什么地方截止)。读取原来写入头文件的ACISS值,在读取补0后的哈夫曼编码Byte数,用for循环读取Byte次就能读出相应ACISS对应的补完0的哈夫曼编码,在读取补0个数,去掉0还原哈夫曼编码。用数组存储。相应下标为ACISS的值,元素值为还原后的哈夫曼编码。这样文件头我们解压要用的信息就全部被存储在数组中了。
2.读取压缩文件内源文件信息,一次读取一个字节转换成相应的01串,用for循环每次读01串中的一个数(每次数累加)。遍历数组和数组中存储的哈夫曼编码做对比,若有相等的,将对应的下标写入解压文件,这样对应的字符便被写入了。写入后循环起始索引改成末尾索引。若没有相等的将原来的for循环的末尾索引加1让每次读取的01串比原来长1,在做对比。这样一直执行下去,直至读到末尾倒数第二个字节。最后读取最后一个字节,并读出末尾补0个数,去掉0还原编码,再执行上面的过程,这样解压就完成了。
在压缩时涉及到将01串转化成整形,在解压时涉及到将整形转化成01串,这个可以看做是10进制和2进制的转化问题。
01串转化成整形
整形转化成01串
听的、看的都很模糊,很乱。关键还是自己动手写。这样才能有真正的体会。
一.读取文件
保存每一个字符对应的出现次数,该步骤利用数组和字符对应的ACISS值来存储,字符对应的ACISS值作为数组的下标,字符没出现一次,相应下标的数组元素加一。
代码如下:
try { // 实例化文件输入流对象 FileInputStream fis = new FileInputStream(path); while (fis.available() > 0) { // 开始读取文件 int i = fis.read(); // System.out.print(i+" "); // 读到的整形数据相应的下标加一 ByteCount[i]++; } //关闭输入流 fis.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }
二.排序
根据相应字符对应的出现次数来排序,该步骤实现利用优先队列,由于后面建树的需要所以存入队列的相应字符实例化的节点对象。
节点属性包括:
1.父节点
2.左子节点、右子节点、父节点
3.节点对应的ACISS值
4.原始的哈夫曼编码
5.补0后的哈夫曼编码(由于写头文件需要,最小单位是一个字节,所以当哈弗吗编码不是8的倍数,就要补0)
6.哈夫曼编码补0的个数(后面再读取头文件的时候要,要还原哈夫曼编码,所以在写头文件时必须写入每个编码对应的补0个数)
/** * * 树的节点类 * */ public class TreeNode implements Comparable<TreeNode>{ private TreeNode left;//声明树的左子节点属性 private TreeNode right;//声明树的右子节点属性 private TreeNode parent;//声明树的父节点属性 private int count;//声明字符出现的次数 private int ACISS;//声明节点的数据属性,即字符对应的ACISS值 private String hfmcode="";//声明节点对应的哈弗曼编码 private int o_count=0;//声明节点编码个数变成八的倍数要添加的0的个数 private int code_length=0;//声明编码长度属性 private String HFMCode="";//未加0前的哈夫曼编码 public String getHFMCode() { return HFMCode; } public void setHFMCode(String code) { HFMCode = code; } /** * 获取节点对应的ACISS值 * @return返回ACISS值 */ public int getACISS() { return ACISS; } /** * * @param aciss */ public void setACISS(int aciss) { ACISS = aciss; } /** * 获取编码长度 * @return编码长度属性 */ public int getCode_length() { return code_length; } /** * 设置编码长度属性 * @param code_length新的编码长度属性 */ public void setCode_length(int code_length) { this.code_length = code_length; } /** * 获取节点对应的哈弗曼编码 * @return返回哈弗曼编码 */ public String gethfmCode() { return hfmcode; } /** * 设置节点对应的哈弗曼编码 * @param 新的哈弗曼编码 */ public void setCode(String code) { this.hfmcode = code; } /** * 获取节点哈弗曼编码添加0的个数 * @return返回添加0的个数 */ public int getO_count() { return o_count; } /** * 设置节点对应编码添加0的个数 * @param o_count新的0的个数值 */ public void setO_count(int o_count) { this.o_count = o_count; } /** * 构造方法 * @param left左子节点 * @param right右子节点 * @param parent父节点 * @param object节点数据 */ public TreeNode(TreeNode left, TreeNode right, TreeNode parent, int count) { this.left = left; this.right = right; this.parent = parent; this.count=count; } /** * 构造方法 * @param object节点数据 */ public TreeNode(int ACISS ,int count) { this.ACISS=ACISS; this.count=count; } /** * 获取左子节点的方法 * @return左子节点 */ public TreeNode getLeft() { return left; } /** * 设置左子节点的方法 * @param left */ public void setLeft(TreeNode left) { this.left = left; } /** * 获取右子节点的方法 * @return右子节点 */ public TreeNode getRight() { return right; } /** * 设置右子节点的方法 * @param right */ public void setRight(TreeNode right) { this.right = right; } /** * 获取父节点的方法 * @return返回父节点 */ public TreeNode getParent() { return parent; } /** * 设置父节点的方法 * @param parent */ public void setParent(TreeNode parent) { this.parent = parent; } /** * 获取节点数据的方法 * @return返回节点数据 */ public int getCount() { return count; } /** * 设置节点数据的方法 * @param object */ public void setCount(int count) { this.count=count; } /** * 获取数据的方法 * @param data数据 * @return返回数据 */ public int getData(int data){ return data; } public int compareTo(TreeNode o) { // TODO Auto-generated method stub return count - o.getCount(); } }
三.构建哈弗曼树
将前面排好的序列,每次取出出现次数最少的对应的字符的两个节点对象,(取出两个对象后该队列也就删除了这两个对象),实例化两个节点的父节点,该节点中对应的出现次数是两个子节点的和,并将该父节点加入队列中,(由于优先队列每次删除加入新的元素后都能自动排序,后面只要一直去执行这个步骤就能把哈弗曼树建好了)。
四.获取叶子节点对象的哈弗曼编码
从根节点开始到对应的每一个 叶子节点,以左0右1的规则便可获得每个叶子节点所对应的哈弗曼编码,并利用队列来保存这些节点(由于优先队列中的节点在建树时已经被删除,后面这些很多地方都要用到这些叶子节点,所以要实例化一个队列来保存)
public void creat_tree() { // 调用实例化节点和往队列中添加节点的方法 CreatNode(); // 开始建树 while (nodeQueue.size() > 1) { // 取出队列中出现次数最少的两个节点 TreeNode minnode1 = nodeQueue.poll(); //System.out.print(minnode1.getCount() + " "); TreeNode minnode2 = nodeQueue.poll(); //System.out.print(minnode2.getCount() + "\n"); // 实例化一个新的节点作为上面两个节点的父节点 TreeNode parentnode = new TreeNode(0, minnode1.getCount()+ minnode2.getCount()); parentnode.setLeft(minnode1); parentnode.setRight(minnode2); minnode1.setParent(parentnode); minnode2.setParent(parentnode); //System.out.println(parentnode.getCount()); // 把父节点添加到队列中 nodeQueue.add(parentnode); } // 取出剩下的一个节点作为根节点 root = nodeQueue.peek(); //设置根节点的一些属性,防止由于只有一个节点的时候出现错误 root.setCode_length(1); root.setHFMCode("1"); root.setCode("1"); root.setO_count(7); System.out.println("+++++++++++"+root.getACISS()); }
五.向压缩文件中写入
1.头文件的写入
写入信息包括 1.头文件长度
2.每个叶子节点对应的ACISS(源文件的字符)
3.每个叶子节点对应的补0后的哈夫曼编码对应的Byte数,(由几个字节组成)
4.每个叶子节点对应的哈夫曼编码(补0后的哈夫曼编码,补了0字符串长度变长8的倍数,按字节写入)
5.每个叶子节点哈夫曼编码对应的补0个数(便于后面读取头文件编码的还原)
/** *文件头信息 * *文件头长度 源文件补0个数 *字符对应的ACISS值 字符对应编码Byte个数 *字符对应的编码补0后按一个整形写入 编码补0个数 * */ try { //定义头文件长度的变量 int headfile_length = 0; //计算出文件头长度 for(int j=0;j<arraylist.size();j++){ headfile_length+=(3+arraylist.get(j).gethfmCode().length()/8); } System.out.println("文件头长度是:"+headfile_length); fos.write(headfile_length);//写入头文件长度 for (int i=0; i < arraylist.size(); i++) { fos.write(arraylist.get(i).getACISS());// 写入对应的字符 System.out.println("写入的ACISS是:"+arraylist.get(i).getACISS()); // 写入对应编码byte个数 fos.write((arraylist.get(i).getCode_length() + arraylist.get(i).getO_count())/8); System.out.println("写入的Byte数时:"+(arraylist.get(i).getCode_length() + arraylist.get(i).getO_count())/8); // System.out.println("<><><><><><><><><>"); //如果编码长度大于8,每次写入8个为一个字节 if (arraylist.get(i).gethfmCode().length()>8) { int k = 0; while (k<arraylist.get(i).gethfmCode().length()) { String string = ""; for (int n=k; n<k+8;n++) { string += arraylist.get(i).gethfmCode().charAt(n); } System.out.println("<><><>" + string); k+=8; System.out.println("写入的编码补0后的编码是"+string+" 变成整数是:"+string_to_int(string)); fos.write(string_to_int(string));// 写入前八位编码 } }else{ System.out.println("写入的编码补0后的编码是"+arraylist.get(i).gethfmCode()+" 变成整数是:"+string_to_int(arraylist.get(i).gethfmCode())); fos.write(string_to_int(arraylist.get(i).gethfmCode())); } fos.write(arraylist.get(i).getO_count());// 写入编码补0个数 System.out.println("写入的补0个数是;"+arraylist.get(i).getO_count()); }
2.源文件信息的写入(这边才真正的实现压缩理) 读取源文件每个字符对应的ACISS,然后遍历存储节点的队列,找出和该ACISS值相等对应下的节点,获取该节点对应的原始哈夫曼编码(未补0的哈夫曼编码),若该编码长度大于等于8,读取前八位按一个字节写入文件,若不足8位,再读取源文件下一个字符对应叶子节点下的哈夫曼编码,加到前面的编码后,再做长度判断。直至把源文件全部写入。
注意点:注意最后读取的源文件尾字符,或者读取的源字符对应的哈夫曼编码和前面编码相连的长度不是8的倍数,就要补0填成8的倍数再写入。记录文件末尾补0个数,并写入文件。(便于后面的文件还原)
压缩原理:由于哈夫曼树的构建获取的每个叶子节点对应的编码有这样的特点:
1.字符在源文件中出现次数多的,对应的哈夫曼编码长度就比较短(比8要少),字符出现次数的对应的字符长度相对就较长一点。但出现比8大的情况比较少。平衡下来整个文件对应的01串便会减短。这样也就实现了源文件的压缩。
2.由于添加了一个头文件,所以这边刚接触时难免有一些困惑,但由于头文件只有一个最多也就0—255都有。所以对相对比较大的文件的压缩这个是毫不影响的。但有些情况这种压缩方法是实现不了压缩的,比如说一个字符的文件,源文件一个字节,按我这种做法压缩后的文件变成了6个字节。
当然这种情况在压缩中是不值一提的,我们之所以要实现压缩是用来压缩大文件的,小文件压它干嘛,你说是吧?
由于java中没有提供二进制写入的方法,所以要将每一个字节对应的哈弗曼编码转换成字节才能写入,一个字节八个位,但并不是所有字符对应的哈弗曼编码都刚刚好是八的整数倍,所以必须给每个字符对象的哈弗曼编码补0使其变成8的整数倍,这样就能用字节的形式往文件中写入。每次都要计入相应每个字符补0的个数,方便解压之用。
/** * * 开始写入源文件内容 * * */ String HFMcode="";//定义从源文件读取的字节对应的哈夫曼编码变量 int ACISS; System.out.println("****************************"); while(fis.available()>0){ ACISS=fis.read(); String write="";//定义要写入的01串变量 //遍历队列,找出和读到的值相等的对象的节点对象,获取哈夫曼编码,写入头文件 for(int j=0;j<arraylist.size();j++){ TreeNode node=arraylist.get(j);//获取队列中的节点 //如果源文件字符与 if(node.getACISS()==ACISS){ //获取对应的哈夫曼编码 HFMcode=HFMcode+node.getHFMCode(); //System.out.println("编码是:"+HFMcode); //System.out.println("编码是"+HFMcode); //System.out.println("现在编码的长度是:"+HFMcode.length()+" "+"编码是"+HFMcode); //System.out.println("对应的哈夫曼编码是:"+node.getACISS()+" "+node.getHFMCode()); if(HFMcode.length()>=8){ //获取前8位 for(int k=0;k<8;k++){ write=write+HFMcode.charAt(k); } //将前八位写入文件 System.out.println("文件字节对应的8位转成int型写入的是:"+write); fos.write(string_to_int(write)); //将原来编码的前八位删掉 String str=""; for(int k=8;k<HFMcode.length();k++){ str=str+HFMcode.charAt(k); } HFMcode=str; }else{ //如果小于8,在读取一个字节 int ACISS2=fis.read(); //System.out.println("不足8为在读取"+ACISS); for(int k=0;k<arraylist.size();k++){ TreeNode node2=arraylist.get(k); if(node2.getACISS()==ACISS2){ HFMcode=HFMcode+node2.getHFMCode(); //System.out.println("对应的哈夫曼编码是:"+node2.getACISS()+" "+node2.getHFMCode()); //System.out.println("补上后的编码"+HFMcode); } } } } } } System.out.println("源文件最后一个编码是:"+HFMcode); if(HFMcode.length()%8!=0){ file__0=(8-HFMcode.length()%8); } //文件末尾添加0,然后写入文件 for(int i=0;i<file__0;i++){ HFMcode=HFMcode+"0"; } System.out.println("文件最后一个添0个数是"+file__0); System.out.println("文件的最后一个代码添加0后是:"+HFMcode); if(HFMcode!=""){ fos.write(string_to_int(HFMcode)); } //关闭文件流 fis.close(); fos.close(); } catch (IOException e) { e.printStackTrace(); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
以上五个步骤就实现了哈夫曼压缩。
解压
解压就是一个逆过程,怎么向压缩文件写东西就怎么从压缩文件读取东西还原后写入解压文件。
步骤:
1.读取头文件信息,(我们之前写入一开始就写入了文件头的长度,所以我们读出的第一个也就是文件头的长度,这个是非常重要的一个数据,我们可以知道头文件在什么地方截止)。读取原来写入头文件的ACISS值,在读取补0后的哈夫曼编码Byte数,用for循环读取Byte次就能读出相应ACISS对应的补完0的哈夫曼编码,在读取补0个数,去掉0还原哈夫曼编码。用数组存储。相应下标为ACISS的值,元素值为还原后的哈夫曼编码。这样文件头我们解压要用的信息就全部被存储在数组中了。
2.读取压缩文件内源文件信息,一次读取一个字节转换成相应的01串,用for循环每次读01串中的一个数(每次数累加)。遍历数组和数组中存储的哈夫曼编码做对比,若有相等的,将对应的下标写入解压文件,这样对应的字符便被写入了。写入后循环起始索引改成末尾索引。若没有相等的将原来的for循环的末尾索引加1让每次读取的01串比原来长1,在做对比。这样一直执行下去,直至读到末尾倒数第二个字节。最后读取最后一个字节,并读出末尾补0个数,去掉0还原编码,再执行上面的过程,这样解压就完成了。
public void read_and_write(){ try { //实例化一个文件输出流对象,用来向解压后的文件写入内容 FileOutputStream fos=new FileOutputStream(newpath); //实例化一个文件输入流对象用来读取压缩文件内容 FileInputStream fis=new FileInputStream(y_path); //读取文件头长度 int head_length=fis.read(); System.out.println("读取的文件头长度是:"+head_length); /** * * * 读取头文件的所有信息 */ while(head_length>0){ int ACISS=fis.read();//读取字符对应的ACISS值 System.out.println("字符的ACISS:"+ACISS); int Byte_count=fis.read();//读取编码的Byte数 System.out.println("哈夫曼编码字节数:"+Byte_count); String hfm_code_0=""; for(int i=0;i<Byte_count;i++){ hfm_code_0+=int_to_string(fis.read()); } System.out.println("补0后的哈夫曼编码是:"+hfm_code_0); int count_0=fis.read();//读取补0个数 String HFMcode="";//定义去掉0后的哈夫曼编码变量 for(int j=0;j<hfm_code_0.length()-count_0;j++){ HFMcode+=hfm_code_0.charAt(j); } System.out.println("去掉0后的哈夫曼编码是:"+HFMcode); array[ACISS]=HFMcode;//将哈夫曼编码和对应的字符的ACISS相应的保存在数组中 head_length-=(3+Byte_count); } for(int i=0;i<array.length;i++){ if(array[i]!=null){ System.out.println("数组中ACISS:"+i+" 对应的哈夫曼编码是:"+array[i]); } } /** * 读取源文件内容 * * */ String file_01=""; while(fis.available()>1){ int count_writed_01=0; //读取的01字符串 file_01+=int_to_string(fis.read()); System.out.println("源文件的01串是:"+file_01); int k=0; int count=1; while(count<=file_01.length()){ //定义哈夫曼编码变量 String HFMcode=""; for(int i=k;i<count;i++){ HFMcode+=file_01.charAt(i); } for(int i=0;i<array.length;i++){ if(array[i]!=null&&array[i].equals(HFMcode)){ System.out.println("哈夫曼编码是"+HFMcode); count_writed_01+=HFMcode.length(); System.out.println("写入了"+count_writed_01+"个"); k=count; fos.write(i); System.out.println("内容写入了"+i); } } count++; } System.out.println("写入后的file_01是"+file_01); String file_01x=""; for(int i=count_writed_01;i<file_01.length();i++){ file_01x+=file_01.charAt(i); } file_01=file_01x; System.out.println("清空后的file_01是"+file_01); } //读取最后一个字符串 String str_end=file_01+int_to_string(fis.read()); System.out.println("最后一个字符串是"+str_end); int file__0=ya_suo.getFile__0();//获取问价末尾补0个数 //把最后读取的字符串补的0去掉 String str=""; for(int i=0;i<str_end.length()-file__0;i++){ str+=str_end.charAt(i); } str_end=str; System.out.println("把0删掉后变成:"+str_end); int count=1; int k=0; while(count<=str_end.length()){ str=""; for(int i=k;i<count;i++){ str+=str_end.charAt(i); } System.out.println("str是:"+str); for(int i=0;i<array.length;i++){ if(array[i]!=null&&array[i].equals(str)){ System.out.println("&&&&&&&&&&&"); fos.write(i); k=count; } } count++; } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
在压缩时涉及到将01串转化成整形,在解压时涉及到将整形转化成01串,这个可以看做是10进制和2进制的转化问题。
01串转化成整形
/** * 将01字符串转成整形的方法 */ public int string_to_int(String str) { return (str.charAt(0) - 48) * 128 + (str.charAt(1) - 48) * 64 + (str.charAt(2) - 48) * 32 + (str.charAt(3) - 48) * 16 + (str.charAt(4) - 48) * 8 + (str.charAt(5) - 48) * 4 + (str.charAt(6) - 48) * 2 + (str.charAt(7) - 48) * 1; }
整形转化成01串
/** * 将整形数据转化成8个01串的方法 * @param Int * @return */ public String int_to_string(int Int){ String str=""; if(Int==0){ str="00000000"; }else{ while(Int!=0){ int mod=Int%2; str+=mod; Int/=2; } } if(str.length()!=8){ int count=8-str.length(); for(int i=0;i<count;i++){ str+=0; } } String str2=""; for(int i=str.length()-1;i>=0;i--){ str2+=str.charAt(i); } //System.out.println(">>>>>>>>>>>>>>>>"+Int+"变成字符串是:"+str2); return str2; }
听的、看的都很模糊,很乱。关键还是自己动手写。这样才能有真正的体会。
评论
2 楼
lixiongzhi_m
2012-10-15
其实这个解压方法效率非常低,每次要遍历数组。
建议你解压读表头时用map保存Acssi值和对应的哈夫曼编码,这样不用每次都去遍历数组效率提高很多、
建议你解压读表头时用map保存Acssi值和对应的哈夫曼编码,这样不用每次都去遍历数组效率提高很多、
1 楼
ronaldoLY
2012-10-14
写的好详细。真心不错。
相关推荐
哈夫曼编码是一种高效的数据压缩方法,由大卫·哈夫曼在1952年提出。它是基于一种称为哈夫曼树(也叫最优二叉树)的数据结构。在这个课程设计中,你将深入理解哈夫曼编码的原理,并通过C++编程语言实现文件的压缩与...
总结,哈弗曼压缩是一种基于频率的编码方法,它通过构建哈弗曼树来实现对数据的有效压缩。在Java中,可以通过分析给定的源码文件了解并实现这一过程,这有助于提高对数据压缩原理和算法的理解。
总结来说,哈夫曼树压缩算法利用了数据的统计特性,通过构建最优二叉树实现高效的数据编码,进而完成数据的压缩。在实际应用中,这种算法广泛应用于文本、图像和音频等数据的压缩,提高了存储和传输的效率。
总结来说,哈夫曼压缩技术是一种基于频率的无损数据压缩方法,特别适合处理包含重复元素的数据。虽然在处理图像压缩时可能效率较低,但与其他算法结合使用时,如EZW,可以提升压缩效果。在实际应用中,哈夫曼编码常...
哈夫曼编码是一种高效的数据压缩编码技术,由美国科学家大卫·哈夫曼在1952年提出。这种编码方式是基于信源符号的概率分布,通过构建最优的二叉树来实现,使得出现频率高的符号拥有较短的编码,而出现频率低的符号...
总结来说,这个小工具通过哈夫曼编码技术实现了文件的压缩和解压缩,利用了数据的频率特性,尤其适用于那些含有大量重复字符的文件。同时,哈夫曼编码的原理和实现也是计算机科学中经典的数据压缩理论,对于理解和...
在哈夫曼压缩与解压软件的实现中,MFC提供了图形用户界面(GUI)的构建基础,包括对话框、控件和文件操作类,使得开发者能够更加专注于算法的实现,而无需过多关注底层的Windows API。 哈夫曼编码的核心步骤包括: ...
总结起来,哈夫曼树和小顶堆在文件压缩中的应用是一项高效的技术,通过优化编码长度,有效减少了文件大小。在实现过程中,理解并掌握这两个数据结构的操作是至关重要的。通过FileCompress.h、Heap.h和HaffmanTree.h...
总结来说,Java哈夫曼编码是利用数据结构和算法理论实现的一种压缩技术,它在处理大量重复字符的数据时表现优秀。通过合理地分配编码长度,哈夫曼编码可以有效地减少存储空间,同时保持数据的可恢复性,因此在文本...
在实际的哈夫曼压缩过程中,我们先遍历输入文件中的每个字符,根据哈夫曼编码表将其转换为二进制序列,然后将所有二进制序列连接起来形成一个大的二进制串。这个二进制串就是压缩后的文件,可以写入到名为"2文件"的...
总结来说,哈夫曼压缩是一种高效的无损数据压缩方法,基于字符频率构建特殊的二叉树并生成前缀编码。它在数据存储、传输和各种文件格式中都有广泛应用,并可以通过各种编程工具和库进行实现和操作。
总结来说,哈夫曼编码是一种基于字符频率的压缩技术,它通过构建哈夫曼树并生成编码来实现数据压缩。在“哈夫曼编码压缩解压文件”的过程中,理解哈夫曼树的构建、编码的生成以及压缩和解压的步骤至关重要。掌握这些...
《哈夫曼编码在压缩软件中的应用与实现》 哈夫曼编码,作为一种高效的数据压缩方法,被广泛应用于各类压缩软件中。它基于频率最小的编码原则,通过构建最优的二叉树结构来实现对数据的高效编码。在这个项目中,我们...
总结,Java哈夫曼压缩和解压涉及对数据编码、构建哈夫曼树、生成编码表、解码等过程,通过高效的数据结构和算法实现高效的数据压缩。了解和掌握哈夫曼编码不仅有助于理解数据压缩原理,也是提升软件开发效率的重要...
总结来说,哈夫曼编码是一种基于字符频率的无损数据压缩方法,通过构建哈夫曼树来生成编码,并据此进行数据的压缩和解压缩。在VC环境下,可以编写C++程序来实现这一过程,从而提高数据存储和传输的效率。
总结来说,利用C++实现哈夫曼算法,需要对哈夫曼树的构建、节点的管理以及编码和解码的过程有深入的理解。通过构建一个按照字符频率排序的哈夫曼树,可以得到一个有效的数据压缩方案。掌握这一算法不仅能够帮助我们...
《哈夫曼压缩解压数据结构设计》报告 在数据处理和存储中,文献压缩是一种重要的技术,旨在减少数据的存储需求。哈夫曼编码是一种高效的数据压缩方法,基于字符出现频率进行编码,使得出现频繁的字符具有较短的编码...
哈夫曼编码是一种高效的数据压缩方法,主要用于无损数据压缩,其原理基于频率最小的字符用最短的编码,频率最高的字符用最长的编码。在本课程设计中,学生将深入理解并应用哈夫曼编码的理论,实现一个能够进行压缩...
总结来说,哈夫曼压缩解压缩是通过构建哈夫曼树,根据字符出现的频率为其分配不同的二进制编码,从而实现文件的高效压缩和解压缩。在具体实现时,需要设计合适的数据结构和算法来支持这一过程,同时保证压缩前后文件...
在Java编程中,哈夫曼编码(Huffman Coding)是一种数据压缩算法,它基于字符出现频率构建最优前缀树(也称为哈夫曼树),从而为每个字符分配一个唯一的二进制编码。这个编码方法使得频繁出现的字符拥有较短的编码,...