java實(shí)現(xiàn)哈夫曼文件解壓縮
本文實(shí)例為大家分享了java實(shí)現(xiàn)哈夫曼文件解壓縮的具體代碼,供大家參考,具體內(nèi)容如下
1、哈夫曼壓縮對已經(jīng)經(jīng)過壓縮處理的文件壓縮率比較低,比如ppt和視頻。
2、這個程序主要涉及到集合、樹、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為止;
寫出、讀取文件時注意使用對象流Object流。
3、個程序可以對字符進(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)//說明此時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)文章
SpringCloud學(xué)習(xí)筆記之Feign遠(yuǎn)程調(diào)用
Feign是一個聲明式的http客戶端。其作用就是幫助我們優(yōu)雅的實(shí)現(xiàn)http請求的發(fā)送。本文將具體為大家介紹一下Feign的遠(yuǎn)程調(diào)用,感興趣的可以了解一下2021-12-12
IDEA插件之mybatisx插件使用教程(超詳細(xì)!)
MybatisX 是一款基于IDEA的快速開發(fā)插件,為效率而生,下面這篇文章主要給大家介紹了關(guān)于IDEA插件之mybatisx插件使用的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-06-06
Spring中的@Scheduled定時任務(wù)注解詳解
這篇文章主要介紹了Spring中的@Scheduled定時任務(wù)注解詳解,要使用@Scheduled注解,首先需要在啟動類添加@EnableScheduling,啟用Spring的計(jì)劃任務(wù)執(zhí)行功能,這樣可以在容器中的任何Spring管理的bean上檢測@Scheduled注解,執(zhí)行計(jì)劃任務(wù),需要的朋友可以參考下2023-09-09
Spring ApplicationContext上下文核心容器深入探究
ApplicationContext是Spring應(yīng)用程序中的中央接口,由于繼承了多個組件,使得ApplicationContext擁有了許多Spring的核心功能,如獲取bean組件,注冊監(jiān)聽事件,加載資源文件等2023-01-01
Java設(shè)計(jì)模式之備忘錄模式實(shí)現(xiàn)對象狀態(tài)的保存和恢復(fù)
本文介紹Java設(shè)計(jì)模式之備忘錄模式,該模式可以實(shí)現(xiàn)對象狀態(tài)的保存和恢復(fù)。通過詳細(xì)講解備忘錄模式的原理、實(shí)現(xiàn)方法和應(yīng)用場景,幫助讀者深入理解該設(shè)計(jì)模式,并提供示例代碼和技巧,便于讀者實(shí)際應(yīng)用2023-04-04
Java中redisTemplate注入失敗NullPointerException異常問題解決
這篇文章主要介紹了Java中redisTemplate注入失敗NullPointerException異常問題解決,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2023-08-08
淺談String類型如何轉(zhuǎn)換為time類型存進(jìn)數(shù)據(jù)庫
這篇文章主要介紹了String類型如何轉(zhuǎn)換為time類型存進(jìn)數(shù)據(jù)庫,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03

