java 字符串 无损压缩算法_使用赫夫曼编码对字符串和文件进行压缩和解压缩(无损压缩)...

packagecom.zhao.algorithm.tree;import java.io.*;import java.util.*;/*** AUTHOR :zhao

* 日期:2020/2/17 17:42

* 赫夫曼编码 压缩与解压缩, 他是无损压缩*/

public classHuffmanCode {public static voidmain(String[] args) {//start 赫夫曼编码 解码

String msg="Man proposes,God disposes.";byte[] bytes =msg.getBytes();

System.out.println("压缩前长度 :"+bytes.length);//进行赫夫曼编码压缩

byte[] b =huffmanZip(bytes);

System.out.println("压缩后长度 :"+b.length);//使用赫夫曼编码进行解码

byte[] newBytes =decode(huffCodes,b);

System.out.println(newString(newBytes));//end ---------// //user.dir指定了当前的路径//String src=System.getProperty("user.dir")+"\\haffman.bmp";// //这里的压缩名后缀随便起//String dst="haffman.god";//try {//zipFile(src, dst);//} catch (IOException e) {//e.printStackTrace();//}//try {//unZip(dst, "haffman2.bmp");//} catch (Exception e) {//e.printStackTrace();//}

}/*** 文件的解压

*@paramsrc

*@paramdst

*@throwsException*/

public static void unZip(String src,String dst) throwsException {//创建一个输入流

InputStream is = newFileInputStream(src);

ObjectInputStream ois= newObjectInputStream(is);//读取byte数组

byte[] b = (byte[]) ois.readObject();//读取赫夫曼编码表

Map codes = (Map) ois.readObject();

ois.close();

is.close();//解码

byte[] bytes =decode(codes, b);//创建一个输出流

OutputStream os = newFileOutputStream(dst);//写出数据

os.write(bytes);

os.close();

}/*** 压缩文件

*@paramsrc 源文件

*@paramdst 压缩后的文件

*@throwsIOException*/

public static void zipFile(String src,String dst) throwsIOException {//创建一个输入流

InputStream is = newFileInputStream(src);//创建一个和输入流指向的文件大小一样的byte数组//available 返回从此输入流中可以读取(或跳过)的剩余字节数的估计值,而不会被下一次调用此输入流的方法阻塞。

byte[] b = new byte[is.available()];//读取文件内容

is.read(b);

is.close();//使用赫夫曼编码进行编码

byte[] byteZip =huffmanZip(b);//输出流

OutputStream os = newFileOutputStream(dst);

ObjectOutputStream oos= newObjectOutputStream(os);//把压缩后的byte数组写入文件

oos.writeObject(byteZip);//把赫夫曼编码表写入文件

oos.writeObject(huffCodes);

oos.close();

os.close();

}/*** 使用指定的赫夫曼编码表进行解码

*

*@paramhuffCodes

*@paramb

*@return

*/

private static byte[] decode(Map huffCodes, byte[] bytes) {

StringBuilder sb= newStringBuilder();//把byte数组转为一个二进制的字符串

for (int i = 0; i < bytes.length; i++) {byte b =bytes[i];//是否是最后一个。

boolean flag = (i == bytes.length - 1);

sb.append(byteToBitStr(!flag, b));

}//把字符串按照指定的赫夫曼编码进行解码//把赫夫曼编码的键值对进行调换

Map map = new HashMap<>();for (Map.Entryentry : huffCodes.entrySet()) {

map.put(entry.getValue(), entry.getKey());

}//创建一个集合,用于存byte

List list = new ArrayList<>();//处理字符串

for (int i = 0; i

Byte b= null;//截取出一个byte

while(flag) {

String key= sb.substring(i, i +count);

b=map.get(key);if (b == null) {

count++;

}else{

flag= false;

}

}

list.add(b);

i+=count;

}//把集合转为数组

byte[] b = new byte[list.size()];for (int i = 0; i < b.length; i++) {

b[i]=list.get(i);

}returnb;

}private static String byteToBitStr(boolean flag, byteb) {int temp =b;if(flag) {

temp|= 256;

}

String str=Integer.toBinaryString(temp);if(flag) {return str.substring(str.length() - 8);

}else{returnstr;

}

}/*** 进行赫夫曼编码压缩的方法

*

*@parambytes

*@return

*/

private static byte[] huffmanZip(byte[] bytes) {//先统计每一个byte出现的次数,并放入一个集合中

List nodes =getNodes(bytes);//创建一颗赫夫曼树

HuffmanNode tree =createHuffmanTree(nodes);//创建一个赫夫曼编码表

Map huffCodes =getCodes(tree);//编码

byte[] b =zip(bytes, huffCodes);returnb;

}/*** 把byte数组转为node集合

*

*@parambytes

*@return

*/

private static List getNodes(byte[] bytes) {

List nodes = new ArrayList<>();//存储每一个byte出现了多少次。

Map counts = new HashMap<>();//统计每一个byte出现的次数

for (byteb : bytes) {

Integer count=counts.get(b);if (count == null) {

counts.put(b,1);

}else{

counts.put(b, count+ 1);

}

}//把每一个键值对转为一个node对象

for (Map.Entryentry : counts.entrySet()) {

nodes.add(newHuffmanNode(entry.getKey(), entry.getValue()));

}returnnodes;

}/*** 进行赫夫曼编码

*

*@parambytes

*@paramhuffCodes

*@return

*/

private static byte[] zip(byte[] bytes, MaphuffCodes) {

StringBuilder sb= newStringBuilder();//把需要压缩的byte数组处理成一个二进制的字符串,其实就是他每个字母的赫夫曼路径

for (byteb : bytes) {

sb.append(huffCodes.get(b));

}//定义长度

intlen;if (sb.length() % 8 == 0) {

len= sb.length() / 8;

}else{

len= sb.length() / 8 + 1;

}//用于存储压缩后的byte

byte[] by = new byte[len];//记录新byte的位置

int index = 0;for (int i = 0; i < sb.length(); i += 8) {

String strByte;if (i + 8 >sb.length()) {

strByte=sb.substring(i);

}else{

strByte= sb.substring(i, i + 8);

}byte byt = (byte) Integer.parseInt(strByte, 2);

by[index]=byt;

index++;

}returnby;

}//用于临时存储路径

static StringBuilder sb = newStringBuilder();//用于存储赫夫曼编码

static Map huffCodes = new HashMap<>();/*** 根据赫夫曼树获取赫夫曼编码

*

*@paramtree

*@return

*/

private static MapgetCodes(HuffmanNode tree) {if (tree == null) {return null;

}

getCodes(tree.left,"0", sb);

getCodes(tree.right,"1", sb);returnhuffCodes;

}/*** 获取赫夫曼 编码中的 数据 eg:b 和数据出现的路径 huffCodes

*

*@paramnode 树节点

*@paramcode 0 左节点 1右节点

*@paramsb 获取这个节点中的数据要走的路径*/

private static voidgetCodes(HuffmanNode node, String code, StringBuilder sb) {

StringBuilder sb2= newStringBuilder(sb);

sb2.append(code);if (node.data == null) {

getCodes(node.left,"0", sb2);

getCodes(node.right,"1", sb2);

}else{

huffCodes.put(node.data, sb2.toString());

}

}/*** 创建赫夫曼树

*

*@paramnodes

*@return

*/

private static HuffmanNode createHuffmanTree(Listnodes) {while (nodes.size() > 1) {//排序

Collections.sort(nodes);//取出两个权值最低的二叉树

HuffmanNode left = nodes.get(nodes.size() - 1);

HuffmanNode right= nodes.get(nodes.size() - 2);//创建一颗新的二叉树

HuffmanNode parent = new HuffmanNode(null, left.weight +right.weight);//把之前取出来的两颗二叉树设置为新创建的二叉树的子树

parent.left =left;

parent.right=right;//把前面取出来的两颗二叉树删除

nodes.remove(left);

nodes.remove(right);//把新创建的二叉树放入集合中

nodes.add(parent);

}return nodes.get(0);

}

}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值