java實(shí)現(xiàn)哈夫曼文件解壓縮
本文實(shí)例為大家分享了java實(shí)現(xiàn)哈夫曼文件解壓縮的具體代碼,供大家參考,具體內(nèi)容如下
1、哈夫曼壓縮對已經(jīng)經(jīng)過壓縮處理的文件壓縮率比較低,比如ppt和視頻。
2、這個(gè)程序主要涉及到集合、樹、IO相關(guān)知識。
字符的統(tǒng)計(jì)可以用map集合進(jìn)行統(tǒng)計(jì)。
哈夫曼樹的構(gòu)建過程也并不復(fù)雜:
①先對樹的集合按照根節(jié)點(diǎn)大小進(jìn)行排序
②拿出根節(jié)點(diǎn)數(shù)值最小的兩棵樹,用它兩構(gòu)建成一顆新的樹;
③從集合中刪除之前那兩顆根節(jié)點(diǎn)最小的數(shù);
④把新生成的樹加入到集合中
一直循環(huán)重復(fù)上面的過程,直到集合的大小變成1為止;
寫出、讀取文件時(shí)注意使用對象流Object流。
3、個(gè)程序可以對字符進(jìn)行壓縮,也可以對文件進(jìn)行壓縮。代碼中的主函數(shù)中只是調(diào)用了對文件解壓縮的方法,若想對字符進(jìn)行解壓縮,可以調(diào)用對應(yīng)的方法。
4、代碼如下:
package huffmancode;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class HuffManCode
{
public static void main(String[] args)
{
String srcFile="d://mydata.txt";//要壓縮的文件
String dstFile="d://mydata.zip";//壓縮后的文件
zipFile(srcFile, dstFile);//壓縮文件
System.out.println("壓縮成功!");
unZipFile(dstFile,"d://unzip.txt");//對剛才的文件進(jìn)行解壓,解壓后的文件名稱叫做unzip.txt
System.out.println("解壓文件成功!");
}
public static void unZipFile(String zipFile,String dstFile)
{
InputStream inputStream=null;
ObjectInputStream objectInputStream=null;
OutputStream outputStream=null;
try
{
inputStream=new FileInputStream(zipFile);
objectInputStream=new ObjectInputStream(inputStream);
byte [] array= (byte [])objectInputStream.readObject();
Map<Byte,String> map=(Map<Byte,String>)objectInputStream.readObject();
byte[] decode = decode(map, array);
outputStream=new FileOutputStream(dstFile);
outputStream.write(decode);
} catch (Exception e)
{
System.out.println(e);
}finally
{
try {
outputStream.close();
objectInputStream.close();
inputStream.close();
} catch (Exception e2) {
System.out.println(e2);
}
}
}
public static void zipFile(String srcFile,String dstFile)
{
FileInputStream inputStream=null;
OutputStream outputStream=null;
ObjectOutputStream objectOutputStream=null;
try
{
inputStream=new FileInputStream(srcFile);
byte [] b=new byte[inputStream.available()];
inputStream.read(b);
byte[] huffmanZip = huffmanZip(b);
outputStream=new FileOutputStream(dstFile);
objectOutputStream=new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(huffmanZip);
objectOutputStream.writeObject(map);
} catch (Exception e)
{
System.out.println(e);
}
finally
{
if(inputStream!=null)
{
try
{
objectOutputStream.close();
outputStream.close();
inputStream.close();//釋放資源
} catch (Exception e2)
{
System.out.println(e2);
}
}
}
}
private static byte[] decode(Map<Byte, String> map,byte [] array)
{
StringBuilder stringBuilder = new StringBuilder();
for(int i=0;i<array.length;i++)
{
boolean flag=(i==array.length-1);
stringBuilder.append(byteToBitString(!flag, array[i]));
}
Map<String, Byte> map2=new HashMap<String, Byte>();//反向編碼表
Set<Byte> keySet = map.keySet();
for(Byte b:keySet)
{
String value=map.get(b);
map2.put(value, b);
}
List<Byte> list=new ArrayList<Byte>();
for (int i = 0; i < stringBuilder.length();)
{
int count=1;
boolean flag=true;
Byte byte1=null;
while (flag)
{
String substring = stringBuilder.substring(i, i+count);
byte1 = map2.get(substring);
if(byte1==null)
{
count++;
}
else
{
flag=false;
}
}
list.add(byte1);
i+=count;
}
byte [] by=new byte[list.size()];
for(int i=0;i<by.length;i++)
{
by[i]=list.get(i);
}
return by;
}
private static String byteToBitString(boolean flag, byte b)
{
int temp=b;
if(flag)
{
temp|=256;
}
String binaryString = Integer.toBinaryString(temp);
if(flag)
{
return binaryString.substring(binaryString.length()-8);
}
else
{
return binaryString;
}
}
private static byte[] huffmanZip(byte [] array)
{
List<Node> nodes = getNodes(array);
Node createHuffManTree = createHuffManTree(nodes);
Map<Byte, String> m=getCodes(createHuffManTree);
byte[] zip = zip(array, m);
return zip;
}
//
private static byte[] zip(byte [] array,Map<Byte,String> map)
{
StringBuilder sBuilder=new StringBuilder();
for(byte item:array)
{
String value=map.get(item);
sBuilder.append(value);
}
//System.out.println(sBuilder);
int len;
if(sBuilder.toString().length()%8==0)//如果可以整除
{
len=sBuilder.toString().length()/8;
}
else //如果不能整除
{
len=sBuilder.toString().length()/8+1;
}
byte [] by=new byte[len];
int index=0;
for(int i=0;i<sBuilder.length();i+=8)
{
String string;
if((i+8)>sBuilder.length())
{
string=sBuilder.substring(i);
}
else
{
string=sBuilder.substring(i, i+8);
}
by[index]=(byte)Integer.parseInt(string,2);
index++;
}
return by;
}
//重載
private static Map<Byte, String> getCodes(Node root)
{
if(root==null)
{
return null;
}
getCodes(root.leftNode,"0",sBuilder);
getCodes(root.rightNode,"1",sBuilder);
return map;
}
//獲取哈夫曼編碼
static Map<Byte, String> map=new HashMap<>();
static StringBuilder sBuilder=new StringBuilder();
public static void getCodes(Node node,String code,StringBuilder stringBuilder)
{
StringBuilder stringBuilder2=new StringBuilder(stringBuilder);
stringBuilder2.append(code);
if(node!=null)
{
if(node.data==null)//非葉子結(jié)點(diǎn)
{
//向左遞歸
getCodes(node.leftNode,"0",stringBuilder2);
//向右遞歸
getCodes(node.rightNode,"1",stringBuilder2);
}
else //如果是葉子結(jié)點(diǎn)
{
map.put(node.data,stringBuilder2.toString());
}
}
}
public static List<Node> getNodes(byte [] array)
{
List<Node> list=new ArrayList<Node>();
Map<Byte, Integer> map=new HashMap<Byte, Integer>();
for(Byte data:array)
{
Integer count=map.get(data);//通過鍵獲取值
if(count==null)//說明此時(shí)map集合中還沒有改字符
{
map.put(data, 1);
}
else
{
map.put(data,count+1);
}
}
//遍歷map集合
Set<Byte> set=map.keySet();
for(Byte key:set)
{
int value=map.get(key);
Node node=new Node(key, value);
list.add(node);
}
return list;
}
private static Node createHuffManTree(List<Node> list)
{
while(list.size()>1)
{
Collections.sort(list);//先對集合進(jìn)行排序
Node leftNode=list.get(0);
Node rightNode=list.get(1);
Node parentNode=new Node(null, leftNode.weight+rightNode.weight);
parentNode.leftNode=leftNode;
parentNode.rightNode=rightNode;
list.remove(leftNode);
list.remove(rightNode);
list.add(parentNode);
}
return list.get(0);
}
}
class Node implements Comparable<Node>
{
Byte data;//字符
int weight;//字符出現(xiàn)的次數(shù)
Node leftNode;
Node rightNode;
public Node(Byte data,int weight)//構(gòu)造器
{
this.data=data;
this.weight=weight;
}
@Override
public int compareTo(Node o)
{
return this.weight-o.weight;
}
@Override
public String toString()
{
return "Node [data=" + data + ", weight=" + weight + "]";
}
//前序遍歷
public void preOrder()
{
System.out.println(this);
if(this.leftNode!=null)
{
this.leftNode.preOrder();
}
if(this.rightNode!=null)
{
this.rightNode.preOrder();
}
}
}
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
MyBatis?如何使項(xiàng)目兼容多種數(shù)據(jù)庫的解決方案
要想做兼容多種數(shù)據(jù)庫,那毫無疑問,我們首先得明確我們要兼容哪些數(shù)據(jù)庫,他們的數(shù)據(jù)庫產(chǎn)品名稱是什么,本次我們講解了一套使項(xiàng)目兼容多種數(shù)據(jù)庫的方案,對MyBatis項(xiàng)目兼容多種數(shù)據(jù)庫操作方法感興趣的朋友一起看看吧2024-05-05
Spring Shell應(yīng)用程序開發(fā)流程解析
這篇文章主要介紹了Spring Shell應(yīng)用程序開發(fā)流程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10
Java web含驗(yàn)證碼及權(quán)限登錄實(shí)例代碼
這篇文章主要介紹了Java web含驗(yàn)證碼及權(quán)限登錄實(shí)例代碼,所用到的開發(fā)工具為myeclipse10,MySQL數(shù)據(jù)庫,具體實(shí)現(xiàn)代碼大家參考下本文吧2017-03-03

