哈夫曼编码与文本压缩

在当今信息爆炸时代,如何采用有效的数据压缩技术来节省数据文件的存储空间越来越引起人们的重视。哈夫曼编码正是一种应用广泛且非常有效的数据压缩技术。我们要分析与设计哈夫曼树的存储结构,实现哈夫曼算法以及编码与译码基本功能,并对文本文件利用哈夫曼编码进行压缩得到压缩文件,然后进行解压缩得到解压文件。进行此项设计要掌握二叉树、哈夫曼树的概念,性质与存储结构,能够利用哈夫曼算法实现哈夫曼编码,并应用于文件压缩。

在数据存储中,假如文件过大存储可能会造成空间的浪费,并且上传文件时,文件的传输时间也会比较长。因此我们可以利用文件压缩来减小时间资源与空间资源的使用量。哈夫曼编码使用的是编码表来对原文件进行编码,将数据量减小,从而更加节约计算机的使用资源。

以下是代码:

import java.io.*;

import java.util.*;

public class hafuman {

static int last ;

static HashMap<Character,String> huffmanTreeMapCode =new HashMap<>(); //哈夫曼编码表

static StringBuilder stringBuilder =new StringBuilder();//字符串拼接类

public static void main(String[] args) throws IOException, ClassNotFoundException {

File file =new File("E:/java/Demo.txt"); //创建一个文件

if(!file.exists()) //如果没有则创建

file.createNewFile();

File file1 =new File("E:/java/zipDemo.zip");

if(!file.exists()) //如果没有则创建

file1.createNewFile();

File file2 =new File("E:/java/unzip.txt");

if(!file2.exists()) //如果没有则创建

file.createNewFile();

String srcFile ="E:/java/Demo.txt"; //原文件路径

String zipFile ="E:/java/zipDemo.zip";//压缩后的文件路径

String deZipFile ="E:/java/unzip.txt";//解压之后的文件路径

zipFile(srcFile,zipFile); //压缩文件

unZip(zipFile,deZipFile);//解压文件

}

public static void unZip(String zipFile,String dstFile) throws IOException, ClassNotFoundException

{

FileInputStream fis =new FileInputStream(zipFile);

byte[] bytes =new byte[fis.available()];

fis.read(bytes);

String s=Decode(bytes,huffmanTreeMapCode);

FileOutputStream fos =new FileOutputStream(dstFile);

fos.write(s.getBytes());

fis.close();

fos.close();

}

压缩文件

public static void zipFile(String srcFile,String dstFile) throws IOException

{

FileInputStream fis = new FileInputStream(srcFile);

byte[] bytes =new byte[fis.available()];

fis.read(bytes);

fis.close();

List<Node> list =getNode(new String(bytes));

Node root =CreateHuffmanTree(list);

getCode(root,"",stringBuilder);

HashMap<Character,String> huffmanTreeMapCode =new HashMap<>();

byte[] b=zip(huffmanTreeMapCode,new String(bytes));

FileOutputStream fos = new FileOutputStream(dstFile);

fos.write(b);

fos.close();

}

//第七步 对压缩成的byte数组进行解码

public static String Decode(byte[] bytes,Map<Character,String> huffmanTreeMapCode )

{

StringBuilder stringBuilder =new StringBuilder();

last =Integer.toBinaryString(bytes[bytes.length-1]).length();

for(int i=0;i<bytes.length;i++) {

if(i!=bytes.length-1) stringBuilder.append(byteToBinary(bytes[i], true));

else stringBuilder.append(byteToBinary(bytes[i], false));

}

System.out.println("对byte数组解码过后:");

Map<String,Character> DecodeMap=new HashMap<String,Character>();

for(char ch:huffmanTreeMapCode.keySet())

DecodeMap.put(huffmanTreeMapCode.get(ch),ch);

StringBuilder s =new StringBuilder();

for(int i=0;i<stringBuilder.length();i++)

{ boolean flag =true;

int count=1;//计步器

String b= "null";

while(flag)

{

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

b = String.valueOf(DecodeMap.get(key));

if(b=="null")

{

count++;

}else {

flag=false;

}

}

s.append(b);

i=i+count-1;

}

return s.toString();

}

//第六步 byte转二进制的工具类

public static String byteToBinary(byte b,boolean flag)

{

int temp=b; //将byte转为int

temp|=256;//将temp或上256 256的二进制码为1 0000 0000

String str =Integer.toBinaryString(temp);

if(flag) return str.substring(str.length()-8);

else return str.substring(str.length()-last);

}

//第五步 根据哈夫曼编码表进行编码

public static byte[] zip(Map<Character,String> huffmanTreeMapCode,String s)

{ char []arr=s.toCharArray();

StringBuilder stringBuilder =new StringBuilder();

for(char ch:arr)//遍历char数组

{

stringBuilder.append(huffmanTreeMapCode.get(ch));

}

System.out.println("哈夫曼编码过后:");

System.out.println(stringBuilder.toString());

int len =stringBuilder.length()%8==0?stringBuilder.length()/8:stringBuilder.length()/8+1;

byte [] bytes =new byte[len];

String str = stringBuilder.toString();

int index=0;//计步器

for(int i=0;i<stringBuilder.length();i+=8)

{

if((i+8)<stringBuilder.length())

bytes[index++]=(byte)Integer.parseInt(str.substring(i,i+8),2);

else

bytes[index++]=(byte)Integer.parseInt(str.substring(i),2);

}

return bytes;

}

//第四步得到哈夫曼编码表 路径值 左路径为0 右路径为1

public static void getCode(Node root ,String code ,StringBuilder stringBuilder)

{

StringBuilder stringBuilder1 =new StringBuilder(stringBuilder);

stringBuilder1.append(code);

if(root!=null)

{

if(root.english=='\0')

{

getCode(root.left,"0",stringBuilder1);

getCode(root.right,"1",stringBuilder1);

}else

{

huffmanTreeMapCode.put(root.english,stringBuilder1.toString());

}

}

}

public static List<Node> getNode(String s)

{

char[] arr = s.toCharArray();

ArrayList<Node> arrayList=new ArrayList<Node>();

Map<Character,Integer> nodesMap =new HashMap<>();

for(char c:arr)

if(!nodesMap.containsKey(c))

{

nodesMap.put(c,1);

}else nodesMap.put(c, nodesMap.get(c)+1);

for(char ch :nodesMap.keySet())

arrayList.add(new Node(nodesMap.get(ch),ch));

return arrayList;

}

//第三步得到创建哈夫曼树的根节点

public static Node CreateHuffmanTree(List<Node> list){

Collections.sort(list);

while(list.size()>1)

{

Node leftNode =list.get(0);

Node rightNode=list.get(1);

Node parentNode=new Node(leftNode.weight+rightNode.weight,'\0');

parentNode.left=leftNode;

parentNode.right=rightNode;

list.remove(leftNode);

list.remove(rightNode);

list.add(parentNode);

Collections.sort(list);

}

return list.get(0);

}

public static void preOrder(Node root)

{

System.out.println(root);

if(root.left!=null)

preOrder(root.left);

if(root.right!=null)

preOrder(root.right);

}

}

//第一步创建结点类

class Node implements Comparable<Node> {

int weight;//权值

char english;//字符

Node left;//左孩子

Node right;//右孩子

public Node(int weight, char english)

{

this.weight=weight;

this.english=english;

}

@Override

public String toString() {

return "Node{" +

" 字符=" + english +

",权重=" + weight +

'}' ;

}

@Override

public int compareTo(Node o) {

return this.weight-o.weight;

}//自定义排序

}

  • 24
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值